Repository: JetBrains/intellij-micropython
Branch: master
Commit: 17bcc4abb60e
Files: 121
Total size: 978.1 KB
Directory structure:
gitextract_ebr8_o39/
├── .github/
│ └── workflows/
│ └── check.yml
├── .gitignore
├── CHANGES.md
├── LICENSE.txt
├── Pipfile
├── README.md
├── build.gradle.kts
├── examples/
│ └── rpsls.py
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── licenses/
│ └── microrepl_license.txt
├── scripts/
│ ├── findusb.py
│ ├── microcleanfs.py
│ ├── microrepl.py
│ └── microupload.py
├── src/
│ └── main/
│ ├── kotlin/
│ │ └── com/
│ │ └── jetbrains/
│ │ └── micropython/
│ │ ├── actions/
│ │ │ ├── MicroPythonAction.kt
│ │ │ ├── MicroPythonCommandAction.kt
│ │ │ ├── RemoveAllFilesFromDeviceAction.kt
│ │ │ └── RunMicroReplAction.kt
│ │ ├── devices/
│ │ │ ├── Esp8266DeviceProvider.kt
│ │ │ ├── MicroBitDeviceProvider.kt
│ │ │ ├── MicroBitV2DeviceProvider.kt
│ │ │ ├── MicroPythonDeviceProvider.kt
│ │ │ ├── PyboardDeviceProvider.kt
│ │ │ └── RPiPicoDeviceProvider.kt
│ │ ├── inspections/
│ │ │ └── MicroPythonRequirementsInspection.kt
│ │ ├── repl/
│ │ │ ├── MicroPythonReplManager.kt
│ │ │ ├── StopReplBeforeRunTask.kt
│ │ │ └── ToolWindowReplTab.kt
│ │ ├── run/
│ │ │ ├── MicroPythonConfigurationType.kt
│ │ │ ├── MicroPythonRunConfiguration.kt
│ │ │ ├── MicroPythonRunConfigurationEditor.kt
│ │ │ ├── MicroPythonRunConfigurationProducer.kt
│ │ │ └── MicroUpload.kt
│ │ ├── settings/
│ │ │ ├── MicroPythonDevicesConfiguration.kt
│ │ │ ├── MicroPythonFacet.kt
│ │ │ ├── MicroPythonFacetConfiguration.kt
│ │ │ ├── MicroPythonFacetDetector.kt
│ │ │ ├── MicroPythonFacetEditorTab.kt
│ │ │ ├── MicroPythonFacetType.kt
│ │ │ ├── MicroPythonModuleConfigurable.kt
│ │ │ ├── MicroPythonProjectConfigurable.kt
│ │ │ ├── MicroPythonSettingsPanel.kt
│ │ │ ├── MicroPythonTypeHints.kt
│ │ │ └── MicroPythonUsbId.kt
│ │ └── ui/
│ │ └── MicroPythonToolWindowFactory.kt
│ └── resources/
│ ├── META-INF/
│ │ └── plugin.xml
│ └── inspectionDescriptions/
│ └── MicroPythonRequirements.html
└── typehints/
├── esp32/
│ ├── esp.pyi
│ ├── esp32.pyi
│ └── network.pyi
├── esp8266/
│ ├── esp.pyi
│ └── network.pyi
├── microbit/
│ ├── microbit/
│ │ ├── __init__.pyi
│ │ ├── accelerometer.pyi
│ │ ├── compass.pyi
│ │ ├── display.pyi
│ │ ├── i2c.pyi
│ │ ├── spi.pyi
│ │ └── uart.pyi
│ ├── music.pyi
│ ├── neopixel.pyi
│ ├── radio.pyi
│ └── speech.pyi
├── micropython/
│ ├── bluetooth.pyi
│ ├── btree.pyi
│ ├── cryptolib.pyi
│ ├── framebuf.pyi
│ ├── machine.pyi
│ ├── micropython.pyi
│ ├── neopixel.pyi
│ ├── network.pyi
│ ├── ubluetooth.pyi
│ ├── ucryptolib.pyi
│ └── uctypes.pyi
├── pyboard/
│ ├── lcd160cr.pyi
│ ├── pyb.pyi
│ └── stm.pyi
├── rpi_pico/
│ └── rp2.pyi
└── stdlib/
├── _thread.pyi
├── array.pyi
├── binascii.pyi
├── cmath.pyi
├── collections.pyi
├── errno.pyi
├── gc.pyi
├── hashlib.pyi
├── heapq.pyi
├── io.pyi
├── json.pyi
├── math.pyi
├── os.pyi
├── re.pyi
├── select.pyi
├── socket.pyi
├── ssl.pyi
├── struct.pyi
├── sys.pyi
├── time.pyi
├── uarray.pyi
├── uasyncio.pyi
├── ubinascii.pyi
├── ucollections.pyi
├── uerrno.pyi
├── uhashlib.pyi
├── uheapq.pyi
├── uio.pyi
├── ujson.pyi
├── uos.pyi
├── ure.pyi
├── uselect.pyi
├── usocket.pyi
├── ussl.pyi
├── ustruct.pyi
├── usys.pyi
├── utime.pyi
├── uzlib.pyi
└── zlib.pyi
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/check.yml
================================================
name: check
on:
push:
branches:
- master
pull_request:
schedule:
- cron: '0 3 * * *'
# Allow cancelling all previous runs for the same branch
# See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#concurrency
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build-plugin:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: corretto
java-version: 17
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
- name: Build plugin
run: ./gradlew :buildPlugin -Pversion=SNAPSHOT-${{ github.run_number }}
- name: Upload plugin archive
uses: actions/upload-artifact@v4
with:
name: intellij-micropython-SNAPSHOT-${{ github.run_number }}
path: build/distributions/intellij-micropython-SNAPSHOT-${{ github.run_number }}.zip
================================================
FILE: .gitignore
================================================
*.iml
.idea/
!/.idea/runConfigurations/
.gradle/
build/
venv/
tmp/
# IntelliJ Platform Gradle Plugin
.intellijPlatform/
================================================
FILE: CHANGES.md
================================================
The Changelog
=============
1.4.6 - 2024-08-28
------------------
* Support for 2024.2 IDE versions
([#295](https://github.com/JetBrains/intellij-micropython/issues/295))
1.4.5 - 2024-07-27
------------------
### Fixed
* Don't interrupt program execution when REPL is started right after the upload
([#313](https://github.com/JetBrains/intellij-micropython/pull/313))
* Update `machine.pyi`
([#291](https://github.com/JetBrains/intellij-micropython/pull/291))
(Thanks to [Lucio Rossi](https://github.com/eigen-value))
* Update `network.pyi`
([#296](https://github.com/JetBrains/intellij-micropython/pull/296))
1.4.4 - 2024-07-13
------------------
### Fixed
* Compatibility with 2024.1.x IDEs
* REPL should work fine with the latest IDE versions
1.4.2 - 2023-10-11
------------------
### Fixed
* Metro M4 Airlift Lite support added
([#254](https://github.com/JetBrains/intellij-micropython/pull/254))
(Thanks to [@PierreDeQuebec](https://github.com/PierreDeQuebec))
* Compatibility issue in REPL support is fixed
([#253](https://github.com/JetBrains/intellij-micropython/pull/253))
(Thanks to [@lancelote](https://github.com/lancelote))
1.4.1 - 2023-03-17
------------------
### Added
* Type Hints for ESP32 added
([#218](https://github.com/JetBrains/intellij-micropython/pull/218))
(Thanks to [@MrNavaStar](https://github.com/MrNavaStar))
1.4.0 - 2022-11-21
------------------
### Added
* MicroPython REPL running in a dedicated tool window
([#139](https://github.com/JetBrains/intellij-micropython/pull/139))
(Thanks to [@lensvol](https://github.com/lensvol))
* Support for the Micro:bit V2 device type
([#186](https://github.com/JetBrains/intellij-micropython/pull/186))
### Changed
* Compatibility with 2021.3-2022.3
1.3.3 — 2022-09-23
------------------
### Fixed
* Broken compatibility with the older PyCharm versions
1.3.2 — 2022-09-23
------------------
### Fixed
* An error on opening projects in PyCharm 2022.2.2
([#205](https://github.com/JetBrains/intellij-micropython/issues/205))
1.3.1 — 2022-03-18
------------------
### Changed
* Compatibility with 2020.3-2022.1
([#184](https://github.com/vlasovskikh/intellij-micropython/issues/184))
1.3 — 2021-12-01
----------------
### Added
* Added many stubs for the MicroPython standard library and Pyboard
([#176](https://github.com/vlasovskikh/intellij-micropython/pull/176))
(Thanks to [@hlovatt](https://github.com/hlovatt))
### Changed
* Compatibility with 2020.3-2021.3
### Fixed
* Fixed special keys in REPL on Windows for pyserial>=3.5
([#175](https://github.com/vlasovskikh/intellij-micropython/issues/175))
1.2 — 2021-08-05
----------------
### Added
* Added support for Raspberry Pi Pico devices
([#132](https://github.com/vlasovskikh/intellij-micropython/issues/132))
(Thanks to [@timsavage](https://github.com/timsavage))
* Added type hints for `lcd160cr`, `network`, `ubluetooth`, `ucryptolib`, `uctypes`
(Thanks to [@hlovatt](https://github.com/hlovatt))
### Changed
* Compatibility with 2020.3-2021.2
([#170](https://github.com/vlasovskikh/intellij-micropython/issues/170))
* Updated type hints for `pyb`, `machine`, `micropython`, `uarray`, `btree`, `framebuf`
(Thanks to [@hlovatt](https://github.com/hlovatt))
### Fixed
* Fixed handling backslash while flashing files on Windows
([#128](https://github.com/vlasovskikh/intellij-micropython/issues/128))
(Thanks to [@jdjjm](https://github.com/jdjjm))
1.1.4 — 2021-03-05
------------------
* Compatibility with 2020.2-2021.1
1.1.3 — 2020-12-12
------------------
* Added an SVG icon for MicroPython actions
* Fixed a regression in 2020.3 that prevented the plugin from updating and persisting
your device type on changing it in the settings
1.1.2 — 2020-10-24
------------------
* Added a type hinting stub for `pyb`
* Switched to newer terminal API to fix regression in PyCharm 2020.2
* Compatibility with 2020.2-2020.3
1.1.1 — 2020-06-24
------------------
* Fixed control characters in REPL on Windows
* Fixed path separators for flashing directories on Windows
1.1 — 2020-06-07
----------------
* Auto-detect a connected MicroPython device with an option to specify the device path
manually in the IDE settings for MicroPython
* Use the nearest directory marked "Sources Root" as the root of your device while
flashing files
* Ignore `.git/`, `.idea/` and other files starting with `.` when flashing a directory
* Launch a run configuration to flash a directory from its context menu
* Compatibility with 2020.1-2020.2
1.0.14 — 2020-01-31
-------------------
* Compatibility with 2019.3-2020.1
1.0.13 — 2019-10-02
-------------------
* Compatibility with 2019.3 only
1.0.12 — 2019-07-23
-------------------
* Compatibility with 2018.3-2019.2
1.0.11 — 2019-02-12
-------------------
* Compatibility with 2018.3-2019.1
1.0.10 — 2018-11-22
-------------------
* Compatibility with 2018.3 only
1.0.9 — 2018-09-10
------------------
* Compatibility with 2018.2-2018.3
1.0.8 — 2018-07-25
------------------
* Compatibility with 2018.2 only
1.0.7 — 2018-06-19
------------------
* Compatibility with 2017.3-2018.2
1.0.6 — 2018-02-23
------------------
* Fixed several bugs in `machine` stub
1.0.5 — 2018-02-11
------------------
* Don't delete `boot.py` when removing all files from the device #35
1.0.4 — 2018-01-18
------------------
* Fixed launching REPL on Windows #12
1.0.3 — 2018-01-16
------------------
* Fixed the outdated pyserial version in requirements #26
* Fixed the error message when getting `EACCESS` error for the device file #27
1.0.2 — 2018-01-15
------------------
* Restored compatibility with IntelliJ
1.0.1 — 2018-01-15
------------------
* Restored compatibility with 2017.2-2018.1
1.0 — 2018-01-15
----------------
* Run files and REPL for ESP8266 and Pyboard devices
* Initial code insight for ESP8266 and MicroPython standard library
* Action for detecting the device path in the MicroPython settings
* Action for removing all files from the device
0.1 — 2017-06-18
----------------
* Code insight and documentation for Micro:bit Python API
* Run Python files on Micro:bit
* Micro:bit Python REPL
================================================
FILE: LICENSE.txt
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2000-2016 JetBrains s.r.o.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: Pipfile
================================================
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
docopt = "*"
adafruit-ampy = "*"
pyserial = "*"
[dev-packages]
[requires]
python_version = "3.7"
================================================
FILE: README.md
================================================
# MicroPython Plugin for PyCharm and IntelliJ
[](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
[](https://plugins.jetbrains.com/plugin/9777-micropython)
[](https://plugins.jetbrains.com/plugin/9777-micropython)
[](https://plugins.jetbrains.com/plugin/9777-micropython)
[](https://github.com/JetBrains/intellij-micropython/actions/workflows/check.yml)
[](https://gitter.im/intellij-micropython/community)
The Python code development plugin for [MicroPython](http://micropython.org/) devices in
[PyCharm](https://www.jetbrains.com/pycharm/) and [IntelliJ](https://www.jetbrains.com/idea/).
## Discontinued
- The project is discontinued and is no longer maintained
- Kindly use [MicroPython Tools](https://plugins.jetbrains.com/plugin/26227-micropython-tools/) instead
## Supported devices
The plugin supports Python development for these devices:
* [ESP8266](https://github.com/JetBrains/intellij-micropython/wiki/ESP8266)
* [PyBoard](https://github.com/JetBrains/intellij-micropython/wiki/Pyboard)
* [BBC Micro:bit](https://github.com/JetBrains/intellij-micropython/wiki/BBC-Micro%3Abit)
* [Raspberry Pi Pico](https://www.raspberrypi.org/products/raspberry-pi-pico/)
It will support more MicroPython devices and more device-specific and MicroPython-specific modules eventually. We are
interested in your contributions to the project. Feel free to open issues and send pull requests!
See also [the changelog](CHANGES.md) for the plugin.
## Features
### Code insight for MicroPython modules
* Context-aware code completion and documentation
* Use Ctrl+Q (F1 on macOS) for quick documentation window, you can dock it permanently

* Syntax checking and type checking
* The plugin checks your code while you're typing it

### Run code on MicroPython devices
* Flash Python files or project directories to devices
* Right-click on a file or directory and select "Run 'Flash '" to flash this item to your
connected device. If you want to flash a sub-directory to the root directory of your device, please mark this
sub-directory as a sources root: right-click on it and select "Mark Directory as | Sources Root". Its
icon will become blue, see the screenshot.

* You can edit your run configurations for flashing files or directories in "Run | Edit Configurations..."
menu.

* MicroPython REPL
* Use "Tools | MicroPython | MicroPython REPL" menu to run a MicroPython shell on your device. Or open
MicroPython REPL tool window directly

## Requirements
* PyCharm or IntelliJ
* Python 3.5+
* The MicroPython language version is 3.5. If you select a newer version, turn on "File | Settings | Editor |
Inspections | Python | Code compatibility inspection" and add Python 3.5 to the compatibility list there
* Python plugin (IntelliJ only)
* Supported MicroPython development board with a recent version of MicroPython firmware flashed to the board
## Installation
1. Install the "MicroPython" plugin from your IDE settings.
2. Create a new project or open an existing folder with your MicroPython code.
3. This step differs for PyCharm and IntelliJ:
* PyCharm: Enable MicroPython support in "File | Settings | Languages & Frameworks | MicroPython" and
specify the path to your MicroPython device
* IntelliJ: Add the MicroPython facet to a Python module in your project structure and specify the path to your
MicroPython device

4. Open any Python file in project. You may see a yellow bar on top of the file, notifying you that you don't
have some packages required for communicating with your device. In this case click "Install requirements" and wait
while the plugin downloads and installs the packages.
## Source Code
We write this plugin in Python and [Kotlin](https://kotlinlang.org/). Kotlin a new JVM language by JetBrains, the
makers of PyCharm and IntelliJ. Google recommends Kotlin as the best language for developing Android apps. If you are a
Python developer, Kotlin may be an interesting language for you to learn.
The steps for setting up the development environment:
1. Check out this project from GitHub
2. Create a new project from existing sources in IntelliJ
To just run the development version use `./gradlew clean runIde` from the command line
or just run **runIde** [run configuration](https://www.jetbrains.com/help/idea/run-debug-configuration.html).
Contributions are welcome!
## License
The plugin is licensed under the terms of the Apache 2 license.
================================================
FILE: build.gradle.kts
================================================
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
repositories {
mavenCentral()
intellijPlatform {
defaultRepositories()
}
}
plugins {
kotlin("jvm") version "2.0.20"
id("org.jetbrains.intellij.platform") version "2.0.1"
}
dependencies {
intellijPlatform {
val type = project.property("platformType").toString()
val version = project.property("platformVersion").toString()
val pythonPlugin = project.property("pythonPlugin").toString()
create(type, version, useInstaller = false)
bundledPlugin("org.jetbrains.plugins.terminal")
when (type) {
"PC" -> bundledPlugin("PythonCore")
"PY" -> bundledPlugin("Pythonid")
else -> plugin(pythonPlugin)
}
}
}
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
intellijPlatform {
pluginConfiguration {
name = "MicroPython"
}
instrumentCode = false
publishing {
token = project.property("publishToken").toString()
}
}
tasks {
withType {
compilerOptions {
jvmTarget = JvmTarget.JVM_21
languageVersion = KotlinVersion.DEFAULT
apiVersion = KotlinVersion.KOTLIN_1_9
}
}
prepareSandbox {
from("$rootDir") {
into("intellij-micropython")
include("typehints/")
include("scripts/")
}
}
}
================================================
FILE: examples/rpsls.py
================================================
from random import choice
import gc
import radio
from microbit import *
CLASSIC_STORY = """
Scissors cuts Paper
Paper covers Rock
Rock crushes Scissors
"""
SHELDON_COOPER_STORY = """
Scissors cuts Paper
Paper covers Rock
Rock crushes Lizard
Lizard poisons Spock
Spock smashes Scissors
Scissors decapitates Lizard
Lizard eats Paper
Paper disproves Spock
Spock vaporizes Rock
(and as it always has) Rock crushes Scissors
"""
STORY = SHELDON_COOPER_STORY
# @formatter:off
SKETCHES = {
'Scissors': '* :'
' * :'
' *:'
' * :'
'* :',
'Paper': '*****:'
'* *:'
'* *:'
'* *:'
'*****:',
'Rock': ' *** :'
'*****:'
'*****:'
'*****:'
' *** :',
'Lizard': '** :'
' * :'
' * :'
' * :'
' **:',
'Spock': ' *** :'
'*****:'
'** **:'
'** **:'
'** **:',
}
# @formatter:on
def sketch_to_image(sketch):
return Image(sketch.replace(' ', '0').replace('*', '9'))
IMAGES = {name: sketch_to_image(sketch) for name, sketch in SKETCHES.items()}
def parse_story(story):
gc.collect()
sentences = [line.split()[-3:] for line in story.split('\n') if line.strip()]
actors = {s for s, v, o in sentences}
victims = {actor: {o for s, v, o in sentences if s == actor} for actor in actors}
return actors, victims
ACTORS, VICTIMS = parse_story(STORY)
def random_outcome():
return choice(list(ACTORS))
def expired(time):
return abs(running_time() - time) > 2000
def beats(actor, victim):
return victim in VICTIMS.get(actor, [])
def wait_for_outcome():
start = running_time()
while not expired(start):
received = radio.receive()
if received:
return received
def main():
last_received = 0
other_outcome = None
radio.on()
while True:
received = radio.receive()
if received:
other_outcome = received
last_received = running_time()
if not accelerometer.was_gesture('face down'):
continue
my_outcome = random_outcome()
radio.send(my_outcome)
if not other_outcome or expired(last_received):
other_outcome = wait_for_outcome()
if other_outcome:
sleep(1000)
image = IMAGES.get(my_outcome, Image.SAD)
if beats(my_outcome, other_outcome):
to_show = [Image('00000:'
'00000:'
'00000:'
'00000:'
'00000:'), image, image, image] * 5
else:
to_show = [image] * 20
display.show(to_show, delay=200, clear=True, wait=False)
other_outcome = None
if __name__ == '__main__':
main()
================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
================================================
FILE: gradle.properties
================================================
version=1.4.6-2024.2
platformType=PC
platformVersion=242-EAP-SNAPSHOT
pythonPlugin=PythonCore:242.20224.300
publishToken=token
# Since kotlin 1.4, stdlib dependency is added by default by kotlin gradle plugin.
# But we don't need it because all necessary kotlin libraries are already bundled into IDE.
# See https://kotlinlang.org/docs/gradle-configure-project.html#dependency-on-the-standard-library for more details
kotlin.stdlib.default.dependency=false
================================================
FILE: gradlew
================================================
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
================================================
FILE: gradlew.bat
================================================
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
================================================
FILE: licenses/microrepl_license.txt
================================================
Copyright 2015 The Python Software Foundation (http://python.org/)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: scripts/findusb.py
================================================
# Copyright 2000-2017 JetBrains s.r.o.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Find USB devices.
Usage:
findusb
Outputs the list of all USB devices it has managed to find.
"""
from serial.tools.list_ports import comports
def main() -> None:
for port in comports():
if port.vid is not None and port.pid is not None:
print('0x%02x:0x%02x %s' % (port.vid, port.pid, port.device))
if __name__ == '__main__':
main()
================================================
FILE: scripts/microcleanfs.py
================================================
# Copyright 2000-2017 JetBrains s.r.o.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Remove the contents of the file system on a MicroPython device.
Usage:
microcleanfs PORT [options]
Options:
-f --force Remove ALL files from filesystem w/o preserving excludes
"""
import traceback
from typing import List
import sys
import time
from ampy.files import Files
from ampy.pyboard import Pyboard, PyboardError
from docopt import docopt
def main(args: List[str]) -> None:
opts = docopt(__doc__, argv=args)
port = opts['PORT']
force = opts['--force']
print('Connecting to {}'.format(port), file=sys.stderr)
board = Pyboard(port)
files = Files(board)
# Specifying subdirectories DOES NOT work as they will be deleted when the
# parent directory is deleted. Specifying top level directories DOES work.
exclude_files = ['boot.py']
print('Removing the contents of the file system')
wait_for_board()
for name in files.ls(long_format=False):
if force or name not in exclude_files:
try:
files.rm(name)
except (RuntimeError, PyboardError):
try:
files.rmdir(name)
except (RuntimeError, PyboardError):
print('Unknown Error removing file {}'.format(name),
file=sys.stderr)
print('Done')
def wait_for_board() -> None:
"""Wait for some ESP8266 devices to become ready for REPL commands."""
time.sleep(0.5)
if __name__ == '__main__':
try:
main(sys.argv[1:])
exitcode = 0
except:
traceback.print_exc()
exitcode = 1
finally:
input('Press ENTER to continue')
sys.exit(exitcode)
================================================
FILE: scripts/microrepl.py
================================================
# Copyright 2015 The Python Software Foundation (http://python.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
A simple shim around PySerial that detects the correct port to which the
MicroPython device is connected and attempts to make a serial connection to it
in order to bring up the Python REPL.
Based on https://github.com/ntoll/microrepl by Nicholas H.Tollervey and the
contributors.
"""
import errno
import sys
from time import sleep
import traceback
import serial
import serial.tools.miniterm
from serial.tools.miniterm import Miniterm, key_description
BAUDRATE = 115200
PARITY = 'N'
if sys.version_info >= (3, 0):
def character(b):
return b.decode('latin1')
else:
def character(b):
return b
def connect_miniterm(port):
try:
ser = serial.Serial(port, BAUDRATE, parity=PARITY, rtscts=False,
xonxoff=False)
return Miniterm(ser, echo=False)
except serial.SerialException as e:
if e.errno == errno.ENOENT:
sys.stderr.write(
"Device %r not found. Check your "
"MicroPython device path settings.\n" % port)
elif e.errno == errno.EBUSY:
# Device is busy. Explain what to do.
sys.stderr.write(
"Found the device, but it is busy. "
"Wait up to 20 seconds, or "
"press the reset button on the "
"back of the device next to the yellow light; "
"then try again.\n"
)
elif e.errno == errno.EACCES:
sys.stderr.write("Found the device, but could not connect.\n".format(port))
sys.stderr.write('%s\n' % (str(e),))
sys.stderr.write('On linux, try adding yourself to the "dialout" group:\n')
sys.stderr.write('sudo usermod -a -G dialout \n')
else:
# Try to be as helpful as possible.
sys.stderr.write("Found the device, but could not connect via" +
" port %r: %s\n" % (port, e))
sys.stderr.write("I'm not sure what to suggest. :-(\n")
input("Press ENTER to continue")
sys.exit(1)
def main():
"""
The function that actually runs the REPL.
"""
if len(sys.argv) not in range(2, 3):
print("Usage: microrepl.py /path/to/device [--nointerrupt]")
port = sys.argv[1]
print('Device path', port)
serial.tools.miniterm.EXITCHARCTER = character(b'\x1d')
miniterm = connect_miniterm(port)
# Emit some helpful information about the program and MicroPython.
shortcut_message = 'Quit: {} | Stop program: Ctrl+C | Reset: Ctrl+D\n'
help_message = 'Type \'help()\' (without the quotes) then press ENTER.\n'
exit_char = key_description(serial.tools.miniterm.EXITCHARCTER)
sys.stderr.write(shortcut_message.format(exit_char))
sys.stderr.write(help_message)
# Start everything.
miniterm.set_rx_encoding('utf-8')
miniterm.set_tx_encoding('utf-8')
miniterm.start()
sleep(0.5)
if len(sys.argv) != 3 or sys.argv[2] != '--nointerrupt':
miniterm.serial.write(b'\x03') # Connecting stops the running program.
try:
miniterm.join(True)
except KeyboardInterrupt:
pass
sys.stderr.write('\nEXIT - see you soon... :-)\n')
if __name__ == '__main__':
try:
main()
except Exception:
sys.stderr.write(traceback.format_exc())
input("Press ENTER to continue")
sys.exit(1)
================================================
FILE: scripts/microupload.py
================================================
# Copyright 2000-2017 JetBrains s.r.o.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Upload files and directories onto a MicroPython device.
Usage:
microupload PORT PATH [-X PATH]... [options]
Options:
-X --exclude=PATH Path to exclude, may be repeated.
-C --chdir=PATH Change current directory to path.
-v --verbose Verbose output.
"""
import time
import sys
import os
from contextlib import suppress
from typing import List, Iterable, TypeVar, Sequence, Set
from docopt import docopt
from ampy.pyboard import Pyboard
from ampy.files import Files, DirectoryExistsError
__all__ = []
verbose = False
T = TypeVar('T')
def main(args: List[str]) -> None:
global verbose
opts = docopt(__doc__, argv=args)
verbose = opts['--verbose']
root = opts['PATH']
chdir = opts['--chdir']
if chdir:
os.chdir(chdir)
port = opts['PORT']
print('Connecting to {}'.format(port), file=sys.stderr)
board = Pyboard(port)
files = Files(board)
rel_root = os.path.relpath(root, os.getcwd())
wait_for_board()
if os.path.isdir(root):
to_upload = [os.path.join(rel_root, x)
for x in list_files(root, opts['--exclude'])]
else:
to_upload = [rel_root]
created_cache = set()
for path in progress('Uploading files', to_upload):
local_path = os.path.abspath(path)
remote_path = os.path.normpath(path).replace(os.path.sep, '/')
if verbose:
print('\n{} -> {}'.format(local_path, remote_path),
file=sys.stderr, flush=True)
remote_dir = os.path.dirname(path)
if remote_dir:
make_dirs(files, remote_dir, created_cache)
with open(local_path, 'rb') as fd:
files.put(remote_path, fd.read())
print('Soft reboot', file=sys.stderr, flush=True)
soft_reset(board)
def make_dirs(files: Files, path: str,
created_cache: Set[str] = None) -> None:
"""Make all the directories the specified relative path consists of."""
if path == '.':
return
if created_cache is None:
created_cache = set()
parent = os.path.dirname(path)
if parent and parent not in created_cache:
make_dirs(files, parent, created_cache)
with suppress(DirectoryExistsError):
posix_path = path.replace(os.path.sep, '/')
files.mkdir(posix_path)
created_cache.add(path)
def soft_reset(board: Pyboard) -> None:
"""Perform soft-reset of the ESP8266 board."""
board.serial.write(b'\x03\x04')
def list_files(path: str, excluded: List[str]) -> Iterable[str]:
"""List relative file paths inside the given path."""
excluded = {os.path.abspath(x) for x in excluded}
for root, dirs, files in os.walk(path):
abs_root = os.path.abspath(root)
for d in list(dirs):
if os.path.join(abs_root, d) in excluded or d.startswith('.'):
dirs.remove(d)
for f in files:
if os.path.join(abs_root, f) not in excluded and not f.startswith('.'):
yield os.path.relpath(os.path.join(root, f), path)
def wait_for_board() -> None:
"""Wait for some ESP8266 devices to become ready for REPL commands."""
time.sleep(0.5)
def progress(msg: str, xs: Sequence[T]) -> Iterable[T]:
"""Show progress while iterating over a sequence."""
size = len(xs)
sys.stderr.write('\r{}: 0% (0/{})'.format(msg, size))
sys.stderr.flush()
for i, x in enumerate(xs, 1):
yield x
s = '{0}: {1}% ({2}/{3})'.format(msg, int(i * 100 / size), i, size)
sys.stderr.write('\r' + s)
sys.stderr.flush()
sys.stderr.write('\n')
sys.stderr.flush()
if __name__ == '__main__':
main(sys.argv[1:])
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/actions/MicroPythonAction.kt
================================================
package com.jetbrains.micropython.actions
import com.intellij.facet.ui.ValidationResult
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.jetbrains.micropython.settings.firstMicroPythonFacet
abstract class MicroPythonAction : AnAction() {
override fun update(e: AnActionEvent) {
val project = e.project ?: return
val facet = project.firstMicroPythonFacet
if (facet != null) {
e.presentation.isEnabledAndVisible = facet.checkValid() == ValidationResult.OK
} else {
e.presentation.isEnabledAndVisible = false
}
}
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/actions/MicroPythonCommandAction.kt
================================================
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.micropython.actions
import com.intellij.openapi.actionSystem.AnActionEvent
import com.jetbrains.micropython.settings.MicroPythonFacet
import com.jetbrains.micropython.settings.firstMicroPythonFacet
import org.jetbrains.plugins.terminal.LocalTerminalDirectRunner
import org.jetbrains.plugins.terminal.TerminalToolWindowManager
/**
* @author vlan
*/
abstract class MicroPythonCommandAction : MicroPythonAction() {
override fun actionPerformed(e: AnActionEvent) {
val project = e.project ?: return
val facet = project.firstMicroPythonFacet ?: return
val command = getCommand(facet) ?: return
TerminalToolWindowManager.getInstance(project).createNewSession(object : LocalTerminalDirectRunner(project) {
override fun getInitialCommand(envs: Map): List = command
})
}
protected abstract fun getCommand(facet: MicroPythonFacet): List?
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/actions/RemoveAllFilesFromDeviceAction.kt
================================================
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.micropython.actions
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.jetbrains.micropython.settings.MicroPythonFacet
/**
* @author vlan
*/
class RemoveAllFilesFromDeviceAction : MicroPythonCommandAction() {
override fun getCommand(facet: MicroPythonFacet): List? {
val pythonPath = facet.pythonPath ?: return null
val devicePath = facet.getOrDetectDevicePathSynchronously() ?: return null
return listOf(pythonPath, "${MicroPythonFacet.scriptsPath}/microcleanfs.py", devicePath)
}
override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/actions/RunMicroReplAction.kt
================================================
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.micropython.actions
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.components.service
import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleUtil
import com.intellij.openapi.vfs.VirtualFile
import com.jetbrains.micropython.repl.MicroPythonReplManager
import com.jetbrains.micropython.settings.firstMicroPythonFacet
class RunMicroReplAction : MicroPythonAction() {
override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.EDT
override fun actionPerformed(e: AnActionEvent) {
val project = e.project ?: return
val editor = FileEditorManagerEx.getInstanceEx(project).selectedTextEditor ?: return
/*
Here we make our best to find out module which is relevant to the current event.
There are two cases to consider:
1) There is an open file present.
2) No files are opened.
*/
val virtualFile: VirtualFile? = FileDocumentManager.getInstance().getFile(editor.document)
val module: Module? = if (virtualFile != null) {
ModuleUtil.findModuleForFile(virtualFile, project)
} else {
project.firstMicroPythonFacet?.module
}
project.service().startOrRestartRepl()
}
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/devices/Esp8266DeviceProvider.kt
================================================
package com.jetbrains.micropython.devices
import com.intellij.execution.configurations.CommandLineState
import com.intellij.execution.configurations.GeneralCommandLine
import com.intellij.execution.process.OSProcessHandler
import com.intellij.execution.runners.ExecutionEnvironment
import com.intellij.openapi.projectRoots.Sdk
import com.jetbrains.micropython.run.MicroPythonRunConfiguration
import com.jetbrains.micropython.run.getMicroUploadCommand
import com.jetbrains.micropython.settings.MicroPythonTypeHints
import com.jetbrains.micropython.settings.MicroPythonUsbId
import com.jetbrains.python.packaging.PyPackageManager
import com.jetbrains.python.packaging.PyRequirement
/**
* @author vlan
*/
class Esp8266DeviceProvider : MicroPythonDeviceProvider {
override val persistentName: String
get() = "ESP8266"
override val documentationURL: String
get() = "https://github.com/JetBrains/intellij-micropython/wiki/ESP8266"
override fun checkUsbId(usbId: MicroPythonUsbId): Boolean = usbIds.contains(usbId)
val usbIds: List
get() = listOf(
MicroPythonUsbId(0x1A86, 0x7523),
MicroPythonUsbId(0x10C4, 0xEA60),
MicroPythonUsbId(0x0403, 0x6001),
MicroPythonUsbId(0x239A, 0x8038), // Metro M4 Airlift Lite
)
override val typeHints: MicroPythonTypeHints by lazy {
MicroPythonTypeHints(listOf("stdlib", "micropython", "esp8266"))
}
override fun getPackageRequirements(sdk: Sdk): List {
val manager = PyPackageManager.getInstance(sdk)
return manager.parseRequirements("""|pyserial>=3.5,<4.0
|docopt>=0.6.2,<0.7
|adafruit-ampy>=1.0.5,<1.1""".trimMargin())
}
override fun getRunCommandLineState(configuration: MicroPythonRunConfiguration,
environment: ExecutionEnvironment): CommandLineState? {
val module = configuration.module ?: return null
val command = getMicroUploadCommand(configuration.path, module) ?: return null
return object : CommandLineState(environment) {
override fun startProcess() =
OSProcessHandler(GeneralCommandLine(command))
}
}
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/devices/MicroBitDeviceProvider.kt
================================================
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.micropython.devices
import com.intellij.execution.configurations.CommandLineState
import com.intellij.execution.configurations.GeneralCommandLine
import com.intellij.execution.process.OSProcessHandler
import com.intellij.execution.runners.ExecutionEnvironment
import com.intellij.openapi.projectRoots.Sdk
import com.jetbrains.micropython.run.MicroPythonRunConfiguration
import com.jetbrains.micropython.settings.MicroPythonTypeHints
import com.jetbrains.micropython.settings.MicroPythonUsbId
import com.jetbrains.micropython.settings.microPythonFacet
import com.jetbrains.python.packaging.PyPackageManager
import com.jetbrains.python.packaging.PyRequirement
/**
* @author vlan
*/
open class MicroBitDeviceProvider : MicroPythonDeviceProvider {
override val persistentName: String
get() = "Micro:bit"
override val documentationURL: String
get() = "https://github.com/JetBrains/intellij-micropython/wiki/BBC-Micro:bit"
override fun checkUsbId(usbId: MicroPythonUsbId): Boolean = usbId == MicroPythonUsbId(0x0D28, 0x0204)
override fun getPackageRequirements(sdk: Sdk): List {
val manager = PyPackageManager.getInstance(sdk)
return manager.parseRequirements("""|uflash>=1.2.4,<1.3
|docopt>=0.6.2,<0.7
|pyserial>=3.5,<4.0""".trimMargin())
}
override val typeHints: MicroPythonTypeHints by lazy {
MicroPythonTypeHints(listOf("microbit"))
}
override val detectedModuleNames: Set
get() = linkedSetOf("microbit")
override fun getRunCommandLineState(configuration: MicroPythonRunConfiguration,
environment: ExecutionEnvironment): CommandLineState? {
val pythonPath = configuration.module?.microPythonFacet?.pythonPath ?: return null
return object : CommandLineState(environment) {
override fun startProcess() =
OSProcessHandler(GeneralCommandLine(pythonPath, "-m", "uflash", configuration.path))
}
}
override val isDefault: Boolean
get() = true
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/devices/MicroBitV2DeviceProvider.kt
================================================
package com.jetbrains.micropython.devices
import com.intellij.openapi.projectRoots.Sdk
import com.jetbrains.python.packaging.PyPackageManager
import com.jetbrains.python.packaging.PyRequirement
class MicroBitV2DeviceProvider : MicroBitDeviceProvider() {
override val persistentName: String
get() = "Micro:bit V2"
override fun getPackageRequirements(sdk: Sdk): List {
val manager = PyPackageManager.getInstance(sdk)
return manager.parseRequirements("""|uflash>=2.0
|docopt>=0.6.2,<0.7
|pyserial>=3.5,<4.0""".trimMargin())
}
override val isDefault: Boolean
get() = false
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/devices/MicroPythonDeviceProvider.kt
================================================
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.micropython.devices
import com.intellij.execution.configurations.CommandLineState
import com.intellij.execution.runners.ExecutionEnvironment
import com.intellij.openapi.extensions.ExtensionPointName
import com.intellij.openapi.projectRoots.Sdk
import com.jetbrains.micropython.run.MicroPythonRunConfiguration
import com.jetbrains.micropython.settings.MicroPythonTypeHints
import com.jetbrains.micropython.settings.MicroPythonUsbId
import com.jetbrains.python.packaging.PyRequirement
/**
* @author vlan
*/
interface MicroPythonDeviceProvider {
companion object {
private val EP_NAME: ExtensionPointName =
ExtensionPointName.create("com.jetbrains.micropython.deviceProvider")
val providers: List
get() = EP_NAME.extensionList
val default: MicroPythonDeviceProvider
get() = providers.first { it.isDefault }
}
val persistentName: String
val documentationURL: String
fun checkUsbId(usbId: MicroPythonUsbId): Boolean
val presentableName: String
get() = persistentName
fun getPackageRequirements(sdk: Sdk): List = emptyList()
val typeHints: MicroPythonTypeHints?
get() = null
val detectedModuleNames: Set
get() = emptySet()
fun getRunCommandLineState(configuration: MicroPythonRunConfiguration,
environment: ExecutionEnvironment): CommandLineState? = null
val isDefault: Boolean
get() = false
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/devices/PyboardDeviceProvider.kt
================================================
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.micropython.devices
import com.intellij.execution.configurations.CommandLineState
import com.intellij.execution.configurations.GeneralCommandLine
import com.intellij.execution.process.OSProcessHandler
import com.intellij.execution.runners.ExecutionEnvironment
import com.intellij.openapi.projectRoots.Sdk
import com.jetbrains.micropython.run.MicroPythonRunConfiguration
import com.jetbrains.micropython.run.getMicroUploadCommand
import com.jetbrains.micropython.settings.MicroPythonTypeHints
import com.jetbrains.micropython.settings.MicroPythonUsbId
import com.jetbrains.python.packaging.PyPackageManager
import com.jetbrains.python.packaging.PyRequirement
/**
* @author stefanhoelzl
*/
class PyboardDeviceProvider : MicroPythonDeviceProvider {
override val persistentName: String
get() = "Pyboard"
override val documentationURL: String
get() = "https://github.com/JetBrains/intellij-micropython/wiki/Pyboard"
override fun checkUsbId(usbId: MicroPythonUsbId): Boolean = usbId == MicroPythonUsbId(0xF055, 0x9800)
override val typeHints: MicroPythonTypeHints by lazy {
MicroPythonTypeHints(listOf("stdlib", "micropython", "pyboard"))
}
override fun getPackageRequirements(sdk: Sdk): List {
val manager = PyPackageManager.getInstance(sdk)
return manager.parseRequirements("""|pyserial>=3.5,<4.0
|docopt>=0.6.2,<0.7
|adafruit-ampy>=1.0.5,<1.1""".trimMargin())
}
override fun getRunCommandLineState(configuration: MicroPythonRunConfiguration,
environment: ExecutionEnvironment): CommandLineState? {
val module = configuration.module ?: return null
val command = getMicroUploadCommand(configuration.path, module) ?: return null
return object : CommandLineState(environment) {
override fun startProcess() =
OSProcessHandler(GeneralCommandLine(command))
}
}
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/devices/RPiPicoDeviceProvider.kt
================================================
package com.jetbrains.micropython.devices
import com.intellij.execution.configurations.CommandLineState
import com.intellij.execution.configurations.GeneralCommandLine
import com.intellij.execution.process.OSProcessHandler
import com.intellij.execution.runners.ExecutionEnvironment
import com.intellij.openapi.projectRoots.Sdk
import com.jetbrains.micropython.run.MicroPythonRunConfiguration
import com.jetbrains.micropython.run.getMicroUploadCommand
import com.jetbrains.micropython.settings.MicroPythonTypeHints
import com.jetbrains.micropython.settings.MicroPythonUsbId
import com.jetbrains.python.packaging.PyPackageManager
import com.jetbrains.python.packaging.PyRequirement
/**
* @author timsavage
*/
class RPiPicoDeviceProvider : MicroPythonDeviceProvider {
override val persistentName: String
get() = "Raspberry Pi Pico"
override val documentationURL: String
get() = "https://www.raspberrypi.com/documentation/microcontrollers/raspberry-pi-pico.html"
/**
* From https://github.com/raspberrypi/usb-pid :
*
* "The USB-IF have given Raspberry Pi permission to sub-license the USB product ID values for its vendor ID (0x2E8A)
* since they are to be used on a common silicon component which will be used within a customer's product (the RP2040
* silicon)."
*
* Consequently, most usb devices with the vendor id 0x2E8A are likely to be an RP2040, and therefore capable of
* running MicroPython.
*/
override fun checkUsbId(usbId: MicroPythonUsbId): Boolean =
usbId.vendorId == 0x2E8A && ProductId.likelyToRunMicroPython(usbId.productId)
object ProductId {
private const val PICO_WITH_STANDARD_MICROPYTHON_FIRMWARE = 0x05
/**
* Raspberry Pi have allocated the productId range 0x1000 - 0x1fff for Commercial RP2040 devices.
* See https://github.com/raspberrypi/usb-pid#assignment
*/
private val COMMERCIAL_RANGE = 0x1000..0x1fff
fun likelyToRunMicroPython(productId: Int): Boolean =
productId == PICO_WITH_STANDARD_MICROPYTHON_FIRMWARE || productId in COMMERCIAL_RANGE
}
override val typeHints: MicroPythonTypeHints by lazy {
MicroPythonTypeHints(listOf("stdlib", "micropython", "rpi_pico"))
}
override fun getPackageRequirements(sdk: Sdk): List {
val manager = PyPackageManager.getInstance(sdk)
return manager.parseRequirements("""|pyserial>=3.5,<4.0
|docopt>=0.6.2,<0.7
|adafruit-ampy>=1.0.5,<1.1""".trimMargin())
}
override fun getRunCommandLineState(configuration: MicroPythonRunConfiguration,
environment: ExecutionEnvironment): CommandLineState? {
val module = configuration.module ?: return null
val command = getMicroUploadCommand(configuration.path, module) ?: return null
return object : CommandLineState(environment) {
override fun startProcess() =
OSProcessHandler(GeneralCommandLine(command))
}
}
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/inspections/MicroPythonRequirementsInspection.kt
================================================
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.micropython.inspections
import com.intellij.codeInspection.*
import com.intellij.facet.ui.FacetConfigurationQuickFix
import com.intellij.openapi.module.ModuleUtilCore
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import com.jetbrains.micropython.settings.microPythonFacet
/**
* @author vlan
*/
class MicroPythonRequirementsInspection : LocalInspectionTool() {
override fun checkFile(file: PsiFile, manager: InspectionManager, isOnTheFly: Boolean): Array? {
val module = ModuleUtilCore.findModuleForPsiElement(file) ?: return null
val facet = module.microPythonFacet ?: return null
val result = facet.checkValid()
if (result.isOk) return null
val facetFix: FacetConfigurationQuickFix? = result.quickFix
val fix = if (facetFix != null) object : LocalQuickFix {
override fun getFamilyName() = "Missing required MicroPython packages"
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
facetFix.run(null)
}
} else null
val fixes = if (fix != null) arrayOf(fix) else emptyArray()
return arrayOf(manager.createProblemDescriptor(file, result.errorMessage, true, fixes,
ProblemHighlightType.GENERIC_ERROR_OR_WARNING))
}
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/repl/MicroPythonReplManager.kt
================================================
package com.jetbrains.micropython.repl
import com.intellij.openapi.components.Service
import com.intellij.openapi.project.Project
import com.intellij.util.messages.Topic
interface MicroPythonReplControl {
fun stopRepl()
fun startOrRestartRepl(interrupt: Boolean = true)
}
@Service(Service.Level.PROJECT)
class MicroPythonReplManager(private val project: Project) : MicroPythonReplControl {
override fun stopRepl() =
project.messageBus.syncPublisher(MICROPYTHON_REPL_CONTROL).stopRepl()
override fun startOrRestartRepl(interrupt: Boolean) =
project.messageBus.syncPublisher(MICROPYTHON_REPL_CONTROL).startOrRestartRepl(interrupt)
}
val MICROPYTHON_REPL_CONTROL = Topic(MicroPythonReplControl::class.java)
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/repl/StopReplBeforeRunTask.kt
================================================
package com.jetbrains.micropython.repl
import com.intellij.execution.BeforeRunTask
import com.intellij.execution.BeforeRunTaskProvider
import com.intellij.execution.configurations.RunConfiguration
import com.intellij.execution.runners.ExecutionEnvironment
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.service
import com.intellij.openapi.util.Key
import com.jetbrains.micropython.run.MicroPythonRunConfiguration
import com.jetbrains.micropython.settings.MicroPythonFacetType
class StopReplBeforeRunTask : BeforeRunTask(StopReplBeforeRunTaskProvider.ID) {
init {
isEnabled = true
}
}
class StopReplBeforeRunTaskProvider : BeforeRunTaskProvider() {
companion object {
val ID = Key.create("MicroPython.StopREPL.Before.Run")
}
override fun getId() = ID
override fun getIcon() = MicroPythonFacetType.LOGO
override fun getName() = "Stop MicroPython REPL"
override fun createTask(runConfiguration: RunConfiguration): StopReplBeforeRunTask? {
if (runConfiguration is MicroPythonRunConfiguration) {
return StopReplBeforeRunTask()
}
return null
}
override fun executeTask(
context: DataContext,
configuration: RunConfiguration,
environment: ExecutionEnvironment,
task: StopReplBeforeRunTask
): Boolean {
if (configuration is MicroPythonRunConfiguration) {
environment.project.service().stopRepl()
}
return true
}
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/repl/ToolWindowReplTab.kt
================================================
package com.jetbrains.micropython.repl
import com.intellij.icons.AllIcons
import com.intellij.ide.ActivityTracker
import com.intellij.openapi.Disposable
import com.intellij.openapi.actionSystem.*
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.components.service
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.DumbAwareAction
import com.intellij.openapi.util.NlsContexts
import com.intellij.util.application
import com.jediterm.terminal.TtyConnector
import com.jetbrains.micropython.settings.MicroPythonDevicesConfiguration
import com.jetbrains.micropython.settings.MicroPythonFacet
import com.jetbrains.micropython.settings.microPythonFacet
import org.jetbrains.plugins.terminal.JBTerminalSystemSettingsProvider
import org.jetbrains.plugins.terminal.LocalTerminalDirectRunner
import org.jetbrains.plugins.terminal.ShellStartupOptions
import org.jetbrains.plugins.terminal.ShellTerminalWidget
import java.awt.BorderLayout
import java.util.concurrent.TimeUnit
import javax.swing.JPanel
class ToolWindowReplTab(val module: Module, parent: Disposable) : MicroPythonReplControl {
private val deviceConfiguration = MicroPythonDevicesConfiguration.getInstance(module.project)
val terminalWidget: ShellTerminalWidget
init {
val mySettingsProvider = JBTerminalSystemSettingsProvider()
terminalWidget = ShellTerminalWidget(module.project, mySettingsProvider, parent)
terminalWidget.isEnabled = false
module.project.messageBus.connect(parent).subscribe(MICROPYTHON_REPL_CONTROL, this)
}
private fun connectWidgetTty(terminalWidget: ShellTerminalWidget, connector: TtyConnector) {
terminalWidget.start(connector)
val modalityState = ModalityState.stateForComponent(terminalWidget.component)
ApplicationManager.getApplication().invokeLater(
{
try {
terminalWidget.component.revalidate()
terminalWidget.notifyStarted()
} catch (e: RuntimeException) {
TODO("You can't cut back on error reporting! You will regret this!")
}
},
modalityState
)
}
fun createUI(): JPanel {
val actionManager = ActionManager.getInstance()
val toolbarActions = DefaultActionGroup().apply {
add(replStartAction)
add(replStopAction)
add(clearReplOnLaunch)
}
val actionToolbar = actionManager.createActionToolbar("MicroPythonREPL", toolbarActions, false)
actionToolbar.targetComponent = terminalWidget.component
return JPanel().apply {
layout = BorderLayout()
add(actionToolbar.component, BorderLayout.WEST)
add(terminalWidget.component)
}
}
private val replStopAction = object : DumbAwareAction(
"Stop", "Stop REPL session", AllIcons.Actions.Suspend
) {
override fun update(e: AnActionEvent) {
e.presentation.isEnabled = terminalWidget.isSessionRunning
}
override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.EDT
override fun actionPerformed(e: AnActionEvent) {
stopRepl()
}
}
private val replStartAction =
object : DumbAwareAction("Restart", "Restart REPL session", AllIcons.Actions.Restart) {
override fun update(e: AnActionEvent) {
e.presentation.isEnabled = true
}
override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.EDT
override fun actionPerformed(e: AnActionEvent) =
module.project.service().startOrRestartRepl()
}
private val clearReplOnLaunch = object : ToggleAction(
"Clear Window On Start",
"Clear REPL window on every start", AllIcons.Actions.GC
) {
override fun isSelected(e: AnActionEvent): Boolean {
return deviceConfiguration.clearReplOnLaunch
}
override fun setSelected(e: AnActionEvent, state: Boolean) {
deviceConfiguration.clearReplOnLaunch = state
}
override fun getActionUpdateThread(): ActionUpdateThread {
return ActionUpdateThread.EDT
}
}
private fun onProcessCreationFailed(@NlsContexts.SystemNotificationText reason: String) {
terminalWidget.terminal.nextLine()
terminalWidget.terminal.writeCharacters(reason)
}
private fun interruptBanner() {
application.invokeLater(
{
with(terminalWidget.terminal) {
nextLine()
writeCharacters("=== SESSION HAS BEEN INTERRUPTED ===")
nextLine()
}
},
{ module.isDisposed }
)
}
override fun stopRepl() {
interruptBanner()
application.executeOnPooledThread {
synchronized(this) {
terminalWidget.processTtyConnector?.process?.destroy()
}
}
}
override fun startOrRestartRepl(interrupt: Boolean) {
interruptBanner()
application.executeOnPooledThread {
synchronized(this) {
terminalWidget.processTtyConnector?.process?.apply {
if (isAlive) destroy()
waitFor(10, TimeUnit.SECONDS)
}
}
application.invokeLater(
{ startRepl(interrupt) },
{ module.project.isDisposed })
}
}
private fun startRepl(interrupt: Boolean) {
val facet = module.microPythonFacet ?: return
val devicePath = facet.getOrDetectDevicePathSynchronously()
if (facet.pythonPath == null) {
onProcessCreationFailed("Valid Python interpreter is needed to start REPL!")
return
}
if (devicePath == null) {
onProcessCreationFailed("Device path is not specified, please check settings.")
return
}
val initialShellCommand = mutableListOf(
facet.pythonPath!!,
"${MicroPythonFacet.scriptsPath}/microrepl.py",
devicePath
).apply {
if(!interrupt) add("--nointerrupt")
}
val terminalRunner = LocalTerminalDirectRunner(module.project)
synchronized(this) {
val terminalOptions = terminalRunner.configureStartupOptions(
ShellStartupOptions.Builder()
.shellCommand(initialShellCommand)
.build()
)
val process = terminalRunner.createProcess(terminalOptions)
val ttyConnector = terminalRunner.createTtyConnector(process)
process.onExit().whenComplete { _, _ -> ActivityTracker.getInstance().inc() }
if (deviceConfiguration.clearReplOnLaunch) {
terminalWidget.terminalTextBuffer.clearHistory()
terminalWidget.terminal.reset(true)
} else {
terminalWidget.terminal.nextLine()
}
connectWidgetTty(terminalWidget, ttyConnector)
terminalWidget.isEnabled = true
}
}
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/run/MicroPythonConfigurationType.kt
================================================
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.micropython.run
import com.intellij.execution.configurations.ConfigurationFactory
import com.intellij.execution.configurations.ConfigurationType
import com.intellij.execution.configurations.ConfigurationTypeUtil
import com.intellij.execution.configurations.RunConfiguration
import com.intellij.openapi.project.Project
import com.jetbrains.micropython.settings.MicroPythonFacetType
import com.jetbrains.python.run.PythonConfigurationFactoryBase
import javax.swing.Icon
/**
* @author Mikhail Golubev
*/
class MicroPythonConfigurationType : ConfigurationType {
companion object {
fun getInstance(): MicroPythonConfigurationType =
ConfigurationTypeUtil.findConfigurationType(MicroPythonConfigurationType::class.java)
}
internal val factory = object : PythonConfigurationFactoryBase(this) {
override fun createTemplateConfiguration(project: Project): RunConfiguration =
MicroPythonRunConfiguration(project, this)
override fun getId(): String = "MicroPython"
}
override fun getIcon(): Icon = MicroPythonFacetType.LOGO
override fun getConfigurationTypeDescription(): String = "MicroPython run configuration"
override fun getId(): String = "MicroPythonConfigurationType"
override fun getDisplayName(): String = "MicroPython"
override fun getConfigurationFactories(): Array = arrayOf(factory)
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/run/MicroPythonRunConfiguration.kt
================================================
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.micropython.run
import com.intellij.execution.ExecutionResult
import com.intellij.execution.Executor
import com.intellij.execution.configuration.AbstractRunConfiguration
import com.intellij.execution.configurations.ConfigurationFactory
import com.intellij.execution.configurations.RunConfigurationWithSuppressedDefaultDebugAction
import com.intellij.execution.configurations.RunProfileState
import com.intellij.execution.configurations.RuntimeConfigurationError
import com.intellij.execution.process.ProcessEvent
import com.intellij.execution.process.ProcessListener
import com.intellij.execution.runners.ExecutionEnvironment
import com.intellij.execution.runners.ProgramRunner
import com.intellij.facet.ui.ValidationResult
import com.intellij.openapi.actionSystem.LangDataKeys
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.service
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleUtil
import com.intellij.openapi.options.ShowSettingsUtil
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ui.configuration.ProjectSettingsService
import com.intellij.openapi.util.Key
import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.wm.ToolWindowManager
import com.intellij.util.PathUtil
import com.intellij.util.PlatformUtils
import com.jetbrains.micropython.repl.MicroPythonReplManager
import com.jetbrains.micropython.settings.MicroPythonProjectConfigurable
import com.jetbrains.micropython.settings.microPythonFacet
import org.jdom.Element
/**
* @author Mikhail Golubev
*/
class RunStateWrapper(private val original: RunProfileState, val block: () -> Unit) : RunProfileState by original {
override fun execute(executor: Executor?, runner: ProgramRunner<*>): ExecutionResult? {
val result = original.execute(executor, runner)
result?.processHandler?.addProcessListener(object : ProcessListener {
override fun startNotified(event: ProcessEvent) {}
override fun processTerminated(event: ProcessEvent) {
if (event.exitCode == 0) {
block()
}
}
override fun onTextAvailable(event: ProcessEvent, outputType: Key<*>) {}
})
return result
}
}
class MicroPythonRunConfiguration(project: Project, factory: ConfigurationFactory) : AbstractRunConfiguration(project, factory), RunConfigurationWithSuppressedDefaultDebugAction {
var path: String = ""
var runReplOnSuccess: Boolean = false
override fun getValidModules() =
allModules.filter { it.microPythonFacet != null }.toMutableList()
override fun getConfigurationEditor() = MicroPythonRunConfigurationEditor(this)
override fun getState(executor: Executor, environment: ExecutionEnvironment): RunProfileState? {
val currentModule = environment.dataContext?.getData(LangDataKeys.MODULE) ?: module
val state = currentModule?.microPythonFacet?.configuration?.deviceProvider?.getRunCommandLineState(this, environment)
// ComponentManagerImpl
if (runReplOnSuccess && state != null) {
return RunStateWrapper(state) {
ApplicationManager.getApplication().invokeLater {
project.service().startOrRestartRepl(false)
ToolWindowManager.getInstance(project).getToolWindow("MicroPython")?.show()
}
}
}
return state
}
override fun checkConfiguration() {
super.checkConfiguration()
if (StringUtil.isEmpty(path)) {
throw RuntimeConfigurationError("Path is not specified")
}
val m = module ?: throw RuntimeConfigurationError("Module for path is not found")
val showSettings = Runnable {
when {
PlatformUtils.isPyCharm() ->
ShowSettingsUtil.getInstance().showSettingsDialog(project, MicroPythonProjectConfigurable::class.java)
PlatformUtils.isIntelliJ() ->
ProjectSettingsService.getInstance(project).openModuleSettings(module)
else ->
ShowSettingsUtil.getInstance().showSettingsDialog(project)
}
}
val facet = m.microPythonFacet ?: throw RuntimeConfigurationError(
"MicroPython support is not enabled for selected module in IDE settings",
showSettings
)
val validationResult = facet.checkValid()
if (validationResult != ValidationResult.OK) {
val runQuickFix = Runnable {
validationResult.quickFix.run(null)
}
throw RuntimeConfigurationError(validationResult.errorMessage, runQuickFix)
}
facet.pythonPath ?: throw RuntimeConfigurationError("Python interpreter is not found")
if (!facet.autoDetectDevicePath && facet.devicePath == null) {
throw RuntimeConfigurationError("Device path is not specified in IDE settings", showSettings)
}
}
override fun suggestedName() = "Flash ${PathUtil.getFileName(path)}"
override fun writeExternal(element: Element) {
super.writeExternal(element)
element.setAttribute("path", path)
element.setAttribute("runReplOnSuccess", if (runReplOnSuccess) "yes" else "no")
}
override fun readExternal(element: Element) {
super.readExternal(element)
configurationModule.readExternal(element)
element.getAttributeValue("path")?.let {
path = it
}
element.getAttributeValue("runReplOnSuccess")?.let {
runReplOnSuccess = it == "yes"
}
}
val module: Module?
get() {
val file = StandardFileSystems.local().findFileByPath(path) ?: return null
return ModuleUtil.findModuleForFile(file, project)
}
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/run/MicroPythonRunConfigurationEditor.kt
================================================
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.micropython.run
import com.intellij.openapi.fileChooser.FileChooserDescriptor
import com.intellij.openapi.options.SettingsEditor
import com.intellij.openapi.ui.ComponentWithBrowseButton
import com.intellij.openapi.ui.TextComponentAccessor
import com.intellij.openapi.ui.TextFieldWithBrowseButton
import com.intellij.ui.components.CheckBox
import com.intellij.util.ui.FormBuilder
import javax.swing.JComponent
class MicroPythonRunConfigurationEditor(config: MicroPythonRunConfiguration) : SettingsEditor() {
private val pathField = TextFieldWithBrowseButton()
private val runReplOnSuccess = CheckBox("Open MicroPython REPL on success", selected = true)
init {
val descriptor = FileChooserDescriptor(true, true, false, false, false, false)
val listener = ComponentWithBrowseButton.BrowseFolderActionListener(
"Select Path", "",
pathField,
config.project, descriptor,
TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT
)
pathField.addActionListener(listener)
}
override fun createEditor(): JComponent =
FormBuilder.createFormBuilder()
.addLabeledComponent("Path:", pathField)
.addComponent(runReplOnSuccess)
.panel
override fun applyEditorTo(s: MicroPythonRunConfiguration) {
s.path = pathField.text
s.runReplOnSuccess = runReplOnSuccess.isSelected
}
override fun resetEditorFrom(s: MicroPythonRunConfiguration) {
pathField.text = s.path
runReplOnSuccess.isSelected = s.runReplOnSuccess
}
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/run/MicroPythonRunConfigurationProducer.kt
================================================
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.micropython.run
import com.intellij.execution.actions.ConfigurationContext
import com.intellij.execution.actions.ConfigurationFromContext
import com.intellij.execution.actions.LazyRunConfigurationProducer
import com.intellij.execution.configurations.ConfigurationFactory
import com.intellij.facet.FacetManager
import com.intellij.openapi.module.ModuleUtilCore
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Ref
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiElement
import com.intellij.testFramework.LightVirtualFile
import com.jetbrains.micropython.settings.MicroPythonFacetType
import com.jetbrains.python.run.AbstractPythonRunConfiguration
/**
* @author Mikhail Golubev
*/
class MicroPythonRunConfigurationProducer : LazyRunConfigurationProducer() {
override fun getConfigurationFactory(): ConfigurationFactory {
return MicroPythonConfigurationType.getInstance().factory
}
override fun isConfigurationFromContext(configuration: MicroPythonRunConfiguration, context: ConfigurationContext): Boolean {
val file = context.location?.virtualFile ?: return false
if (!facetEnabledForElement(file, context.project)) return false
if (file is LightVirtualFile) return false
return configuration.path == file.path
}
override fun setupConfigurationFromContext(configuration: MicroPythonRunConfiguration,
context: ConfigurationContext,
sourceElement: Ref): Boolean {
val file = context.location?.virtualFile ?: return false
if (!facetEnabledForElement(file, context.project)) return false
configuration.path = file.path
configuration.setGeneratedName()
configuration.setModule(ModuleUtilCore.findModuleForFile(file, context.project))
return true
}
private fun facetEnabledForElement(virtualFile: VirtualFile, project: Project): Boolean {
val module = ModuleUtilCore.findModuleForFile(virtualFile, project) ?: return false
return FacetManager.getInstance(module)?.getFacetByType(MicroPythonFacetType.ID) != null
}
override fun shouldReplace(self: ConfigurationFromContext, other: ConfigurationFromContext) =
other.configuration is AbstractPythonRunConfiguration<*>
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/run/MicroUpload.kt
================================================
package com.jetbrains.micropython.run
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.guessModuleDir
import com.intellij.openapi.project.rootManager
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import com.jetbrains.micropython.settings.MicroPythonFacet
import com.jetbrains.micropython.settings.microPythonFacet
fun getMicroUploadCommand(path: String, module: Module): List? {
val facet = module.microPythonFacet ?: return null
val pythonPath = facet.pythonPath ?: return null
val devicePath = facet.getOrDetectDevicePathSynchronously() ?: return null
val file = StandardFileSystems.local().findFileByPath(path) ?: return null
val rootDir = getClosestRoot(file, module) ?: return null
val excludeRoots = ModuleRootManager.getInstance(module).excludeRoots
val excludes = excludeRoots
.asSequence()
.filter { VfsUtil.isAncestor(file, it, false) }
.map { VfsUtilCore.getRelativePath(it, rootDir) }
.filterNotNull()
.map { listOf("-X", it) }
.flatten()
.toList()
return listOf(pythonPath, "${MicroPythonFacet.scriptsPath}/microupload.py", "-C", rootDir.path) +
excludes +
listOf("-v", devicePath, path)
}
private fun getClosestRoot(file: VirtualFile, module: Module): VirtualFile? {
val roots = mutableSetOf().apply {
val rootManager = module.rootManager
addAll(rootManager.contentRoots)
addAll(rootManager.sourceRoots)
}
var parent: VirtualFile? = file
while (parent != null) {
if (parent in roots) {
break
}
parent = parent.parent
}
return parent ?: module.guessModuleDir()
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/settings/MicroPythonDevicesConfiguration.kt
================================================
package com.jetbrains.micropython.settings
import com.intellij.openapi.components.PersistentStateComponent
import com.intellij.openapi.components.State
import com.intellij.openapi.components.Storage
import com.intellij.openapi.components.StoragePathMacros
import com.intellij.openapi.project.Project
import com.intellij.util.xmlb.XmlSerializerUtil
import com.intellij.util.xmlb.annotations.Attribute
/**
* @author vlan
*/
@State(name = "MicroPythonDevices", storages = [Storage(StoragePathMacros.WORKSPACE_FILE)])
class MicroPythonDevicesConfiguration : PersistentStateComponent {
companion object {
fun getInstance(project: Project): MicroPythonDevicesConfiguration =
project.getService(MicroPythonDevicesConfiguration::class.java)
}
// Currently, the device path is stored per project, not per module
@Attribute var devicePath: String = ""
@Attribute var autoDetectDevicePath: Boolean = true
@Attribute var clearReplOnLaunch: Boolean = true
override fun getState() = this
override fun loadState(state: MicroPythonDevicesConfiguration) {
XmlSerializerUtil.copyBean(state, this)
}
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/settings/MicroPythonFacet.kt
================================================
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.micropython.settings
import com.intellij.execution.configurations.GeneralCommandLine
import com.intellij.execution.process.CapturingProcessHandler
import com.intellij.facet.Facet
import com.intellij.facet.FacetManager
import com.intellij.facet.FacetType
import com.intellij.facet.ui.FacetConfigurationQuickFix
import com.intellij.facet.ui.ValidationResult
import com.intellij.ide.plugins.IdeaPluginDescriptor
import com.intellij.ide.plugins.PluginManagerCore
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.extensions.PluginId
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.Messages
import com.intellij.util.text.nullize
import com.jetbrains.micropython.devices.MicroPythonDeviceProvider
import com.jetbrains.python.facet.FacetLibraryConfigurator
import com.jetbrains.python.facet.LibraryContributingFacet
import com.jetbrains.python.packaging.PyPackageManager
import com.jetbrains.python.packaging.PyPackageManagerUI
import com.jetbrains.python.psi.LanguageLevel
import com.jetbrains.python.sdk.PySdkUtil
import com.jetbrains.python.sdk.PythonSdkUtil
import javax.swing.JComponent
/**
* @author vlan
*/
class MicroPythonFacet(facetType: FacetType, *>, module: Module, name: String,
configuration: MicroPythonFacetConfiguration, underlyingFacet: Facet<*>?)
: LibraryContributingFacet(facetType, module, name, configuration, underlyingFacet) {
companion object {
private const val PLUGIN_ID = "intellij-micropython"
val scriptsPath: String
get() = "${pluginDescriptor.pluginPath}/scripts"
private val pluginDescriptor: IdeaPluginDescriptor
get() = PluginManagerCore.getPlugin(PluginId.getId(PLUGIN_ID)) ?:
throw RuntimeException("The $PLUGIN_ID plugin cannot find itself")
}
override fun initFacet() {
updateLibrary()
}
override fun updateLibrary() {
val plugin = pluginDescriptor
val boardHintsPaths = configuration.deviceProvider.typeHints?.paths?.map {
"${plugin.pluginPath}/typehints/$it"
} ?: emptyList()
ApplicationManager.getApplication().invokeLater {
FacetLibraryConfigurator.attachPythonLibrary(module, null, "MicroPython", boardHintsPaths)
removeLegacyLibraries()
}
}
override fun removeLibrary() {
FacetLibraryConfigurator.detachPythonLibrary(module, "MicroPython")
}
fun checkValid(): ValidationResult {
val provider = configuration.deviceProvider
val sdk = PythonSdkUtil.findPythonSdk(module)
if (sdk == null || PythonSdkUtil.isInvalid(sdk) || PySdkUtil.getLanguageLevelForSdk(sdk).isOlderThan(LanguageLevel.PYTHON35)) {
return ValidationResult("${provider.presentableName} support requires valid Python 3.5+ SDK")
}
val packageManager = PyPackageManager.getInstance(sdk)
val packages = packageManager.packages ?: return ValidationResult.OK
val requirements = provider.getPackageRequirements(sdk).filter { it.match(packages) == null }.toList()
if (requirements.isNotEmpty()) {
val requirementsText = requirements.joinToString(", ") {
it.presentableText
}
return ValidationResult("Packages required for ${provider.presentableName} support not found: $requirementsText",
object : FacetConfigurationQuickFix("Install Requirements") {
override fun run(place: JComponent?) {
PyPackageManagerUI(module.project, sdk, null).install(requirements, emptyList())
}
})
}
return ValidationResult.OK
}
private fun findSerialPorts(deviceProvider: MicroPythonDeviceProvider, indicator: ProgressIndicator): List {
val timeout = 1_000
val pythonPath = pythonPath ?: return emptyList()
val command = listOf(pythonPath, "$scriptsPath/findusb.py")
val process = CapturingProcessHandler(GeneralCommandLine(command))
val output = process.runProcessWithProgressIndicator(indicator, timeout)
return when {
output.isCancelled -> emptyList()
output.isTimeout -> emptyList()
output.exitCode != 0 -> emptyList()
else -> {
output.stdoutLines.associate {
Pair(MicroPythonUsbId.parse(it.substringBefore(' ')), it.substringAfter(' '))
}.filterKeys { deviceProvider.checkUsbId(it) }.values.toList()
}
}
}
val pythonPath: String?
get() = PythonSdkUtil.findPythonSdk(module)?.homePath
var devicePath: String?
get() = MicroPythonDevicesConfiguration.getInstance(module.project).devicePath.nullize(true)
set(value) {
MicroPythonDevicesConfiguration.getInstance(module.project).devicePath = value ?: ""
}
var autoDetectDevicePath: Boolean
get() = MicroPythonDevicesConfiguration.getInstance(module.project).autoDetectDevicePath
set(value) {
MicroPythonDevicesConfiguration.getInstance(module.project).autoDetectDevicePath = value
}
fun getOrDetectDevicePathSynchronously(): String? =
if (autoDetectDevicePath)
detectDevicePathSynchronously(configuration.deviceProvider)
else
devicePath
fun detectDevicePathSynchronously(deviceProvider: MicroPythonDeviceProvider): String? {
ApplicationManager.getApplication().assertIsDispatchThread()
var detectedDevicePath: String? = null
val deviceProviderName = deviceProvider.presentableName
val progress = ProgressManager.getInstance()
progress.runProcessWithProgressSynchronously({
progress.progressIndicator.text = "Detecting connected $deviceProviderName devices..."
val detected = findSerialPorts(deviceProvider, progress.progressIndicator).firstOrNull()
ApplicationManager.getApplication().invokeLater {
if (detected == null) {
Messages.showErrorDialog(module.project,
"""Possible solutions:
|
|- Check if your device is connected to your computer
|- Specify the device path manually in the IDE settings for MicroPython""".trimMargin(),
"No $deviceProviderName Devices Detected")
}
detectedDevicePath = detected
}
}, "Detecting MicroPython devices", true, module.project, null)
return detectedDevicePath
}
private fun removeLegacyLibraries() {
FacetLibraryConfigurator.detachPythonLibrary(module, "Micro:bit")
}
}
val Module.microPythonFacet: MicroPythonFacet?
get() = FacetManager.getInstance(this).getFacetByType(MicroPythonFacetType.ID)
val Project.firstMicroPythonFacet: MicroPythonFacet?
get() = ModuleManager.getInstance(this).modules
.asSequence()
.map { it.microPythonFacet }
.firstOrNull()
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/settings/MicroPythonFacetConfiguration.kt
================================================
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.micropython.settings
import com.intellij.facet.FacetConfiguration
import com.intellij.facet.ui.FacetEditorContext
import com.intellij.facet.ui.FacetEditorTab
import com.intellij.facet.ui.FacetEditorValidator
import com.intellij.facet.ui.FacetValidatorsManager
import com.jetbrains.micropython.devices.MicroPythonDeviceProvider
import org.jdom.Element
/**
* @author vlan
*/
class MicroPythonFacetConfiguration : FacetConfiguration {
var deviceProvider = MicroPythonDeviceProvider.default
override fun createEditorTabs(editorContext: FacetEditorContext, validatorsManager: FacetValidatorsManager): Array {
val facet = editorContext.facet as MicroPythonFacet
validatorsManager.registerValidator(object: FacetEditorValidator() {
override fun check() = facet.checkValid()
})
return arrayOf(MicroPythonFacetEditorTab(this, facet))
}
@Deprecated("Deprecated in Java")
override fun readExternal(element: Element?) {
val deviceName = element?.getChild("device")?.getAttribute("name")?.value
val device = MicroPythonDeviceProvider.providers.firstOrNull { it.persistentName == deviceName }
deviceProvider = device ?: MicroPythonDeviceProvider.default
}
@Deprecated("Deprecated in Java")
override fun writeExternal(element: Element?) {
val deviceElement = Element("device")
deviceElement.setAttribute("name", deviceProvider.persistentName)
element?.addContent(deviceElement)
}
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/settings/MicroPythonFacetDetector.kt
================================================
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.micropython.settings
import com.intellij.framework.detection.FacetBasedFrameworkDetector
import com.intellij.framework.detection.FileContentPattern
import com.intellij.openapi.fileTypes.FileType
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.patterns.PatternCondition
import com.intellij.util.ProcessingContext
import com.intellij.util.indexing.FileContent
import com.jetbrains.micropython.devices.MicroPythonDeviceProvider
import com.jetbrains.python.PythonFileType
import com.jetbrains.python.psi.PyFile
import com.jetbrains.python.psi.PyFromImportStatement
import com.jetbrains.python.psi.PyImportStatement
/**
* @author Mikhail Golubev
*/
class MicroPythonFacetDetector : FacetBasedFrameworkDetector("MicroPython") {
override fun getFacetType() = MicroPythonFacetType.getInstance()
override fun createSuitableFilePattern() =
FileContentPattern.fileContent().with(object : PatternCondition("Contains MicroPython imports") {
override fun accepts(fileContent: FileContent, context: ProcessingContext?): Boolean {
val fileIndex = ProjectRootManager.getInstance(fileContent.project).fileIndex
if (!fileIndex.isInContent(fileContent.file) || fileIndex.isInLibraryClasses(fileContent.file)) {
return false
}
val detected = MicroPythonDeviceProvider.providers
.asSequence()
.flatMap { it.detectedModuleNames.asSequence() }
.toSet()
return when (val psiFile = fileContent.psiFile) {
is PyFile -> {
return psiFile.importBlock.any { imp ->
when (imp) {
is PyFromImportStatement -> imp.importSourceQName?.firstComponent in detected
is PyImportStatement -> imp.importElements.any { it.importedQName?.firstComponent in detected }
else -> false
}
}
}
else -> false
}
}
})
override fun getFileType(): FileType = PythonFileType.INSTANCE
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/settings/MicroPythonFacetEditorTab.kt
================================================
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.micropython.settings
import com.intellij.facet.ui.FacetEditorTab
import javax.swing.JComponent
/**
* @author vlan
*/
class MicroPythonFacetEditorTab(val configuration: MicroPythonFacetConfiguration,
private val facet: MicroPythonFacet) : FacetEditorTab() {
private val panel: MicroPythonSettingsPanel by lazy {
MicroPythonSettingsPanel(facet.module)
}
override fun isModified(): Boolean = panel.isModified(configuration, facet)
override fun getDisplayName(): String = panel.getDisplayName()
override fun createComponent(): JComponent = panel
override fun apply() {
panel.apply(configuration, facet)
facet.updateLibrary()
}
override fun reset() {
panel.reset(configuration, facet)
}
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/settings/MicroPythonFacetType.kt
================================================
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.micropython.settings
import com.intellij.facet.Facet
import com.intellij.facet.FacetType
import com.intellij.facet.FacetTypeId
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleType
import com.intellij.openapi.util.IconLoader
import com.jetbrains.python.PythonModuleTypeBase
import javax.swing.Icon
/**
* @author vlan
*/
class MicroPythonFacetType : FacetType(ID, STRING_ID, PRESENTABLE_NAME) {
companion object {
const val STRING_ID = "MicroPython"
const val PRESENTABLE_NAME = "MicroPython"
val ID = FacetTypeId(STRING_ID)
val LOGO = IconLoader.getIcon("/icons/micropython.svg", MicroPythonFacetType::class.java)
fun getInstance() = findInstance(MicroPythonFacetType::class.java)!!
}
override fun createDefaultConfiguration() = MicroPythonFacetConfiguration()
override fun createFacet(module: Module, name: String, configuration: MicroPythonFacetConfiguration,
underlyingFacet: Facet<*>?) =
MicroPythonFacet(this, module, name, configuration, underlyingFacet)
override fun isSuitableModuleType(moduleType: ModuleType<*>?) = moduleType is PythonModuleTypeBase
override fun getIcon(): Icon = LOGO
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/settings/MicroPythonModuleConfigurable.kt
================================================
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.micropython.settings
import com.intellij.facet.FacetManager
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.module.Module
import com.intellij.openapi.options.Configurable
import com.intellij.util.ui.UIUtil
import java.awt.BorderLayout
import javax.swing.JCheckBox
import javax.swing.JComponent
import javax.swing.JPanel
/**
* @author vlan
*/
class MicroPythonModuleConfigurable(private val module: Module) : Configurable {
private val panel: MicroPythonSettingsPanel by lazy {
MicroPythonSettingsPanel(module)
}
private val enabledCheckbox by lazy {
val checkBox = JCheckBox("Enable MicroPython support")
checkBox.addActionListener {
update()
}
checkBox
}
override fun isModified(): Boolean {
val facet = module.microPythonFacet
val enabled = facet != null
if (enabledCheckbox.isSelected != enabled) return true
val c = facet?.configuration ?: return false
return panel.isModified(c, facet)
}
override fun getDisplayName() = "MicroPython"
override fun apply() {
val facet = module.microPythonFacet
val application = ApplicationManager.getApplication()
val facetManager = FacetManager.getInstance(module)
if (enabledCheckbox.isSelected) {
if (facet != null) {
panel.apply(facet.configuration, facet)
FacetManager.getInstance(module).facetConfigurationChanged(facet)
facet.updateLibrary()
}
else {
val facetType = MicroPythonFacetType.getInstance()
val newFacet = facetManager.createFacet(facetType, facetType.defaultFacetName, null)
panel.apply(newFacet.configuration, newFacet)
val facetModel = facetManager.createModifiableModel()
facetModel.addFacet(newFacet)
application.runWriteAction { facetModel.commit() }
}
}
else if (facet != null) {
val facetModel = facetManager.createModifiableModel()
facetModel.removeFacet(facet)
application.runWriteAction { facetModel.commit() }
}
}
override fun createComponent(): JComponent {
val mainPanel = JPanel()
with(mainPanel) {
layout = BorderLayout()
add(enabledCheckbox, BorderLayout.NORTH)
add(panel, BorderLayout.CENTER)
}
update()
return mainPanel
}
override fun reset() {
val facet = module.microPythonFacet
val enabled = facet != null
enabledCheckbox.isSelected = enabled
panel.isEnabled = enabled
update()
if (facet != null) {
panel.reset(facet.configuration, facet)
}
}
private fun update() {
UIUtil.setEnabled(panel, enabledCheckbox.isSelected, true)
}
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/settings/MicroPythonProjectConfigurable.kt
================================================
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.micropython.settings
import com.intellij.application.options.ModuleAwareProjectConfigurable
import com.intellij.openapi.module.Module
import com.intellij.openapi.options.Configurable
import com.intellij.openapi.project.Project
/**
* @author vlan
*/
class MicroPythonProjectConfigurable(project: Project)
: ModuleAwareProjectConfigurable(project, "MicroPython", null) {
override fun createModuleConfigurable(module: Module?) = MicroPythonModuleConfigurable(module!!)
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/settings/MicroPythonSettingsPanel.kt
================================================
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.micropython.settings
import com.intellij.ide.BrowserUtil
import com.intellij.openapi.fileChooser.FileChooserDescriptor
import com.intellij.openapi.module.Module
import com.intellij.openapi.ui.ComboBox
import com.intellij.openapi.ui.TextFieldWithBrowseButton
import com.intellij.ui.IdeBorderFactory
import com.intellij.ui.SimpleListCellRenderer
import com.intellij.ui.components.ActionLink
import com.intellij.ui.components.CheckBox
import com.intellij.util.text.nullize
import com.intellij.util.ui.FormBuilder
import com.intellij.util.ui.UIUtil
import com.jetbrains.micropython.devices.MicroPythonDeviceProvider
import java.awt.BorderLayout
import javax.swing.JButton
import javax.swing.JList
import javax.swing.JPanel
/**
* @author vlan
*/
class MicroPythonSettingsPanel(private val module: Module) : JPanel() {
private val deviceTypeCombo = ComboBox(MicroPythonDeviceProvider.providers.toTypedArray())
private var docsHyperlink = object : ActionLink() {
var url = ""
init {
addActionListener {
BrowserUtil.browse(url)
}
}
}
private val devicePath = TextFieldWithBrowseButton()
private val autoDetectDevicePath = CheckBox("Auto-detect device path").apply {
addActionListener {
update()
}
}
private val devicePathPanel: JPanel by lazy {
FormBuilder.createFormBuilder()
.addLabeledComponent("Device path:", JPanel(BorderLayout()).apply {
add(devicePath, BorderLayout.CENTER)
add(JButton("Detect").apply {
addActionListener {
devicePath.text = module.microPythonFacet?.detectDevicePathSynchronously(selectedProvider) ?: ""
}
}, BorderLayout.EAST)
})
.panel
}
init {
layout = BorderLayout()
border = IdeBorderFactory.createEmptyBorder(UIUtil.PANEL_SMALL_INSETS)
val deviceContentPanel = FormBuilder.createFormBuilder()
.addLabeledComponent("Device type:", deviceTypeCombo)
.addComponent(autoDetectDevicePath)
.addComponent(devicePathPanel)
.addComponent(docsHyperlink)
.panel
add(deviceContentPanel, BorderLayout.NORTH)
deviceTypeCombo.apply {
renderer = object: SimpleListCellRenderer() {
override fun customize(list: JList, value: MicroPythonDeviceProvider?,
index: Int, selected: Boolean, hasFocus: Boolean) {
text = value?.presentableName ?: return
}
}
addActionListener {
docsHyperlink.apply {
url = selectedProvider.documentationURL
text = "Learn more about setting up ${selectedProvider.presentableName} devices"
repaint()
}
}
}
devicePath.apply {
val descriptor = FileChooserDescriptor(true, false, false, false, false, false)
addBrowseFolderListener("My Title", null, module.project, descriptor)
}
update()
}
fun isModified(configuration: MicroPythonFacetConfiguration, facet: MicroPythonFacet): Boolean =
deviceTypeCombo.selectedItem != configuration.deviceProvider
|| devicePath.text.nullize(true) != facet.devicePath
|| autoDetectDevicePath.isSelected != facet.autoDetectDevicePath
fun getDisplayName(): String = "MicroPython"
fun apply(configuration: MicroPythonFacetConfiguration, facet: MicroPythonFacet) {
configuration.deviceProvider = selectedProvider
facet.devicePath = devicePath.text.nullize(true)
facet.autoDetectDevicePath = autoDetectDevicePath.isSelected
}
fun reset(configuration: MicroPythonFacetConfiguration, facet: MicroPythonFacet) {
deviceTypeCombo.selectedItem = configuration.deviceProvider
devicePath.text = facet.devicePath ?: ""
autoDetectDevicePath.isSelected = facet.autoDetectDevicePath
update()
}
private fun update() {
UIUtil.setEnabled(devicePathPanel, !autoDetectDevicePath.isSelected, true)
}
private val selectedProvider: MicroPythonDeviceProvider
get() = deviceTypeCombo.selectedItem as MicroPythonDeviceProvider
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/settings/MicroPythonTypeHints.kt
================================================
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.micropython.settings
/**
* @author vlan
*/
data class MicroPythonTypeHints(val paths: List)
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/settings/MicroPythonUsbId.kt
================================================
package com.jetbrains.micropython.settings
/**
* @author vlan
*/
data class MicroPythonUsbId(val vendorId: Int, val productId: Int) {
companion object {
fun parse(vendorAndProductId: String): MicroPythonUsbId {
val ints = vendorAndProductId.split(':').map { Integer.decode(it) }
return MicroPythonUsbId(ints[0], ints[1])
}
}
}
================================================
FILE: src/main/kotlin/com/jetbrains/micropython/ui/MicroPythonToolWindowFactory.kt
================================================
package com.jetbrains.micropython.ui
import com.intellij.openapi.components.service
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.project.Project
import com.intellij.openapi.wm.ToolWindow
import com.intellij.openapi.wm.ToolWindowFactory
import com.intellij.ui.content.ContentFactory
import com.jetbrains.micropython.repl.MicroPythonReplManager
import com.jetbrains.micropython.repl.ToolWindowReplTab
import com.jetbrains.micropython.settings.firstMicroPythonFacet
class MicroPythonToolWindowFactory : ToolWindowFactory, DumbAware {
override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
val contentFactory = ContentFactory.getInstance()
val terminalContent = contentFactory.createContent(null, "REPL", false)
project.firstMicroPythonFacet?.let {
terminalContent.component = ToolWindowReplTab(it.module, terminalContent).createUI()
toolWindow.contentManager.addContent(terminalContent)
project.service().startOrRestartRepl()
}
}
}
================================================
FILE: src/main/resources/META-INF/plugin.xml
================================================
MicroPython
intellij-micropython
See CHANGES.md on GitHub.
]]>
Support for MicroPython devices in PyCharm and IntelliJ.
Features:
- Code completion and docs for some MicroPython-specific modules
- Flash a Python file or directory to a device
- Run REPL on a device
Currently the plugin supports ESP8266, Pyboard, Micro:bit, and Raspberry Pi Pico devices. Your feedback and contributions
are welcome! See the project page on GitHub.
]]>
SNAPSHOT
JetBrains
com.intellij.modules.lang
com.intellij.modules.python
org.jetbrains.plugins.terminal
================================================
FILE: src/main/resources/inspectionDescriptions/MicroPythonRequirements.html
================================================
Detects missing Python packages that are required for communicating with your MicroPython device.
================================================
FILE: typehints/esp32/esp.pyi
================================================
from typing import Optional
from typing import Final
LOG_NONE: Final[int] = ...
LOG_ERROR: Final[int] = ...
LOG_WARN: Final[int] = ...
LOG_INFO: Final[int] = ...
LOG_DEBUG: Final[int] = ...
LOG_VERBOSE: Final[int] = ...
def flash_size():
"""Read the total size of the flash memory."""
...
def flash_user_start():
"""Read the memory offset at which the user flash space begins."""
...
def flash_read(byte_offset, length_or_buffer):
...
def flash_write(byte_offset, bytes):
...
def flash_erase(sector_no):
...
def osdebug(level: Optional[int]):
"""
Turn esp os debugging messages on or off.
The level parameter sets the threshold for the log messages for all esp components. The log levels are defined as constants:
* ``LOG_NONE`` – No log output
* ``LOG_ERROR`` – Critical errors, software module can not recover on its own
* ``LOG_WARN`` – Error conditions from which recovery measures have been taken
* ``LOG_INFO`` – Information messages which describe normal flow of events
* ``LOG_DEBUG`` – Extra information which is not necessary for normal use (values, pointers, sizes, etc)
* ``LOG_VERBOSE`` – Bigger chunks of debugging information, or frequent messages which can potentially flood the output
"""
...
================================================
FILE: typehints/esp32/esp32.pyi
================================================
from machine import Pin
from typing import Optional
from typing import overload
from typing import Final
HEAP_DATA: Final[int] = ...
"""Used in ``idf_heap_info``."""
HEAP_EXEC: Final[int] = ...
"""Used in ``idf_heap_info``."""
WAKEUP_ALL_LOW: Final[int] = ...
"""Selects the wake level for pins."""
WAKEUP_ANY_HIGH: Final[int] = ...
"""Selects the wake level for pins."""
def wake_on_touch(wake: bool):
"""
:param wake: Configure whether or not a touch will wake the device from sleep.
"""
def wake_on_ulp(wake: bool):
"""
:param wake: Configure whether or not the Ultra-Low-Power co-processor can wake the device from sleep.
"""
def wake_on_ext0(pin: Pin, level: Optional[int]):
"""
Configure how EXT0 wakes the device from sleep.
:param pin: None or a valid Pin object.
:param level: ``esp32.WAKEUP_ALL_LOW`` or ``esp32.WAKEUP_ANY_HIGH``.
"""
def wake_on_ext1(pin: Pin, level: Optional[int]):
"""
Configure how EXT1 wakes the device from sleep.
:param pin: None or a valid Pin object.
:param level: ``esp32.WAKEUP_ALL_LOW`` or ``esp32.WAKEUP_ANY_HIGH``.
"""
def gpio_deep_sleep_hold(enable: bool):
"""
:param enable: Whether non-RTC GPIO pin configuration is retained during deep-sleep mode for held pads.
"""
def raw_temperature() -> int:
"""
:return: The raw value of the internal temperature sensor.
"""
def hall_sensor() -> int:
"""
:return: The raw value of the internal Hall sensor.
"""
def idf_heap_info(capabilities: Optional[int]) -> list:
"""
Returns information about the ESP-IDF heap memory regions. One of them contains the MicroPython heap and the others
are used by ESP-IDF, e.g., for network buffers and other data. This data is useful to get a sense of how much
memory is available to ESP-IDF and the networking stack in particular. It may shed some light on situations where
ESP-IDF operations fail due to allocation failures. The information returned is not useful to troubleshoot Python
allocation failures, use ``micropython.mem_info()`` instead.
The capabilities parameter corresponds to ESP-IDF’s ``MALLOC_CAP_XXX`` values but the two most useful ones are
predefined as ``esp32.HEAP_DATA`` for data heap regions and ``esp32.HEAP_EXEC`` for executable regions as used by
the native code emitter.
The return value is a list of 4-tuples, where each 4-tuple corresponds to one heap and contains: the total bytes,
the free bytes, the largest free block, and the minimum free seen over time.
"""
class Partition:
"""
This class gives access to the partitions in the device’s flash memory and includes methods to
enable over-the-air (OTA) updates.
"""
BOOT: Final[str] = ...
"""Used in ``Partition`` constructor - The partition that will be booted at the next reset."""
RUNNING: Final[str] = ...
"""Used in ``Partition`` constructor - The currently running partition."""
TYPE_APP: Final[int] = ...
"""
Used in ``Partition.find``
- for bootable firmware partitions (typically labelled ``factory``, ``ota_0``, ``ota_1``)
"""
TYPE_DATA: Final[int] = ...
"""
Used in Partition.find
- for other partitions, e.g. ``nvs``, ``otadata``, ``phy_init``, ``vfs``.
"""
def __init__(self, id: str, block_size=4096, /):
"""
Create an object representing a partition.
:param id: Can be a string which is the label of the partition to retrieve or one of the
constants: ``BOOT`` or ``RUNNING``.
:param block_size: Specifies the byte size of an individual block.
"""
@classmethod
def find(self, type=TYPE_APP, subtype=0xFF, label=None, block_size=4096) -> list:
"""
Find a partition specified by type, subtype and label.
Note: ``subtype=0xff`` matches any subtype and ``label=None`` matches any label.
:param block_size: Specifies the byte size of an individual block used by the returned objects.
:return: A (possibly empty) list of Partition objects.
"""
def info(self) -> tuple:
"""
:return: A 6-tuple ``(type, subtype, addr, size, label, encrypted)``.
"""
@overload
def readblocks(self, block_num, buf): ...
@overload
def readblocks(self, block_num, buf, offset): ...
@overload
def writeblocks(self, block_num, buf): ...
@overload
def writeblocks(self, block_num, buf, offset): ...
def ioctl(self, cmd, arg):
"""These methods implement the simple and extended block protocol defined by ``os.AbstractBlockDev``."""
def set_boot(self):
"""Sets the partition as the boot partition."""
def get_next_update(self):
"""
Gets the next update partition after this one, and returns a new Partition object.
Typical usage is ``Partition(Partition.RUNNING).get_next_update()``.
:return: The next partition to update given the current running one.
"""
def mark_app_valid_cancel_rollback(self):
"""
Signals that the current boot is considered successful. Calling ``mark_app_valid_cancel_rollback`` is required
on the first boot of a new partition to avoid an automatic rollback at the next boot. This uses the
ESP-IDF “app rollback” feature with “CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE” and an ``OSError(-261)`` is raised
if called on firmware that doesnt have the feature enabled. It is OK to call ``mark_app_valid_cancel_rollback``
on every boot and it is not necessary when booting firmware that was loaded using esptool.
"""
class RMT:
"""
This class provides access to one of the eight RMT channels.
WARNING: The current MicroPython RMT implementation lacks some features, most notably receiving pulses. RMT should
be considered a beta feature and the interface may change in the future.
"""
def __init__(self, channel: int, *, pin=None, clock_div=8, idle_level=False, tx_carrier=None):
"""
:param channel: Identifies which RMT channel (0-7) will be configured.
:param pin: Configures which Pin is bound to the RMT channel
:param clock_div: An 8-bit clock divider that divides the source clock (80MHz) to the RMT channel allowing the
resolution to be specified.
:param idle_level: Specifies what level the output will be when no transmission is in progress
To enable the transmission carrier feature, ``tx_carrier`` should be a tuple of three positive integers: carrier
frequency, duty percent (0 to 100) and the output level to apply the carrier to (a boolean as per idle_level).
"""
def source_freq(self):
"""
:return: The source clock frequency. Currently the source clock is not configurable so this will always
return 80MHz.
"""
def clock_div(self):
"""
:return: The clock divider. Note that the channel resolution is ``1 / (source_freq / clock_div)``.
"""
def wait_done(self, *, timeout=0):
"""
If the timeout keyword argument is given then block for up to this many milliseconds for transmission to
complete.
:return: ``True`` if the channel is idle or ``False`` if a sequence of pulses started with ``RMT.write_pulses``
is being transmitted.
"""
def loop(self, enable_loop: bool):
"""
Configure looping on the channel.
:param enable_loop: ``True`` to enable looping on the next call to ``RMT.write_pulses``. If called with
``False`` while a looping sequence is currently being transmitted then the current loop iteration will be
completed and then transmission will stop.
"""
def write_pulses(self, duration, data=True):
"""
Begin transmitting a sequence. There are three ways to specify this:
Mode 1: duration is a list or tuple of durations. The optional data argument specifies the initial output level.
The output level will toggle after each duration.
Mode 2: duration is a positive integer and data is a list or tuple of output levels.
duration specifies a fixed duration for each.
Mode 3: duration and data are lists or tuples of equal length, specifying individual durations and the output
level for each.
Durations are in integer units of the channel resolution (as described above), between 1 and 32767 units.
Output levels are any value that can be converted to a boolean, with ``True`` representing high voltage and
``False`` representing low.
If transmission of an earlier sequence is in progress then this method will block until that transmission is
complete before beginning the new sequence.
If looping has been enabled with RMT.loop, the sequence will be repeated indefinitely. Further calls to this
method will block until the end of the current loop iteration before immediately beginning to loop the new
sequence of pulses. Looping sequences longer than 126 pulses is not supported by the hardware.
"""
@staticmethod
def bitstream_channel(value: Optional[int]) -> int:
"""
Select which RMT channel is used by the ``machine.bitstream`` implementation.
:param value: Can be None or a valid RMT channel number. The default RMT channel is the highest numbered one.
Passing in None disables the use of RMT and instead selects a bit-banging implementation for
``machine.bitstream``. Passing in no argument will not change the channel. This function returns the current
channel number.
:type value: int
"""
class ULP:
"""This class provides access to the Ultra-Low-Power co-processor."""
def set_wakeup_period(self, period_index: int, period_us):
"""Set the wake-up period."""
def load_binary(self, load_addr, program_binary):
"""Load a program_binary into the ULP at the given load_addr."""
def run(self, entry_point):
"""Start the ULP running at the given entry_point."""
class NVS:
"""
This class gives access to the Non-Volatile storage managed by ESP-IDF. The NVS is partitioned into namespaces
and each namespace contains typed key-value pairs. The keys are strings and the values may be various integer types,
strings, and binary blobs. The driver currently only supports 32-bit signed integers and blobs.
"""
def __init__(self, namespace: str):
"""Create an object providing access to a namespace (which is automatically created if not present)."""
def set_i32(self, key, value):
"""Sets a 32-bit signed integer value for the specified key. Remember to call commit!"""
def get_i32(self, key):
"""
Returns the signed integer value for the specified key. Raises an OSError if the key does not exist or has
a different type.
"""
def set_blob(self, key, value):
"""
Sets a binary blob value for the specified key. The value passed in must support the buffer protocol,
e.g. bytes, bytearray, str. (Note that esp-idf distinguishes blobs and strings, this method always writes a
blob even if a string is passed in as value.) Remember to call commit!
"""
def get_blob(self, key, buffer):
"""
Reads the value of the blob for the specified key into the buffer, which must be a bytearray.
Returns the actual length read. Raises an OSError if the key does not exist, has a different type, or if the
buffer is too small.
"""
def erase_key(self, key):
"""Erases a key-value pair."""
def commit(self):
"""Commits changes made by set_xxx methods to flash."""
================================================
FILE: typehints/esp32/network.pyi
================================================
"""network configuration
This module provides network drivers and routing configuration. To use this
module, a MicroPython variant/build with network capabilities must be installed.
Network drivers for specific hardware are available within this module and are
used to configure hardware network interface(s). Network services provided
by configured interfaces are then available for use via the :mod:`usocket`
module.
For example::
# connect/ show IP config a specific network interface
# see below for examples of specific drivers
import network
import utime
nic = network.Driver(...)
if not nic.isconnected():
nic.connect()
print("Waiting for connection...")
while not nic.isconnected():
utime.sleep(1)
print(nic.ifconfig())
# now use usocket as usual
import usocket as socket
addr = socket.getaddrinfo('micropython.org', 80)[0][-1]
s = socket.socket()
s.connect(addr)
s.send(b'GET / HTTP/1.1\r\nHost: micropython.org\r\n\r\n')
data = s.recv(1000)
s.close()
"""
from typing import overload, Optional, List, Tuple, Union, Any, Final
STA_IF: Final[int] = ...
AP_IF: Final[int] = ...
@overload
def phy_mode() -> int:
"""Get the PHY mode."""
...
@overload
def phy_mode(mode: int) -> None:
"""Set the PHY mode.
The possible modes are defined as constants:
* ``MODE_11B`` -- IEEE 802.11b,
* ``MODE_11G`` -- IEEE 802.11g,
* ``MODE_11N`` -- IEEE 802.11n.
"""
...
class WLAN:
def __init__(self, interface_id: int) -> None:
"""Create a WLAN network interface object. Supported interfaces are
``network.STA_IF`` (station aka client, connects to upstream WiFi access
points) and ``network.AP_IF`` (access point, allows other WiFi clients to
connect). Availability of the methods below depends on interface type.
For example, only STA interface may `connect()` to an access point.
"""
...
@overload
def active(self) -> bool:
"""Query current state of the interface."""
...
@overload
def active(self, is_active: bool) -> None:
"""Activate ("up") or deactivate ("down") network interface."""
...
def connect(self, ssid: Optional[Union[bytes, str]] = None,
password: Optional[Union[bytes, str]] = None, *,
bssid: Optional[Union[bytes, str]] = None) -> None:
"""Connect to the specified wireless network, using the specified password.
If *bssid* is given then the connection will be restricted to the
access-point with that MAC address (the *ssid* must also be specified
in this case).
"""
...
def disconnect(self) -> None:
"""Disconnect from the currently connected wireless network."""
...
def scan(self) -> List[Tuple[bytes, bytes, int, int, int, int]]:
"""Scan for the available wireless networks.
Scanning is only possible on STA interface. Returns list of tuples with
the information about WiFi access points:
(ssid, bssid, channel, RSSI, authmode, hidden)
*bssid* is hardware address of an access point, in binary form, returned as
bytes object. You can use `ubinascii.hexlify()` to convert it to ASCII form.
There are five values for authmode:
* 0 -- open
* 1 -- WEP
* 2 -- WPA-PSK
* 3 -- WPA2-PSK
* 4 -- WPA/WPA2-PSK
and two for hidden:
* 0 -- visible
* 1 -- hidden
"""
...
def status(self) -> int:
"""Return the current status of the wireless connection.
The possible statuses are defined as constants:
* ``STAT_IDLE`` -- no connection and no activity,
* ``STAT_CONNECTING`` -- connecting in progress,
* ``STAT_WRONG_PASSWORD`` -- failed due to incorrect password,
* ``STAT_NO_AP_FOUND`` -- failed because no access point replied,
* ``STAT_CONNECT_FAIL`` -- failed due to other problems,
* ``STAT_GOT_IP`` -- connection successful.
"""
...
def isconnected(self) -> bool:
"""In case of STA mode, returns ``True`` if connected to a WiFi access
point and has a valid IP address. In AP mode returns ``True`` when a
station is connected. Returns ``False`` otherwise.
"""
...
@overload
def ifconfig(self) -> Tuple[str, str, str, str]:
"""Get IP-level network interface parameters: IP address, subnet mask,
gateway and DNS server.
"""
...
@overload
def ifconfig(self, ip: str, subnet: str, gateway: str, dns: str) -> None:
"""Get/set IP-level network interface parameters: IP address, subnet mask,
gateway and DNS server.
"""
...
@overload
def config(self, param: str) -> Any:
"""Get general network interface parameters."""
...
@overload
def config(self, **kwargs: Any) -> None:
"""Get or set general network interface parameters. These methods allow to work
with additional parameters beyond standard IP configuration (as dealt with by
`wlan.ifconfig()`). These include network-specific and hardware-specific
parameters. For setting parameters, keyword argument syntax should be used,
multiple parameters can be set at once. For querying, parameters name should
be quoted as a string, and only one parameter can be queries at time::
# Set WiFi access point name (formally known as ESSID) and WiFi channel
ap.config(essid='My AP', channel=11)
# Query params one by one
print(ap.config('essid'))
print(ap.config('channel'))
Following are commonly supported parameters (availability of a specific parameter
depends on network technology type, driver, and `MicroPython port`).
============= ===========
Parameter Description
============= ===========
mac MAC address (bytes)
essid WiFi access point name (string)
channel WiFi channel (integer)
hidden Whether ESSID is hidden (boolean)
authmode Authentication mode supported (enumeration, see module constants)
password Access password (string)
dhcp_hostname The DHCP hostname to use
============= ===========
"""
...
STA_IF: int
AP_IF: int
STAT_IDLE: int
STAT_CONNECTING: int
STAT_WRONG_PASSWORD: int
STAT_NO_AP_FOUND: int
STAT_CONNECT_FAIL: int
STAT_GOT_IP: int
MODE_11B: int
MODE_11G: int
MODE_11N: int
================================================
FILE: typehints/esp8266/esp.pyi
================================================
from typing import Optional
def sleep_type(sleep_type: Optional[int]) -> Optional[int]:
"""
Get or set the sleep type.
If the sleep_type parameter is provided, sets the sleep type to its value.
If the function is called without parameters, returns the current sleep type.
The possible sleep types are defined as constants:
* ``SLEEP_NONE`` – all functions enabled,\n
* ``SLEEP_MODEM`` – modem sleep, shuts down the WiFi Modem circuit.\n
* ``SLEEP_LIGHT`` – light sleep, shuts down the WiFi Modem circuit and suspends the processor periodically.\n
The system enters the set sleep mode automatically when possible.
:param sleep_type: Sleep type.
:type sleep_type: int
:return: Current sleep type
:rtype: int
"""
def deepsleep(time: int = 0) -> None:
"""
Enter deep sleep.
The whole module powers down, except for the RTC clock circuit, which can
be used to restart the module after the specified time if the pin 16 is
connected to the reset pin. Otherwise the module will sleep until manually reset.
:param time: Amount of time in milliseconds to sleep.
"""
def set_native_code_location(start: Optional[int], length: Optional[int]) -> None:
"""
Set the location that native code will be placed for execution after it is
compiled. Native code is emitted when the ``@micropython.native``, ``@micropython.viper``
and ``@micropython.asm_xtensa`` decorators are applied to a function. The
ESP8266 must execute code from either iRAM or the lower 1MByte of flash
(which is memory mapped), and this function controls the location.
If start and length are both **None** then the native code location is
set to the unused portion of memory at the end of the iRAM1 region. The
size of this unused portion depends on the firmware and is typically
quite small (around 500 bytes), and is enough to store a few very small
functions. The advantage of using this iRAM1 region is that it does not
get worn out by writing to it.
If neither start nor length are None then they should be integers. start
should specify the byte offset from the beginning of the flash at which
native code should be stored. length specifies how many bytes of flash
from start can be used to store native code. start and length should be
multiples of the sector size (being 4096 bytes). The flash will be
automatically erased before writing to it so be sure to use a region of
flash that is not otherwise used, for example by the firmware or the filesystem.
When using the flash to store native code *start*+*length* must be less
than or equal to 1MByte. Note that the flash can be worn out if repeated
erasures (and writes) are made so use this feature sparingly. In particular,
native code needs to be recompiled and rewritten to flash on each boot
(including wake from deepsleep).
In both cases above, using iRAM1 or flash, if there is no more room left in
the specified region then the use of a native decorator on a function will
lead to ``MemoryError`` exception being raised during compilation of that function.
:param start: Start of native code region.
:param length: End of native code region.
"""
================================================
FILE: typehints/esp8266/network.pyi
================================================
"""network configuration
This module provides network drivers and routing configuration. To use this
module, a MicroPython variant/build with network capabilities must be installed.
Network drivers for specific hardware are available within this module and are
used to configure hardware network interface(s). Network services provided
by configured interfaces are then available for use via the :mod:`usocket`
module.
For example::
# connect/ show IP config a specific network interface
# see below for examples of specific drivers
import network
import utime
nic = network.Driver(...)
if not nic.isconnected():
nic.connect()
print("Waiting for connection...")
while not nic.isconnected():
utime.sleep(1)
print(nic.ifconfig())
# now use usocket as usual
import usocket as socket
addr = socket.getaddrinfo('micropython.org', 80)[0][-1]
s = socket.socket()
s.connect(addr)
s.send(b'GET / HTTP/1.1\r\nHost: micropython.org\r\n\r\n')
data = s.recv(1000)
s.close()
"""
from typing import overload, Optional, List, Tuple, Union, Any, Final
STA_IF: Final[int] = ...
AP_IF: Final[int] = ...
@overload
def phy_mode() -> int:
"""Get the PHY mode."""
...
@overload
def phy_mode(mode: int) -> None:
"""Set the PHY mode.
The possible modes are defined as constants:
* ``MODE_11B`` -- IEEE 802.11b,
* ``MODE_11G`` -- IEEE 802.11g,
* ``MODE_11N`` -- IEEE 802.11n.
"""
...
class WLAN:
def __init__(self, interface_id: int) -> None:
"""Create a WLAN network interface object. Supported interfaces are
``network.STA_IF`` (station aka client, connects to upstream WiFi access
points) and ``network.AP_IF`` (access point, allows other WiFi clients to
connect). Availability of the methods below depends on interface type.
For example, only STA interface may `connect()` to an access point.
"""
...
@overload
def active(self) -> bool:
"""Query current state of the interface."""
...
@overload
def active(self, is_active: bool) -> None:
"""Activate ("up") or deactivate ("down") network interface."""
...
def connect(self, ssid: Optional[Union[bytes, str]] = None,
password: Optional[Union[bytes, str]] = None, *,
bssid: Optional[Union[bytes, str]] = None) -> None:
"""Connect to the specified wireless network, using the specified password.
If *bssid* is given then the connection will be restricted to the
access-point with that MAC address (the *ssid* must also be specified
in this case).
"""
...
def disconnect(self) -> None:
"""Disconnect from the currently connected wireless network."""
...
def scan(self) -> List[Tuple[bytes, bytes, int, int, int, int]]:
"""Scan for the available wireless networks.
Scanning is only possible on STA interface. Returns list of tuples with
the information about WiFi access points:
(ssid, bssid, channel, RSSI, authmode, hidden)
*bssid* is hardware address of an access point, in binary form, returned as
bytes object. You can use `ubinascii.hexlify()` to convert it to ASCII form.
There are five values for authmode:
* 0 -- open
* 1 -- WEP
* 2 -- WPA-PSK
* 3 -- WPA2-PSK
* 4 -- WPA/WPA2-PSK
and two for hidden:
* 0 -- visible
* 1 -- hidden
"""
...
def status(self) -> int:
"""Return the current status of the wireless connection.
The possible statuses are defined as constants:
* ``STAT_IDLE`` -- no connection and no activity,
* ``STAT_CONNECTING`` -- connecting in progress,
* ``STAT_WRONG_PASSWORD`` -- failed due to incorrect password,
* ``STAT_NO_AP_FOUND`` -- failed because no access point replied,
* ``STAT_CONNECT_FAIL`` -- failed due to other problems,
* ``STAT_GOT_IP`` -- connection successful.
"""
...
def isconnected(self) -> bool:
"""In case of STA mode, returns ``True`` if connected to a WiFi access
point and has a valid IP address. In AP mode returns ``True`` when a
station is connected. Returns ``False`` otherwise.
"""
...
@overload
def ifconfig(self) -> Tuple[str, str, str, str]:
"""Get IP-level network interface parameters: IP address, subnet mask,
gateway and DNS server.
"""
...
@overload
def ifconfig(self, ip: str, subnet: str, gateway: str, dns: str) -> None:
"""Get/set IP-level network interface parameters: IP address, subnet mask,
gateway and DNS server.
"""
...
@overload
def config(self, param: str) -> Any:
"""Get general network interface parameters."""
...
@overload
def config(self, **kwargs: Any) -> None:
"""Get or set general network interface parameters. These methods allow to work
with additional parameters beyond standard IP configuration (as dealt with by
`wlan.ifconfig()`). These include network-specific and hardware-specific
parameters. For setting parameters, keyword argument syntax should be used,
multiple parameters can be set at once. For querying, parameters name should
be quoted as a string, and only one parameter can be queries at time::
# Set WiFi access point name (formally known as ESSID) and WiFi channel
ap.config(essid='My AP', channel=11)
# Query params one by one
print(ap.config('essid'))
print(ap.config('channel'))
Following are commonly supported parameters (availability of a specific parameter
depends on network technology type, driver, and `MicroPython port`).
============= ===========
Parameter Description
============= ===========
mac MAC address (bytes)
essid WiFi access point name (string)
channel WiFi channel (integer)
hidden Whether ESSID is hidden (boolean)
authmode Authentication mode supported (enumeration, see module constants)
password Access password (string)
dhcp_hostname The DHCP hostname to use
============= ===========
"""
...
STA_IF: int
AP_IF: int
STAT_IDLE: int
STAT_CONNECTING: int
STAT_WRONG_PASSWORD: int
STAT_NO_AP_FOUND: int
STAT_CONNECT_FAIL: int
STAT_GOT_IP: int
MODE_11B: int
MODE_11G: int
MODE_11N: int
================================================
FILE: typehints/microbit/microbit/__init__.pyi
================================================
"""micro:bit Micropython API
Everything directly related to interacting with the hardware lives in the
`microbit` module. For ease of use it's recommended you start all scripts
with::
from microbit import *
The following documentation assumes you have done this.
There are a few functions available directly::
# sleep for the given number of milliseconds.
sleep(ms)
# returns the number of milliseconds since the micro:bit was last switched on.
running_time()
# makes the micro:bit enter panic mode (this usually happens when the DAL runs
# out of memory, and causes a sad face to be drawn on the display). The error
# code can be any arbitrary integer value.
panic(error_code)
# resets the micro:bit.
reset()
The rest of the functionality is provided by objects and classes in the
microbit module, as described below.
Note that the API exposes integers only (ie no floats are needed, but they may
be accepted). We thus use milliseconds for the standard time unit.
"""
from . import (display as display, uart as uart, spi as spi, i2c as i2c,
accelerometer as accelerometer, compass as compass)
from typing import Any, List, overload
def panic(n: int) -> None:
"""Enter a panic mode. Requires restart. Pass in an arbitrary integer <= 255
to indicate a status::
microbit.panic(255)
"""
def reset() -> None:
"""Restart the board."""
def sleep(n: int) -> None:
"""Wait for ``n`` milliseconds. One second is 1000 milliseconds, so::
microbit.sleep(1000)
will pause the execution for one second. ``n`` can be an integer or
a floating point number.
"""
def running_time() -> int:
"""Return the number of milliseconds since the board was switched on or
restarted.
"""
def temperature() -> int:
"""Return the temperature of the micro:bit in degrees Celcius."""
class Button:
"""Represents a button.
.. note::
This class is not actually available to the user, it is only used by
the two button instances, which are provided already initialized.
"""
def is_pressed(self) -> bool:
"""Returns ``True`` if the specified button ``button`` is pressed, and
``False`` otherwise.
"""
def was_pressed(self) -> bool:
"""Returns ``True`` or ``False`` to indicate if the button was pressed
since the device started or the last time this method was called.
"""
def get_presses(self) -> int:
"""Returns the running total of button presses, and resets this total
to zero before returning.
"""
button_a: Button
"""A ``Button`` instance (see below) representing the left button."""
button_b: Button
"""Represents the right button."""
class MicroBitDigitalPin:
"""
The pull mode for a pin is automatically configured when the pin changes to an
input mode. Input modes are when you call ``read_analog`` / ``read_digital`` /
``is_touched``. The pull mode for these is, respectively, ``NO_PULL``,
``PULL_DOWN``, ``PULL_UP``. Only when in ``read_digital`` mode can you call
``set_pull`` to change the pull mode from the default.
"""
NO_PULL: int = 0
PULL_UP: int = 1
PULL_DOWN: int = 2
def read_digital(self) -> int:
"""Return 1 if the pin is high, and 0 if it's low."""
def set_pull(self, value: int = (NO_PULL or PULL_UP or PULL_DOWN)) -> None:
"""Set the pull state to one of three possible values: ``pin.PULL_UP``,
``pin.PULL_DOWN`` or ``pin.NO_PULL`` (where ``pin`` is an instance of
a pin). See below for discussion of default pull states.
"""
def write_digital(self, value: int) -> None:
"""Set the pin to high if ``value`` is 1, or to low, if it is 0."""
def write_analog(self, value: int) -> None:
"""Output a PWM signal on the pin, with the duty cycle proportional to
the provided ``value``. The ``value`` may be either an integer or a
floating point number between 0 (0% duty cycle) and 1023 (100% duty).
"""
def set_analog_period(self, period: int) -> None:
"""Set the period of the PWM signal being output to ``period`` in
milliseconds. The minimum valid value is 1ms.
"""
def set_analog_period_microseconds(self, period: int) -> None:
"""Set the period of the PWM signal being output to ``period`` in
microseconds. The minimum valid value is 35µs.
"""
class MicroBitAnalogDigitalPin(MicroBitDigitalPin):
def read_analog(self) -> int:
"""Read the voltage applied to the pin, and return it as an integer
between 0 (meaning 0V) and 1023 (meaning 3.3V).
"""
class MicroBitTouchPin(MicroBitAnalogDigitalPin):
def is_touched(self) -> bool:
"""Return ``True`` if the pin is being touched with a finger, otherwise
return ``False``.
This test is done by measuring the capacitance of the pin together with
whatever is connected to it. Human body has quite a large capacitance,
so touching the pin gives a dramatic change in reading, which can be
detected.
"""
pin0: MicroBitTouchPin
"""Pad 0."""
pin1: MicroBitTouchPin
"""Pad 1."""
pin2: MicroBitTouchPin
"""Pad 2."""
pin3: MicroBitAnalogDigitalPin
"""Column 1."""
pin4: MicroBitAnalogDigitalPin
"""Column 2."""
pin5: MicroBitDigitalPin
"""Button A."""
pin6: MicroBitDigitalPin
"""Row 2."""
pin7: MicroBitDigitalPin
"""Row 1."""
pin8: MicroBitDigitalPin
pin9: MicroBitDigitalPin
"""Row 3."""
pin10: MicroBitAnalogDigitalPin
"""Column 3."""
pin11: MicroBitDigitalPin
"""Button B."""
pin12: MicroBitDigitalPin
pin13: MicroBitDigitalPin
"""SPI MOSI."""
pin14: MicroBitDigitalPin
"""SPI MISO."""
pin15: MicroBitDigitalPin
"""SPI SCK."""
pin16: MicroBitDigitalPin
pin19: MicroBitDigitalPin
"""I2C SCL."""
pin20: MicroBitDigitalPin
"""I2C SDA."""
class Image:
"""The ``Image`` class is used to create images that can be displayed
easily on the device's LED matrix. Given an image object it's possible to
display it via the ``display`` API::
display.show(Image.HAPPY)
"""
HEART: Image
HEART_SMALL: Image
HAPPY: Image
SMILE: Image
SAD: Image
CONFUSED: Image
ANGRY: Image
ASLEEP: Image
SURPRISED: Image
SILLY: Image
FABULOUS: Image
MEH: Image
YES: Image
NO: Image
CLOCK12: Image
CLOCK11: Image
CLOCK10: Image
CLOCK9: Image
CLOCK8: Image
CLOCK7: Image
CLOCK6: Image
CLOCK5: Image
CLOCK4: Image
CLOCK3: Image
CLOCK2: Image
CLOCK1: Image
ARROW_N: Image
ARROW_NE: Image
ARROW_E: Image
ARROW_SE: Image
ARROW_S: Image
ARROW_SW: Image
ARROW_W: Image
ARROW_NW: Image
TRIANGLE: Image
TRIANGLE_LEFT: Image
CHESSBOARD: Image
DIAMOND: Image
DIAMOND_SMALL: Image
SQUARE: Image
SQUARE_SMALL: Image
RABBIT: Image
COW: Image
MUSIC_CROTCHET: Image
MUSIC_QUAVER: Image
MUSIC_QUAVERS: Image
PITCHFORK: Image
XMAS: Image
PACMAN: Image
TARGET: Image
TSHIRT: Image
ROLLERSKATE: Image
DUCK: Image
HOUSE: Image
TORTOISE: Image
BUTTERFLY: Image
STICKFIGURE: Image
GHOST: Image
SWORD: Image
GIRAFFE: Image
SKULL: Image
UMBRELLA: Image
SNAKE: Image
ALL_CLOCKS: List[Image]
ALL_ARROWS: List[Image]
@overload
def __init__(self, string: str) -> None:
"""``string`` has to consist of digits 0-9 arranged into lines,
describing the image, for example::
image = Image("90009:"
"09090:"
"00900:"
"09090:"
"90009")
will create a 5×5 image of an X. The end of a line is indicated by a
colon. It's also possible to use a newline (\n) to indicate the end of
a line like this::
image = Image("90009\n"
"09090\n"
"00900\n"
"09090\n"
"90009")
"""
@overload
def __init__(self, width: int = None, height: int = None,
buffer: Any = None) -> None:
"""Create an empty image with ``width`` columns and ``height`` rows.
Optionally ``buffer`` can be an array of ``width``×``height`` integers
in range 0-9 to initialize the image.
"""
def width(self) -> int:
"""Return the number of columns in the image."""
def height(self) -> int:
"""Return the numbers of rows in the image."""
def set_pixel(self, x: int, y: int, value: int) -> None:
"""Set the brightness of the pixel at column ``x`` and row ``y`` to the
``value``, which has to be between 0 (dark) and 9 (bright).
This method will raise an exception when called on any of the built-in
read-only images, like ``Image.HEART``.
"""
def get_pixel(self, x: int, y: int) -> int:
"""Return the brightness of pixel at column ``x`` and row ``y`` as an
integer between 0 and 9.
"""
def shift_left(self, n: int) -> Image:
"""Return a new image created by shifting the picture left by ``n``
columns.
"""
def shift_right(self, n: int) -> Image:
"""Same as ``image.shift_left(-n)``."""
def shift_up(self, n: int) -> Image:
"""Return a new image created by shifting the picture up by ``n``
rows.
"""
def shift_down(self, n: int) -> Image:
"""Same as ``image.shift_up(-n)``."""
def crop(self, x: int, y: int, w: int, h: int) -> Image:
"""Return a new image by cropping the picture to a width of ``w`` and a
height of ``h``, starting with the pixel at column ``x`` and row
``y``.
"""
def copy(self) -> Image:
"""Return an exact copy of the image."""
def invert(self) -> Image:
"""Return a new image by inverting the brightness of the pixels in the
source image."""
def fill(self, value: int) -> None:
"""Set the brightness of all the pixels in the image to the
``value``, which has to be between 0 (dark) and 9 (bright).
This method will raise an exception when called on any of the built-in
read-only images, like ``Image.HEART``.
"""
def blit(self, src: Image, x: int, y: int, w: int, h: int, xdest: int = 0,
ydest: int = 0) -> None:
"""Copy the rectangle defined by ``x``, ``y``, ``w``, ``h`` from the
image ``src`` into this image at ``xdest``, ``ydest``. Areas in the
source rectangle, but outside the source image are treated as having a
value of 0.
``shift_left()``, ``shift_right()``, ``shift_up()``, ``shift_down()``
and ``crop()`` can are all implemented by using ``blit()``.
For example, img.crop(x, y, w, h) can be implemented as::
def crop(self, x, y, w, h):
res = Image(w, h)
res.blit(self, x, y, w, h)
return res
"""
def __repr__(self) -> str:
"""Get a compact string representation of the image."""
def __str__(self) -> str:
"""Get a readable string representation of the image."""
def __add__(self, other: Image) -> Image:
"""Create a new image by adding the brightness values from the two
images for each pixel.
"""
def __mul__(self, n: float) -> Image:
"""Create a new image by multiplying the brightness of each pixel by
``n``.
"""
================================================
FILE: typehints/microbit/microbit/accelerometer.pyi
================================================
"""This object gives you access to the on-board accelerometer. The accelerometer
also provides convenience functions for detecting gestures. The
recognised gestures are: ``up``, ``down``, ``left``, ``right``, ``face up``,
``face down``, ``freefall``, ``3g``, ``6g``, ``8g``, ``shake``.
"""
from typing import Tuple
def get_x() -> int:
"""Get the acceleration measurement in the ``x`` axis, as a positive or
negative integer, depending on the direction.
"""
def get_y() -> int:
"""Get the acceleration measurement in the ``y`` axis, as a positive or
negative integer, depending on the direction.
"""
def get_z() -> int:
"""Get the acceleration measurement in the ``z`` axis, as a positive or
negative integer, depending on the direction.
"""
def get_values() -> Tuple[int, int, int]:
"""Get the acceleration measurements in all axes at once, as a three-element
tuple of integers ordered as X, Y, Z.
"""
def current_gesture() -> str:
"""Return the name of the current gesture.
.. note::
MicroPython understands the following gesture names: ``"up"``, ``"down"``,
``"left"``, ``"right"``, ``"face up"``, ``"face down"``, ``"freefall"``,
``"3g"``, ``"6g"``, ``"8g"``, ``"shake"``. Gestures are always
represented as strings."""
def is_gesture(name: str) -> bool:
"""Return True or False to indicate if the named gesture is currently
active."""
def was_gesture(name: str) -> bool:
"""Return True or False to indicate if the named gesture was active since the
last call.
"""
def get_gestures() -> Tuple[str, ...]:
"""Return a tuple of the gesture history. The most recent is listed last.
Also clears the gesture history before returning.
"""
================================================
FILE: typehints/microbit/microbit/compass.pyi
================================================
"""This module lets you access the built-in electronic compass. Before using,
the compass should be calibrated, otherwise the readings may be wrong.
.. warning::
Calibrating the compass will cause your program to pause until calibration
is complete. Calibration consists of a little game to draw a circle on the
LED display by rotating the device.
"""
def calibrate() -> None:
"""Starts the calibration process. An instructive message will be scrolled
to the user after which they will need to rotate the device in order to
draw a circle on the LED display.
"""
def is_calibrated() -> bool:
"""Returns ``True`` if the compass has been successfully calibrated, and
returns ``False`` otherwise.
"""
def clear_calibration() -> None:
"""Undoes the calibration, making the compass uncalibrated again."""
def get_x() -> int:
"""Gives the reading of the magnetic force on the ``x`` axis, as a
positive or negative integer, depending on the direction of the
force.
"""
def get_y() -> int:
"""Gives the reading of the magnetic force on the ``x`` axis, as a
positive or negative integer, depending on the direction of the
force.
"""
def get_z() -> int:
"""Gives the reading of the magnetic force on the ``x`` axis, as a
positive or negative integer, depending on the direction of the
force.
"""
def heading() -> int:
"""Gives the compass heading, calculated from the above readings, as an
integer in the range from 0 to 360, representing the angle in degrees,
clockwise, with north as 0.
If the compass has not been calibrated, then this will call ``calibrate``.
"""
def get_field_strength() -> int:
"""Returns an integer indication of the magnitude of the magnetic field
around the device."""
================================================
FILE: typehints/microbit/microbit/display.pyi
================================================
"""This module controls the 5×5 LED display on the front of your board. It can
be used to display images, animations and even text.
To continuously scroll a string across the display, and do it in the background,
you can use::
import microbit
microbit.display.scroll('Hello!', wait=False, loop=True)
"""
from . import Image
from typing import overload, Iterable
def get_pixel(x: int, y: int) -> int:
"""Return the brightness of the LED at column ``x`` and row ``y`` as an
integer between 0 (off) and 9 (bright).
"""
def set_pixel(x: int, y: int, value: int) -> None:
"""Set the brightness of the LED at column ``x`` and row ``y`` to ``value``,
which has to be an integer between 0 and 9.
"""
def clear() -> None:
"""Set the brightness of all LEDs to 0 (off)."""
@overload
def show(image: Image) -> None:
"""Display the ``image``."""
@overload
def show(iterable: Iterable[Image, str], delay: int = 400, *,
wait: bool = True, loop: bool =False, clear: bool = False) -> None:
"""Display images or letters from the ``iterable`` in sequence, with
``delay`` milliseconds between them.
If ``wait`` is ``True``, this function will block until the animation is
finished, otherwise the animation will happen in the background.
If ``loop`` is ``True``, the animation will repeat forever.
If ``clear`` is ``True``, the display will be cleared after the iterable
has finished.
Note that the ``wait``, ``loop`` and ``clear`` arguments must be specified
using their keyword.
.. note::
If using a generator as the ``iterable``, then take care not to
allocate any memory in the generator as allocating memory in an
interrupt is prohibited and will raise a ``MemoryError``.
"""
def scroll(string: str, delay: int = 150, *, wait: bool = True,
loop: bool = False, monospace: bool = False) -> None:
"""Similar to ``show``, but scrolls the ``string`` horizontally instead. The
``delay`` parameter controls how fast the text is scrolling.
If ``wait`` is ``True``, this function will block until the animation is
finished, otherwise the animation will happen in the background.
If ``loop`` is ``True``, the animation will repeat forever.
If ``monospace`` is ``True``, the characters will all take up 5 pixel-columns
in width, otherwise there will be exactly 1 blank pixel-column between each
character as they scroll.
Note that the ``wait``, ``loop`` and ``monospace`` arguments must be specified
using their keyword.
"""
def on() -> None:
"""Use on() to turn on the display."""
def off() -> None:
"""Use off() to turn off the display (thus allowing you to re-use the GPIO
pins associated with the display for other purposes).
"""
def is_on() -> bool:
"""Returns ``True`` if the display is on, otherwise returns ``False``."""
================================================
FILE: typehints/microbit/microbit/i2c.pyi
================================================
"""The ``i2c`` module lets you communicate with devices connected to your board
using the I²C bus protocol. There can be multiple slave devices connected at
the same time, and each one has its own unique address, that is either fixed
for the device or configured on it. Your board acts as the I²C master.
We use 7-bit addressing for devices because of the reasons stated
`here `_.
This may be different to other micro:bit related solutions.
How exactly you should communicate with the devices, that is, what bytes to
send and how to interpret the responses, depends on the device in question and
should be described separately in that device's documentation.
You should connect the device's ``SCL`` pin to micro:bit pin 19, and the
device's ``SDA`` pin to micro:bit pin 20. You also must connect the device's
ground to the micro:bit ground (pin ``GND``). You may need to power the device
using an external power supply or the micro:bit.
There are internal pull-up resistors on the I²C lines of the board, but with
particularly long wires or large number of devices you may need to add
additional pull-up resistors, to ensure noise-free communication.
"""
from . import pin19, pin20
from typing import Union
from . import pin19, pin20
def init(freq: int = 100000, sda: int = pin20, scl: int = pin19) -> None:
"""Re-initialize peripheral with the specified clock frequency ``freq`` on the
specified ``sda`` and ``scl`` pins.
.. warning::
Changing the I²C pins from defaults will make the accelerometer and
compass stop working, as they are connected internally to those pins.
"""
def read(addr: int, n: int, repeat: bool = False) -> bytes:
"""Read ``n`` bytes from the device with 7-bit address ``addr``. If ``repeat``
is ``True``, no stop bit will be sent.
"""
def write(addr: int, buf: Union[bytes, bytearray], repeat=False) -> None:
"""Write bytes from ``buf`` to the device with 7-bit address ``addr``. If
``repeat`` is ``True``, no stop bit will be sent.
"""
================================================
FILE: typehints/microbit/microbit/spi.pyi
================================================
"""The ``spi`` module lets you talk to a device connected to your board using
a serial peripheral interface (SPI) bus. SPI uses a so-called master-slave
architecture with a single master. You will need to specify the connections
for three signals:
* SCLK : Serial Clock (output from master).
* MOSI : Master Output, Slave Input (output from master).
* MISO : Master Input, Slave Output (output from slave).
"""
from . import pin13, pin14, pin15, MicroBitDigitalPin
from typing import Union
def init(baudrate: int = 1000000, bits: int = 8, mode: int = 0,
sclk: MicroBitDigitalPin = pin13,
mosi: MicroBitDigitalPin = pin15,
miso: MicroBitDigitalPin = pin14) -> None:
"""Initialize SPI communication with the specified parameters on the
specified ``pins``. Note that for correct communication, the parameters
have to be the same on both communicating devices.
The ``baudrate`` defines the speed of communication.
The ``bits`` defines the size of bytes being transmitted. Currently only
``bits=8`` is supported. However, this may change in the future.
The ``mode`` determines the combination of clock polarity and phase
according to the following convention, with polarity as the high order bit
and phase as the low order bit:
+----------+-----------------+--------------+
| SPI Mode | Polarity (CPOL) | Phase (CPHA) |
+==========+=================+==============+
| 0 | 0 | 0 |
+----------+-----------------+--------------+
| 1 | 0 | 1 |
+----------+-----------------+--------------+
| 2 | 1 | 0 |
+----------+-----------------+--------------+
| 3 | 1 | 1 |
+----------+-----------------+--------------+
Polarity (aka CPOL) 0 means that the clock is at logic value 0 when idle
and goes high (logic value 1) when active; polarity 1 means the clock is
at logic value 1 when idle and goes low (logic value 0) when active. Phase
(aka CPHA) 0 means that data is sampled on the leading edge of the clock,
and 1 means on the trailing edge
(viz. https://en.wikipedia.org/wiki/Signal_edge).
The ``sclk``, ``mosi`` and ``miso`` arguments specify the pins to use for
each type of signal.
"""
def read(nbytes: int) -> bytes:
"""Read at most ``nbytes``. Returns what was read."""
def write(buffer: Union[bytes, bytearray]) -> None:
"""Write the ``buffer`` of bytes to the bus."""
def write_readinto(out: Union[bytes, bytearray], in_: bytearray) -> None:
"""Write the ``out`` buffer to the bus and read any response into the ``in``
buffer. The length of the buffers should be the same. The buffers can be
the same object."""
================================================
FILE: typehints/microbit/microbit/uart.pyi
================================================
"""The ``uart`` module lets you talk to a device connected to your board using
a serial interface.
"""
from . import MicroBitDigitalPin
from typing import Optional, Union
def init(baudrate: int = 9600, bits: int = 8, parity: int = None,
stop: int = 1, *, tx: MicroBitDigitalPin = None,
rx: MicroBitDigitalPin = None) -> None:
"""Initialize serial communication with the specified parameters on the
specified ``tx`` and ``rx`` pins. Note that for correct communication, the
parameters have to be the same on both communicating devices.
.. warning::
Initializing the UART on external pins will cause the Python console on
USB to become unaccessible, as it uses the same hardware. To bring the
console back you must reinitialize the UART without passing anything for
``tx'' or ``rx'' (or passing ``None'' to these arguments). This means
that calling ``uart.init(115200)'' is enough to restore the Python console.
The ``baudrate`` defines the speed of communication. Common baud
rates include:
* 9600
* 14400
* 19200
* 28800
* 38400
* 57600
* 115200
The ``bits`` defines the size of bytes being transmitted, and the board
only supports 8. The ``parity`` parameter defines how parity is checked,
and it can be ``None``, ``microbit.uart.ODD`` or ``microbit.uart.EVEN``.
The ``stop`` parameter tells the number of stop bits, and has to be 1 for
this board.
If ``tx`` and ``rx`` are not specified then the internal USB-UART TX/RX pins
are used which connect to the USB serial convertor on the micro:bit, thus
connecting the UART to your PC. You can specify any other pins you want by
passing the desired pin objects to the ``tx`` and ``rx`` parameters.
.. note::
When connecting the device, make sure you "cross" the wires -- the TX
pin on your board needs to be connected with the RX pin on the device,
and the RX pin -- with the TX pin on the device. Also make sure the
ground pins of both devices are connected.
"""
def any() -> bool:
"""Return ``True`` if any characters waiting, else ``False``."""
def read(nbytes: int = None) -> bytes:
"""Read characters. If ``nbytes`` is specified then read at most that many
bytes."""
def readall() -> Optional[bytes]:
"""Read as much data as possible.
Return value: a bytes object or ``None`` on timeout.
"""
def readinto(buf: bytearray, nbytes: int = None) -> Optional[int]:
"""Read bytes into the ``buf``. If ``nbytes`` is specified then read at most
that many bytes. Otherwise, read at most ``len(buf)`` bytes.
Return value: number of bytes read and stored into ``buf`` or ``None`` on
timeout.
"""
def readline() -> Optional[bytes]:
"""Read a line, ending in a newline character.
Return value: the line read or ``None`` on timeout. The newline character is
included in the returned bytes.
"""
def write(buf: Union[bytes, bytearray]) -> Optional[int]:
"""Write the buffer of bytes to the bus.
Return value: number of bytes written or ``None`` on timeout.
"""
ODD: int
EVEN: int
================================================
FILE: typehints/microbit/music.pyi
================================================
"""
MicroPython on the BBC micro:bit comes with a powerful music and
sound module. It’s very easy to generate bleeps and bloops from
the device if you attach a speaker. Use crocodile clips to attach
pin 0 and GND to the positive and negative inputs on the speaker -
it doesn’t matter which way round they are connected to the speaker.
Musical Notation
An individual note is specified thus:
NOTE[octave][:duration]
For example, A1:4 refers to the note “A” in octave 1 that lasts for four ticks
(a tick is an arbitrary length of time defined by a tempo setting function -
see below). If the note name R is used then it is treated as a rest (silence).
Accidentals (flats and sharps) are denoted by the b
(flat - a lower case b) and # (sharp - a hash symbol).
For example, Ab is A-flat and C# is C-sharp.
Note names are case-insensitive.
The octave and duration parameters are states that carry over to
subsequent notes until re-specified. The default states are octave = 4
(containing middle C) and duration = 4 (a crotchet, given the default
tempo settings - see below).
For example, if 4 ticks is a crotchet, the following list is crotchet,
quaver, quaver, crotchet based arpeggio:
['c1:4', 'e:2', 'g', 'c2:4']
The opening of Beethoven’s 5th Symphony would be encoded thus:
['r4:2', 'g', 'g', 'g', 'eb:8', 'r:2', 'f', 'f', 'f', 'd:8']
The definition and scope of an octave conforms to the table
listed on this page about scientific pitch notation. For example, middle “C” is
c4' and concert “A” (440) is 'a4'. Octaves start on the note “C”.
The definition and scope of an octave conforms to the table
listed on this page about scientific pitch notation. For example, middle
“C” is 'c4' and concert “A” (440) is 'a4'. Octaves start on the note “C”.
Built in Melodies
For the purposes of education and entertainment, the module contains
several example tunes that are expressed as Python lists. They can be used like this:
import music
music.play(music.NYAN)
All the tunes are either out of copyright, composed by
Nicholas H.Tollervey and
released to the public domain or have an unknown composer and are
covered by a fair (educational) use provision.
They are:
DADADADUM - the opening to Beethoven’s 5th Symphony in C minor.
ENTERTAINER - the opening fragment of Scott Joplin’s
Ragtime classic “The Entertainer”.
PRELUDE - the opening of the first Prelude in C Major of
J.S.Bach’s 48 Preludes and Fugues.
ODE - the “Ode to Joy” theme from Beethoven’s 9th Symphony in D minor.
NYAN - the Nyan Cat theme (http://www.nyan.cat/). The composer is unknown.
This is fair use for educational porpoises (as they say in New York).
RINGTONE - something that sounds like a mobile phone ringtone. To be used
to indicate an incoming message.
FUNK - a funky bass line for secret agents and criminal masterminds.
BLUES - a boogie-woogie 12-bar blues walking bass.
BIRTHDAY - “Happy Birthday to You...” for copyright status see:
http://www.bbc.co.uk/news/world-us-canada-34332853
WEDDING - the bridal chorus from Wagner’s opera “Lohengrin”.
FUNERAL - the “funeral march” otherwise known as Frédéric Chopin’s
Piano Sonata No. 2 in B♭ minor, Op. 35.
PUNCHLINE - a fun fragment that signifies a joke has been made.
PYTHON - John Philip Sousa’s march “Liberty Bell” aka, the theme for
“Monty Python’s Flying Circus” (after which the Python
programming language is named).
BADDY - silent movie era entrance of a baddy.
CHASE - silent movie era chase scene.
BA_DING - a short signal to indicate something has happened.
WAWAWAWAA - a very sad trombone.
JUMP_UP - for use in a game, indicating upward movement.
JUMP_DOWN - for use in a game, indicating downward movement.
POWER_UP - a fanfare to indicate an achievement unlocked.
POWER_DOWN - a sad fanfare to indicate an achievement lost.
Example
Plays a simple tune using the Micropython music module.
This example requires a speaker/buzzer/headphones connected to P0 and GND.
from microbit import *
import music
# play Prelude in C.
notes = [
'c4:1', 'e', 'g', 'c5', 'e5', 'g4', 'c5', 'e5', 'c4', 'e', 'g', 'c5', 'e5', 'g4', 'c5', 'e5',
'c4', 'd', 'g', 'd5', 'f5', 'g4', 'd5', 'f5', 'c4', 'd', 'g', 'd5', 'f5', 'g4', 'd5', 'f5',
'b3', 'd4', 'g', 'd5', 'f5', 'g4', 'd5', 'f5', 'b3', 'd4', 'g', 'd5', 'f5', 'g4', 'd5', 'f5',
'c4', 'e', 'g', 'c5', 'e5', 'g4', 'c5', 'e5', 'c4', 'e', 'g', 'c5', 'e5', 'g4', 'c5', 'e5',
'c4', 'e', 'a', 'e5', 'a5', 'a4', 'e5', 'a5', 'c4', 'e', 'a', 'e5', 'a5', 'a4', 'e5', 'a5',
'c4', 'd', 'f#', 'a', 'd5', 'f#4', 'a', 'd5', 'c4', 'd', 'f#', 'a', 'd5', 'f#4', 'a', 'd5',
'b3', 'd4', 'g', 'd5', 'g5', 'g4', 'd5', 'g5', 'b3', 'd4', 'g', 'd5', 'g5', 'g4', 'd5', 'g5',
'b3', 'c4', 'e', 'g', 'c5', 'e4', 'g', 'c5', 'b3', 'c4', 'e', 'g', 'c5', 'e4', 'g', 'c5',
'b3', 'c4', 'e', 'g', 'c5', 'e4', 'g', 'c5', 'b3', 'c4', 'e', 'g', 'c5', 'e4', 'g', 'c5',
'a3', 'c4', 'e', 'g', 'c5', 'e4', 'g', 'c5', 'a3', 'c4', 'e', 'g', 'c5', 'e4', 'g', 'c5',
'd3', 'a', 'd4', 'f#', 'c5', 'd4', 'f#', 'c5', 'd3', 'a', 'd4', 'f#', 'c5', 'd4', 'f#', 'c5',
'g3', 'b', 'd4', 'g', 'b', 'd', 'g', 'b', 'g3', 'b3', 'd4', 'g', 'b', 'd', 'g', 'b'
]
music.play(notes)
"""
from typing import Tuple, Union, List
from . microbit import pin0, MicroBitAnalogDigitalPin
DADADADUM = 0
ENTERTAINER = 1
PRELUDE = 2
ODE = 3
NYAN = 4
RINGTONE = 5
FUNK = 6
BLUES = 7
BIRTHDAY = 8
WEDDING = 9
FUNERAL = 10
PUNCHLINE = 11
PYTHON = 12
BADDY = 12
CHASE = 13
BA_DING = 14
WAWAWAWAA = 15
JUMP_UP = 16
JUMP_DOWN = 17
POWER_UP = 18
POWER_DOWN = 19
def set_tempo(ticks: int = 4, bpm: int = 120) -> None:
"""
Sets the approximate tempo for playback.
A number of ticks (expressed as an integer) constitute a beat.
Each beat is to be played at a certain frequency per minute
(expressed as the more familiar BPM - beats per minute -
also as an integer).
Suggested default values allow the following useful behaviour:
music.set_tempo() - reset the tempo to default of ticks = 4, bpm = 120
music.set_tempo(ticks=8) - change the “definition” of a beat
music.set_tempo(bpm=180) - just change the tempo
To work out the length of a tick in milliseconds is very simple arithmetic:
60000/bpm/ticks_per_beat . For the default values that’s
60000/120/4 = 125 milliseconds or 1 beat = 500 milliseconds.
"""
def get_tempo(self) -> Tuple[int, int]:
"""
Gets the current tempo as a tuple of integers: (ticks, bpm).
"""
def play(music: Union[str, List[str]],
pin: MicroBitAnalogDigitalPin = pin0, wait: bool=True, loop: bool=False) -> None:
"""
Sets the approximate tempo for playback.
A number of ticks (expressed as an integer) constitute a beat.
Each beat is to be played at a certain frequency per
minute (expressed as the more familiar BPM - beats per minute -
also as an integer).
Suggested default values allow the following useful behaviour:
music.set_tempo() - reset the tempo to default of ticks = 4, bpm = 120
music.set_tempo(ticks=8) - change the “definition” of a beat
music.set_tempo(bpm=180) - just change the tempo
To work out the length of a tick in milliseconds is very simple arithmetic:
60000/bpm/ticks_per_beat . For the default values that’s 60000/120/4 =
125 milliseconds or 1 beat = 500 milliseconds.
"""
def pitch(frequency: int, len=-1, pin: MicroBitAnalogDigitalPin = pin0,
wait: bool=True) -> None:
"""
Plays a pitch at the integer frequency given for the specified
number of milliseconds. For example, if the frequency is set to 440 and
the length to 1000 then we hear a standard concert A for one second.
If wait is set to True, this function is blocking.
If len is negative the pitch is played continuously until
either the blocking call is interrupted or, in the case of a background call,
a new frequency is set or stop is called (see below).
"""
def stop(pin: MicroBitAnalogDigitalPin = pin0) -> None:
"""
Stops all music playback on a given pin.
"""
def reset() -> None:
"""
Resets the state of the following attributes in the following way:
ticks = 4
bpm = 120
duration = 4
octave = 4
"""
================================================
FILE: typehints/microbit/neopixel.pyi
================================================
"""
The neopixel module lets you use Neopixel (WS2812) individually
addressable RGB LED strips with the Microbit.
Note to use the neopixel module, you need to import it separately with:
import neopixel
Note
From our tests, the Microbit Neopixel module can drive up to around 256
Neopixels. Anything above that and you may experience weird bugs and issues.
NeoPixels are fun strips of multi-coloured programmable LEDs.
This module contains everything to plug them into a micro:bit
and create funky displays, art and games
Warning
Do not use the 3v connector on the Microbit to power any more than
8 Neopixels at a time.
If you wish to use more than 8 Neopixels, you must use a separate
3v-5v power supply for the Neopixel power pin.
Operations
Writing the colour doesn’t update the display (use show() for that).
np[0] = (255, 0, 128) # first element
np[-1] = (0, 255, 0) # last element
np.show() # only now will the updated value be shown
To read the colour of a specific pixel just reference it.
print(np[0])
Using Neopixels
Interact with Neopixels as if they were a list of tuples.
Each tuple represents the RGB (red, green and blue) mix of colours
for a specific pixel. The RGB values can range between 0 to 255.
For example, initialise a strip of 8 neopixels on a strip connected
to pin0 like this:
import neopixel
np = neopixel.NeoPixel(pin0, 8)
Set pixels by indexing them (like with a Python list). For instance,
to set the first pixel to full brightness red, you would use:
np[0] = (255, 0, 0)
Or the final pixel to purple:
np[-1] = (255, 0, 255)
Get the current colour value of a pixel by indexing it. For example,
to print the first pixel’s RGB value use:
print(np[0])
Finally, to push the new colour data to your Neopixel strip, use the .show() function:
np.show()
If nothing is happening, it’s probably because you’ve forgotten this final step..!
Note
If you’re not seeing anything change on your Neopixel strip,
make sure you have show() at least somewhere otherwise your updates won’t be shown.
"""
from . microbit import MicroBitAnalogDigitalPin
def NeoPixel(pin: MicroBitAnalogDigitalPin, n: int)-> None:
"""
Initialise a new strip of n number of neopixel LEDs controlled via pin pin.
Each pixel is addressed by a position (starting from 0).
Neopixels are given RGB (red, green, blue) values between 0-255 as a tuple.
For example, (255,255,255) is white.
"""
def clear()->None:
"""
Clear all the pixels.
"""
def show()->None:
"""
Show the pixels. Must be called for any updates to become visible.
"""
================================================
FILE: typehints/microbit/radio.pyi
================================================
"""The ``radio`` module allows devices to work together via simple wireless
networks.
The radio module is conceptually very simple:
* Broadcast messages are of a certain configurable length (up to 251 bytes).
* Messages received are read from a queue of configurable size (the larger the queue the more RAM is used). If the queue is full, new messages are ignored.
* Messages are broadcast and received on a preselected channel (numbered 0-100).
* Broadcasts are at a certain level of power - more power means more range.
* Messages are filtered by address (like a house number) and group (like a named recipient at the specified address).
* The rate of throughput can be one of three pre-determined settings.
* Send and receieve bytes to work with arbitrary data.
* As a convenience for children, it's easy to send and receive messages as strings.
* The default configuration is both sensible and compatible with other platforms that target the BBC micro:bit.
To access this module you need to::
import radio
We assume you have done this for the examples below.
"""
from typing import Optional
RATE_250KBIT: int
"""Constant used to indicate a throughput of 256 Kbit a second."""
RATE_1MBIT: int
"""Constant used to indicate a throughput of 1 MBit a second."""
RATE_2MBIT: int
"""Constant used to indicate a throughput of 2 MBit a second."""
def on() -> None:
"""Turns the radio on. This needs to be explicitly called since the radio
draws power and takes up memory that you may otherwise need.
"""
def off() -> None:
"""Turns off the radio, thus saving power and memory."""
def config(length: int = 32, queue: int = 3, channel: int = 7,
power: int = 6, address: int = 0x75626974, group: int = 0,
data_rate: int = RATE_1MBIT) -> None:
"""Configures various keyword based settings relating to the radio. The
available settings and their sensible default values are listed below.
The ``length`` (default=32) defines the maximum length, in bytes, of a
message sent via the radio. It can be up to 251 bytes long (254 - 3 bytes
for S0, LENGTH and S1 preamble).
The ``queue`` (default=3) specifies the number of messages that can be
stored on the incoming message queue. If there are no spaces left on the
queue for incoming messages, then the incoming message is dropped.
The ``channel`` (default=7) can be an integer value from 0 to 100
(inclusive) that defines an arbitrary "channel" to which the radio is
tuned. Messages will be sent via this channel and only messages received
via this channel will be put onto the incoming message queue. Each step is
1MHz wide, based at 2400MHz.
The ``power`` (default=6) is an integer value from 0 to 7 (inclusive) to
indicate the strength of signal used when broadcasting a message. The
higher the value the stronger the signal, but the more power is consumed
by the device. The numbering translates to positions in the following list
of dBm (decibel milliwatt) values: -30, -20, -16, -12, -8, -4, 0, 4.
The ``address`` (default=0x75626974) is an arbitrary name, expressed as a
32-bit address, that's used to filter incoming packets at the hardware
level, keeping only those that match the address you set. The default used
by other micro:bit related platforms is the default setting used here.
The ``group`` (default=0) is an 8-bit value (0-255) used with the
``address`` when filtering messages. Conceptually, "address" is like a
house/office address and "group" is like the person at that address to
which you want to send your message.
The ``data_rate`` (default=radio.RATE_1MBIT) indicates the speed at which
data throughput takes place. Can be one of the following contants defined
in the ``radio`` module : ``RATE_250KBIT``, ``RATE_1MBIT`` or
``RATE_2MBIT``.
If ``config`` is not called then the defaults described above are assumed.
"""
def reset() -> None:
"""Reset the settings to their default values (as listed in the documentation
for the ``config`` function above).
"""
def send_bytes(message: bytes) -> None:
"""Sends a message containing bytes."""
def receive_bytes() -> Optional[bytes]:
"""Receive the next incoming message on the message queue. Returns ``None`` if
there are no pending messages. Messages are returned as bytes.
"""
def receive_bytes_into(buffer: bytearray) -> Optional[int]:
"""Receive the next incoming message on the message queue. Copies the message
into ``buffer``, trimming the end of the message if necessary.
Returns ``None`` if there are no pending messages, otherwise it returns the length
of the message (which might be more than the length of the buffer).
"""
def send(message: str) -> None:
"""Sends a message string. This is the equivalent of
``send_bytes(bytes(message, 'utf8'))`` but with ``b'\x01\x00\x01'``
prepended to the front (to make it compatible with other platforms that
target the micro:bit).
"""
def receive() -> Optional[str]:
"""Works in exactly the same way as ``receive_bytes`` but returns
whatever was sent.
Currently, it's equivalent to ``str(receive_bytes(), 'utf8')`` but with a
check that the the first three bytes are ``b'\x01\x00\x01'`` (to make it
compatible with other platforms that may target the micro:bit). It strips
the prepended bytes before converting to a string.
A ``ValueError`` exception is raised if conversion to string fails.
"""
================================================
FILE: typehints/microbit/speech.pyi
================================================
"""
Speech
Warning
WARNING! THIS IS ALPHA CODE.
We reserve the right to change this API as development continues.
The quality of the speech is not great, merely “good enough”.
Given the constraints of the device you may encounter memory errors
and / or unexpected extra sounds during playback. It’s early days
and we’re improving the code for the speech synthesiser all the time.
Bug reports and pull requests are most welcome.
This module makes microbit talk, sing and make other
speech like sounds provided that you connect a speaker to your board.
Note
This work is based upon the amazing reverse engineering efforts of
Sebastian Macke based upon an old text-to-speech (TTS) program called
SAM (Software Automated Mouth) originally released in 1982 for the
Commodore 64. The result is a small C library that we have
adopted and adapted for the micro:bit. You can find out more from his homepage.
Much of the information in this document was gleaned from the
original user’s manual which can be found here.
The speech synthesiser can produce around 2.5 seconds
worth of sound from up to 255 characters of textual input.
To access this module you need to:
import speech
See http://microbit-micropython.readthedocs.io/en/latest/speech.html
for details
"""
def translate(words: str) ->None:
"""
Given English words in the string words, return a string
containing a best guess at the appropriate phonemes to pronounce.
The output is generated from this text to phoneme translation table.
This function should be used to generate a first approximation of phonemes
that can be further hand-edited to improve accuracy, inflection and emphasis.
"""
def pronounce(phonemes: str, pitch: int=64, speed: int=72,
mouth: int=128, throat: int=128)->None:
"""
Pronounce the phonemes in the string phonemes. See below for details of how
to use phonemes to finely control the output of the speech synthesiser.
Override the optional pitch, speed, mouth and throat settings to change
the timbre (quality) of the voice.
"""
def say(words: str, pitch: int=64, speed: int=72,
mouth: int=128, throat: int=128)->None:
"""
Say the English words in the string words. The result is semi-accurate
for English.
Override the optional pitch, speed, mouth and throat settings to change
the timbre (quality) of the voice. This is a short-hand equivalent of:
speech.pronounce(speech.translate(words))
"""
def sing(phonemes: str, pitch: int=64, speed: int=72,
mouth: int=128, throat: int=128)->None:
"""
Sing the phonemes contained in the string phonemes. Changing the pitch
and duration of the note is described below. Override the optional pitch,
speed, mouth and throat settings to change the timbre (quality) of the voice.
"""
================================================
FILE: typehints/micropython/bluetooth.pyi
================================================
"""
Low-level Bluetooth radio functionality.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/bluetooth.rst.
This module provides an interface to a Bluetooth controller on a board.
Currently this supports Bluetooth Low Energy (BLE) in Central, Peripheral,
Broadcaster, and Observer roles, as well as GATT Server and Client and L2CAP
connection-oriented-channels. A device may operate in multiple roles
concurrently. Pairing (and bonding) is supported on some ports.
This API is intended to match the low-level Bluetooth protocol and provide
building-blocks for higher-level abstractions such as specific device types.
.. note:: This module is still under development and its classes, functions,
methods and constants are subject to change.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import overload, Any, Callable, Final
from uio import AnyReadableBuf, AnyWritableBuf
# noinspection SpellCheckingInspection
class BLE:
"""
class BLE
---------
"""
def __init__(self):
"""
Returns the singleton BLE object.
"""
@overload
def active(self) -> bool:
"""
Optionally changes the active state of the BLE radio, and returns the
current state.
The radio must be made active before using any other methods on this class.
"""
@overload
def active(self, active: bool, /) -> None:
"""
Optionally changes the active state of the BLE radio, and returns the
current state.
The radio must be made active before using any other methods on this class.
"""
@overload
def config(self, param: str, /) -> Any:
"""
Get or set configuration values of the BLE interface. To get a value the
parameter name should be quoted as a string, and just one parameter is
queried at a time. To set values use the keyword syntax, and one ore more
parameter can be set at a time.
Currently supported values are:
- ``'mac'``: The current address in use, depending on the current address mode.
This returns a tuple of ``(addr_type, addr)``.
See :meth:`gatts_write ` for details about address type.
This may only be queried while the interface is currently active.
- ``'addr_mode'``: Sets the address mode. Values can be:
* 0x00 - PUBLIC - Use the controller's public address.
* 0x01 - RANDOM - Use a generated static address.
* 0x02 - RPA - Use resolvable private addresses.
* 0x03 - NRPA - Use non-resolvable private addresses.
By default the interface mode will use a PUBLIC address if available, otherwise
it will use a RANDOM address.
- ``'gap_name'``: Get/set the GAP device name used by service 0x1800,
characteristic 0x2a00. This can be set at any time and changed multiple
times.
- ``'rxbuf'``: Get/set the size in bytes of the internal buffer used to store
incoming events. This buffer is global to the entire BLE driver and so
handles incoming data for all events, including all characteristics.
Increasing this allows better handling of bursty incoming data (for
example scan results) and the ability to receive larger characteristic values.
- ``'mtu'``: Get/set the MTU that will be used during a ATT MTU exchange. The
resulting MTU will be the minimum of this and the remote device's MTU.
ATT MTU exchange will not happen automatically (unless the remote device initiates
it), and must be manually initiated with
:meth:`gattc_exchange_mtu`.
Use the ``_IRQ_MTU_EXCHANGED`` event to discover the MTU for a given connection.
- ``'bond'``: Sets whether bonding will be enabled during pairing. When
enabled, pairing requests will set the "bond" flag and the keys will be stored
by both devices.
- ``'mitm'``: Sets whether MITM-protection is required for pairing.
- ``'io'``: Sets the I/O capabilities of this device.
Available options are::
_IO_CAPABILITY_DISPLAY_ONLY = const(0)
_IO_CAPABILITY_DISPLAY_YESNO = const(1)
_IO_CAPABILITY_KEYBOARD_ONLY = const(2)
_IO_CAPABILITY_NO_INPUT_OUTPUT = const(3)
_IO_CAPABILITY_KEYBOARD_DISPLAY = const(4)
- ``'le_secure'``: Sets whether "LE Secure" pairing is required. Default is
false (i.e. allow "Legacy Pairing").
"""
@overload
def config(self, **kwargs) -> None:
"""
Get or set configuration values of the BLE interface. To get a value the
parameter name should be quoted as a string, and just one parameter is
queried at a time. To set values use the keyword syntax, and one ore more
parameter can be set at a time.
Currently supported values are:
- ``'mac'``: The current address in use, depending on the current address mode.
This returns a tuple of ``(addr_type, addr)``.
See :meth:`gatts_write ` for details about address type.
This may only be queried while the interface is currently active.
- ``'addr_mode'``: Sets the address mode. Values can be:
* 0x00 - PUBLIC - Use the controller's public address.
* 0x01 - RANDOM - Use a generated static address.
* 0x02 - RPA - Use resolvable private addresses.
* 0x03 - NRPA - Use non-resolvable private addresses.
By default the interface mode will use a PUBLIC address if available, otherwise
it will use a RANDOM address.
- ``'gap_name'``: Get/set the GAP device name used by service 0x1800,
characteristic 0x2a00. This can be set at any time and changed multiple
times.
- ``'rxbuf'``: Get/set the size in bytes of the internal buffer used to store
incoming events. This buffer is global to the entire BLE driver and so
handles incoming data for all events, including all characteristics.
Increasing this allows better handling of bursty incoming data (for
example scan results) and the ability to receive larger characteristic values.
- ``'mtu'``: Get/set the MTU that will be used during a ATT MTU exchange. The
resulting MTU will be the minimum of this and the remote device's MTU.
ATT MTU exchange will not happen automatically (unless the remote device initiates
it), and must be manually initiated with
:meth:`gattc_exchange_mtu`.
Use the ``_IRQ_MTU_EXCHANGED`` event to discover the MTU for a given connection.
- ``'bond'``: Sets whether bonding will be enabled during pairing. When
enabled, pairing requests will set the "bond" flag and the keys will be stored
by both devices.
- ``'mitm'``: Sets whether MITM-protection is required for pairing.
- ``'io'``: Sets the I/O capabilities of this device.
Available options are::
_IO_CAPABILITY_DISPLAY_ONLY = const(0)
_IO_CAPABILITY_DISPLAY_YESNO = const(1)
_IO_CAPABILITY_KEYBOARD_ONLY = const(2)
_IO_CAPABILITY_NO_INPUT_OUTPUT = const(3)
_IO_CAPABILITY_KEYBOARD_DISPLAY = const(4)
- ``'le_secure'``: Sets whether "LE Secure" pairing is required. Default is
false (i.e. allow "Legacy Pairing").
"""
def irq(self, handler: Callable[[int, tuple[memoryview, ...]], Any], /) -> None:
"""
Registers a callback for events from the BLE stack. The *handler* takes two
arguments, ``event`` (which will be one of the codes below) and ``data``
(which is an event-specific tuple of values).
**Note:** As an optimisation to prevent unnecessary allocations, the ``addr``,
``adv_data``, ``char_data``, ``notify_data``, and ``uuid`` entries in the
tuples are read-only memoryview instances pointing to :mod:`bluetooth`'s internal
ringbuffer, and are only valid during the invocation of the IRQ handler
function. If your program needs to save one of these values to access after
the IRQ handler has returned (e.g. by saving it in a class instance or global
variable), then it needs to take a copy of the data, either by using ``bytes()``
or ``bluetooth.UUID()``, like this::
connected_addr = bytes(addr) # equivalently: adv_data, char_data, or notify_data
matched_uuid = bluetooth.UUID(uuid)
For example, the IRQ handler for a scan result might inspect the ``adv_data``
to decide if it's the correct device, and only then copy the address data to be
used elsewhere in the program. And to print data from within the IRQ handler,
``print(bytes(addr))`` will be needed.
An event handler showing all possible events::
def bt_irq(event, data):
if event == _IRQ_CENTRAL_CONNECT:
# A central has connected to this peripheral.
conn_handle, addr_type, addr = data
elif event == _IRQ_CENTRAL_DISCONNECT:
# A central has disconnected from this peripheral.
conn_handle, addr_type, addr = data
elif event == _IRQ_GATTS_WRITE:
# A client has written to this characteristic or descriptor.
conn_handle, attr_handle = data
elif event == _IRQ_GATTS_READ_REQUEST:
# A client has issued a read. Note: this is only supported on STM32.
# Return a non-zero integer to deny the read (see below), or zero (or None)
# to accept the read.
conn_handle, attr_handle = data
elif event == _IRQ_SCAN_RESULT:
# A single scan result.
addr_type, addr, adv_type, rssi, adv_data = data
elif event == _IRQ_SCAN_DONE:
# Scan duration finished or manually stopped.
pass
elif event == _IRQ_PERIPHERAL_CONNECT:
# A successful gap_connect().
conn_handle, addr_type, addr = data
elif event == _IRQ_PERIPHERAL_DISCONNECT:
# Connected peripheral has disconnected.
conn_handle, addr_type, addr = data
elif event == _IRQ_GATTC_SERVICE_RESULT:
# Called for each service found by gattc_discover_services().
conn_handle, start_handle, end_handle, uuid = data
elif event == _IRQ_GATTC_SERVICE_DONE:
# Called once service discovery is complete.
# Note: Status will be zero on success, implementation-specific value otherwise.
conn_handle, status = data
elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT:
# Called for each characteristic found by gattc_discover_services().
conn_handle, def_handle, value_handle, properties, uuid = data
elif event == _IRQ_GATTC_CHARACTERISTIC_DONE:
# Called once service discovery is complete.
# Note: Status will be zero on success, implementation-specific value otherwise.
conn_handle, status = data
elif event == _IRQ_GATTC_DESCRIPTOR_RESULT:
# Called for each descriptor found by gattc_discover_descriptors().
conn_handle, dsc_handle, uuid = data
elif event == _IRQ_GATTC_DESCRIPTOR_DONE:
# Called once service discovery is complete.
# Note: Status will be zero on success, implementation-specific value otherwise.
conn_handle, status = data
elif event == _IRQ_GATTC_READ_RESULT:
# A gattc_read() has completed.
conn_handle, value_handle, char_data = data
elif event == _IRQ_GATTC_READ_DONE:
# A gattc_read() has completed.
# Note: The value_handle will be zero on btstack (but present on NimBLE).
# Note: Status will be zero on success, implementation-specific value otherwise.
conn_handle, value_handle, status = data
elif event == _IRQ_GATTC_WRITE_DONE:
# A gattc_write() has completed.
# Note: The value_handle will be zero on btstack (but present on NimBLE).
# Note: Status will be zero on success, implementation-specific value otherwise.
conn_handle, value_handle, status = data
elif event == _IRQ_GATTC_NOTIFY:
# A server has sent a notify request.
conn_handle, value_handle, notify_data = data
elif event == _IRQ_GATTC_INDICATE:
# A server has sent an indicate request.
conn_handle, value_handle, notify_data = data
elif event == _IRQ_GATTS_INDICATE_DONE:
# A client has acknowledged the indication.
# Note: Status will be zero on successful acknowledgment, implementation-specific value otherwise.
conn_handle, value_handle, status = data
elif event == _IRQ_MTU_EXCHANGED:
# ATT MTU exchange complete (either initiated by us or the remote device).
conn_handle, mtu = data
elif event == _IRQ_L2CAP_ACCEPT:
# A new channel has been accepted.
# Return a non-zero integer to reject the connection, or zero (or None) to accept.
conn_handle, cid, psm, our_mtu, peer_mtu = data
elif event == _IRQ_L2CAP_CONNECT:
# A new channel is now connected (either as a result of connecting or accepting).
conn_handle, cid, psm, our_mtu, peer_mtu = data
elif event == _IRQ_L2CAP_DISCONNECT:
# Existing channel has disconnected (status is zero), or a connection attempt failed (non-zero status).
conn_handle, cid, psm, status = data
elif event == _IRQ_L2CAP_RECV:
# New data is available on the channel. Use l2cap_recvinto to read.
conn_handle, cid = data
elif event == _IRQ_L2CAP_SEND_READY:
# A previous l2cap_send that returned False has now completed and the channel is ready to send again.
# If status is non-zero, then the transmit buffer overflowed and the application should re-send the data.
conn_handle, cid, status = data
elif event == _IRQ_CONNECTION_UPDATE:
# The remote device has updated connection parameters.
conn_handle, conn_interval, conn_latency, supervision_timeout, status = data
elif event == _IRQ_ENCRYPTION_UPDATE:
# The encryption state has changed (likely as a result of pairing or bonding).
conn_handle, encrypted, authenticated, bonded, key_size = data
elif event == _IRQ_GET_SECRET:
# Return a stored secret.
# If key is None, return the index'th value of this sec_type.
# Otherwise return the corresponding value for this sec_type and key.
sec_type, index, key = data
return value
elif event == _IRQ_SET_SECRET:
# Save a secret to the store for this sec_type and key.
sec_type, key, value = data
return True
elif event == _IRQ_PASSKEY_ACTION:
# Respond to a passkey request during pairing.
# See gap_passkey() for details.
# action will be an action that is compatible with the configured "io" config.
# passkey will be non-zero if action is "numeric comparison".
conn_handle, action, passkey = data
The event codes are::
from micropython import const
_IRQ_CENTRAL_CONNECT = const(1)
_IRQ_CENTRAL_DISCONNECT = const(2)
_IRQ_GATTS_WRITE = const(3)
_IRQ_GATTS_READ_REQUEST = const(4)
_IRQ_SCAN_RESULT = const(5)
_IRQ_SCAN_DONE = const(6)
_IRQ_PERIPHERAL_CONNECT = const(7)
_IRQ_PERIPHERAL_DISCONNECT = const(8)
_IRQ_GATTC_SERVICE_RESULT = const(9)
_IRQ_GATTC_SERVICE_DONE = const(10)
_IRQ_GATTC_CHARACTERISTIC_RESULT = const(11)
_IRQ_GATTC_CHARACTERISTIC_DONE = const(12)
_IRQ_GATTC_DESCRIPTOR_RESULT = const(13)
_IRQ_GATTC_DESCRIPTOR_DONE = const(14)
_IRQ_GATTC_READ_RESULT = const(15)
_IRQ_GATTC_READ_DONE = const(16)
_IRQ_GATTC_WRITE_DONE = const(17)
_IRQ_GATTC_NOTIFY = const(18)
_IRQ_GATTC_INDICATE = const(19)
_IRQ_GATTS_INDICATE_DONE = const(20)
_IRQ_MTU_EXCHANGED = const(21)
_IRQ_L2CAP_ACCEPT = const(22)
_IRQ_L2CAP_CONNECT = const(23)
_IRQ_L2CAP_DISCONNECT = const(24)
_IRQ_L2CAP_RECV = const(25)
_IRQ_L2CAP_SEND_READY = const(26)
_IRQ_CONNECTION_UPDATE = const(27)
_IRQ_ENCRYPTION_UPDATE = const(28)
_IRQ_GET_SECRET = const(29)
_IRQ_SET_SECRET = const(30)
For the ``_IRQ_GATTS_READ_REQUEST`` event, the available return codes are::
_GATTS_NO_ERROR = const(0x00)
_GATTS_ERROR_READ_NOT_PERMITTED = const(0x02)
_GATTS_ERROR_WRITE_NOT_PERMITTED = const(0x03)
_GATTS_ERROR_INSUFFICIENT_AUTHENTICATION = const(0x05)
_GATTS_ERROR_INSUFFICIENT_AUTHORIZATION = const(0x08)
_GATTS_ERROR_INSUFFICIENT_ENCRYPTION = const(0x0f)
For the ``_IRQ_PASSKEY_ACTION`` event, the available actions are::
_PASSKEY_ACTION_NONE = const(0)
_PASSKEY_ACTION_INPUT = const(2)
_PASSKEY_ACTION_DISPLAY = const(3)
_PASSKEY_ACTION_NUMERIC_COMPARISON = const(4)
In order to save space in the firmware, these constants are not included on the
:mod:`bluetooth` module. Add the ones that you need from the list above to your
program.
"""
def gap_advertise(
self,
interval_us: int,
adv_data: AnyReadableBuf | None = None,
/,
*,
resp_data: AnyReadableBuf | None = None,
connectable: bool = True,
) -> None:
"""
Starts advertising at the specified interval (in **micro**\ seconds). This
interval will be rounded down to the nearest 625us. To stop advertising, set
*interval_us* to ``None``.
*adv_data* and *resp_data* can be any type that implements the buffer
protocol (e.g. ``bytes``, ``bytearray``, ``str``). *adv_data* is included
in all broadcasts, and *resp_data* is send in reply to an active scan.
**Note:** if *adv_data* (or *resp_data*) is ``None``, then the data passed
to the previous call to ``gap_advertise`` will be re-used. This allows a
broadcaster to resume advertising with just ``gap_advertise(interval_us)``.
To clear the advertising payload pass an empty ``bytes``, i.e. ``b''``.
"""
def gap_scan(
self,
duration_ms: int,
interval_us: int = 1280000,
window_us: int = 11250,
active: bool = False,
/,
) -> None:
"""
Run a scan operation lasting for the specified duration (in **milli**\ seconds).
To scan indefinitely, set *duration_ms* to ``0``.
To stop scanning, set *duration_ms* to ``None``.
Use *interval_us* and *window_us* to optionally configure the duty cycle.
The scanner will run for *window_us* **micro**\ seconds every *interval_us*
**micro**\ seconds for a total of *duration_ms* **milli**\ seconds. The default
interval and window are 1.28 seconds and 11.25 milliseconds respectively
(background scanning).
For each scan result the ``_IRQ_SCAN_RESULT`` event will be raised, with event
data ``(addr_type, addr, adv_type, rssi, adv_data)``.
``addr_type`` values indicate public or random addresses:
* 0x00 - PUBLIC
* 0x01 - RANDOM (either static, RPA, or NRPA, the type is encoded in the address itself)
``adv_type`` values correspond to the Bluetooth Specification:
* 0x00 - ADV_IND - connectable and scannable undirected advertising
* 0x01 - ADV_DIRECT_IND - connectable directed advertising
* 0x02 - ADV_SCAN_IND - scannable undirected advertising
* 0x03 - ADV_NONCONN_IND - non-connectable undirected advertising
* 0x04 - SCAN_RSP - scan response
``active`` can be set ``True`` if you want to receive scan responses in the results.
When scanning is stopped (either due to the duration finishing or when
explicitly stopped), the ``_IRQ_SCAN_DONE`` event will be raised.
"""
def gap_connect(
self,
addr_type: int,
addr: bytes,
scan_duration_ms: int = 2000,
min_conn_interval_us: int | None = None,
max_conn_interval_us: int | None = None,
/,
) -> None:
"""
Connect to a peripheral.
See :meth:`gap_scan ` for details about address types.
On success, the ``_IRQ_PERIPHERAL_CONNECT`` event will be raised.
The device will wait up to *scan_duration_ms* to receive an advertising
payload from the device.
The connection interval can be configured in **micro**\ seconds using either
or both of *min_conn_interval_us* and *max_conn_interval_us*. Otherwise a
default interval will be chosen, typically between 30000 and 50000
microseconds. A shorter interval will increase throughput, at the expense
of power usage.
Central Role
------------
A central device can connect to peripherals that it has discovered using the observer role (see :meth:`gap_scan`) or with a known address.
"""
def gap_disconnect(self, conn_handle: memoryview, /) -> bool:
"""
Disconnect the specified connection handle. This can either be a
central that has connected to this device (if acting as a peripheral)
or a peripheral that was previously connected to by this device (if acting
as a central).
On success, the ``_IRQ_PERIPHERAL_DISCONNECT`` or ``_IRQ_CENTRAL_DISCONNECT``
event will be raised.
Returns ``False`` if the connection handle wasn't connected, and ``True``
otherwise.
Central Role
------------
A central device can connect to peripherals that it has discovered using the observer role (see :meth:`gap_scan`) or with a known address.
Peripheral Role
---------------
A peripheral device is expected to send connectable advertisements (see
:meth:`gap_advertise`). It will usually be acting as a GATT
server, having first registered services and characteristics using
:meth:`gatts_register_services`.
When a central connects, the ``_IRQ_CENTRAL_CONNECT`` event will be raised.
"""
_Flag: Final = int
_Descriptor: Final = tuple["UUID", _Flag]
_Characteristic: Final = tuple["UUID", _Flag] | tuple[
"UUID", _Flag, tuple[_Descriptor, ...]
]
_Service: Final = tuple["UUID", tuple[_Characteristic, ...]]
def gatts_register_services(
self, services_definition: tuple[_Service, ...], /
) -> tuple[tuple[memoryview, ...], ...]:
"""
Configures the server with the specified services, replacing any
existing services.
*services_definition* is a list of **services**, where each **service** is a
two-element tuple containing a UUID and a list of **characteristics**.
Each **characteristic** is a two-or-three-element tuple containing a UUID, a
**flags** value, and optionally a list of *descriptors*.
Each **descriptor** is a two-element tuple containing a UUID and a **flags**
value.
The **flags** are a bitwise-OR combination of the flags defined below. These
set both the behaviour of the characteristic (or descriptor) as well as the
security and privacy requirements.
The return value is a list (one element per service) of tuples (each element
is a value handle). Characteristics and descriptor handles are flattened
into the same tuple, in the order that they are defined.
The following example registers two services (Heart Rate, and Nordic UART)::
HR_UUID = bluetooth.UUID(0x180D)
HR_CHAR = (bluetooth.UUID(0x2A37), bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,)
HR_SERVICE = (HR_UUID, (HR_CHAR,),)
UART_UUID = bluetooth.UUID('6E400001-B5A3-F393-E0A9-E50E24DCCA9E')
UART_TX = (bluetooth.UUID('6E400003-B5A3-F393-E0A9-E50E24DCCA9E'), bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,)
UART_RX = (bluetooth.UUID('6E400002-B5A3-F393-E0A9-E50E24DCCA9E'), bluetooth.FLAG_WRITE,)
UART_SERVICE = (UART_UUID, (UART_TX, UART_RX,),)
SERVICES = (HR_SERVICE, UART_SERVICE,)
( (hr,), (tx, rx,), ) = bt.gatts_register_services(SERVICES)
The three value handles (``hr``, ``tx``, ``rx``) can be used with
:meth:`gatts_read `, :meth:`gatts_write `, :meth:`gatts_notify `, and
:meth:`gatts_indicate `.
**Note:** Advertising must be stopped before registering services.
Available flags for characteristics and descriptors are::
from micropython import const
_FLAG_BROADCAST = const(0x0001)
_FLAG_READ = const(0x0002)
_FLAG_WRITE_NO_RESPONSE = const(0x0004)
_FLAG_WRITE = const(0x0008)
_FLAG_NOTIFY = const(0x0010)
_FLAG_INDICATE = const(0x0020)
_FLAG_AUTHENTICATED_SIGNED_WRITE = const(0x0040)
_FLAG_AUX_WRITE = const(0x0100)
_FLAG_READ_ENCRYPTED = const(0x0200)
_FLAG_READ_AUTHENTICATED = const(0x0400)
_FLAG_READ_AUTHORIZED = const(0x0800)
_FLAG_WRITE_ENCRYPTED = const(0x1000)
_FLAG_WRITE_AUTHENTICATED = const(0x2000)
_FLAG_WRITE_AUTHORIZED = const(0x4000)
As for the IRQs above, any required constants should be added to your Python code.
GATT Server
-----------
A GATT server has a set of registered services. Each service may contain
characteristics, which each have a value. Characteristics can also contain
descriptors, which themselves have values.
These values are stored locally, and are accessed by their "value handle" which
is generated during service registration. They can also be read from or written
to by a remote client device. Additionally, a server can "notify" a
characteristic to a connected client via a connection handle.
A device in either central or peripheral roles may function as a GATT server,
however in most cases it will be more common for a peripheral device to act
as the server.
Characteristics and descriptors have a default maximum size of 20 bytes.
Anything written to them by a client will be truncated to this length. However,
any local write will increase the maximum size, so if you want to allow larger
writes from a client to a given characteristic, use
:meth:`gatts_write` after registration. e.g.
``gatts_write(char_handle, bytes(100))``.
"""
def gatts_read(self, value_handle: memoryview, /) -> bytes:
"""
Reads the local value for this handle (which has either been written by
:meth:`gatts_write ` or by a remote client).
GATT Server
-----------
A GATT server has a set of registered services. Each service may contain
characteristics, which each have a value. Characteristics can also contain
descriptors, which themselves have values.
These values are stored locally, and are accessed by their "value handle" which
is generated during service registration. They can also be read from or written
to by a remote client device. Additionally, a server can "notify" a
characteristic to a connected client via a connection handle.
A device in either central or peripheral roles may function as a GATT server,
however in most cases it will be more common for a peripheral device to act
as the server.
Characteristics and descriptors have a default maximum size of 20 bytes.
Anything written to them by a client will be truncated to this length. However,
any local write will increase the maximum size, so if you want to allow larger
writes from a client to a given characteristic, use
:meth:`gatts_write` after registration. e.g.
``gatts_write(char_handle, bytes(100))``.
"""
def gatts_write(
self, value_handle: memoryview, data: bytes, send_update: bool = False, /
) -> None:
"""
Writes the local value for this handle, which can be read by a client.
If *send_update* is ``True``, then any subscribed clients will be notified
(or indicated, depending on what they're subscribed to and which operations
the characteristic supports) about this write.
GATT Server
-----------
A GATT server has a set of registered services. Each service may contain
characteristics, which each have a value. Characteristics can also contain
descriptors, which themselves have values.
These values are stored locally, and are accessed by their "value handle" which
is generated during service registration. They can also be read from or written
to by a remote client device. Additionally, a server can "notify" a
characteristic to a connected client via a connection handle.
A device in either central or peripheral roles may function as a GATT server,
however in most cases it will be more common for a peripheral device to act
as the server.
Characteristics and descriptors have a default maximum size of 20 bytes.
Anything written to them by a client will be truncated to this length. However,
any local write will increase the maximum size, so if you want to allow larger
writes from a client to a given characteristic, use
:meth:`gatts_write` after registration. e.g.
``gatts_write(char_handle, bytes(100))``.
"""
def gatts_notify(self, value_handle: memoryview, data: bytes, /) -> None:
"""
Sends a notification request to a connected client.
If *data* is not ``None``, then that value is sent to the client as part of
the notification. The local value will not be modified.
Otherwise, if *data* is ``None``, then the current local value (as
set with :meth:`gatts_write `) will be sent.
**Note:** The notification will be sent regardless of the subscription
status of the client to this characteristic.
GATT Server
-----------
A GATT server has a set of registered services. Each service may contain
characteristics, which each have a value. Characteristics can also contain
descriptors, which themselves have values.
These values are stored locally, and are accessed by their "value handle" which
is generated during service registration. They can also be read from or written
to by a remote client device. Additionally, a server can "notify" a
characteristic to a connected client via a connection handle.
A device in either central or peripheral roles may function as a GATT server,
however in most cases it will be more common for a peripheral device to act
as the server.
Characteristics and descriptors have a default maximum size of 20 bytes.
Anything written to them by a client will be truncated to this length. However,
any local write will increase the maximum size, so if you want to allow larger
writes from a client to a given characteristic, use
:meth:`gatts_write` after registration. e.g.
``gatts_write(char_handle, bytes(100))``.
"""
def gatts_indicate(
self, conn_handle: memoryview, value_handle: memoryview, /
) -> None:
"""
Sends an indication request containing the characteristic's current value to
a connected client.
On acknowledgment (or failure, e.g. timeout), the
``_IRQ_GATTS_INDICATE_DONE`` event will be raised.
**Note:** The indication will be sent regardless of the subscription
status of the client to this characteristic.
GATT Server
-----------
A GATT server has a set of registered services. Each service may contain
characteristics, which each have a value. Characteristics can also contain
descriptors, which themselves have values.
These values are stored locally, and are accessed by their "value handle" which
is generated during service registration. They can also be read from or written
to by a remote client device. Additionally, a server can "notify" a
characteristic to a connected client via a connection handle.
A device in either central or peripheral roles may function as a GATT server,
however in most cases it will be more common for a peripheral device to act
as the server.
Characteristics and descriptors have a default maximum size of 20 bytes.
Anything written to them by a client will be truncated to this length. However,
any local write will increase the maximum size, so if you want to allow larger
writes from a client to a given characteristic, use
:meth:`gatts_write` after registration. e.g.
``gatts_write(char_handle, bytes(100))``.
"""
def gatts_set_buffer(
self, conn_handle: memoryview, len: int, append: bool = False, /
) -> None:
"""
Sets the internal buffer size for a value in bytes. This will limit the
largest possible write that can be received. The default is 20.
Setting *append* to ``True`` will make all remote writes append to, rather
than replace, the current value. At most *len* bytes can be buffered in
this way. When you use :meth:`gatts_read `, the value will
be cleared after reading. This feature is useful when implementing something
like the Nordic UART Service.
GATT Server
-----------
A GATT server has a set of registered services. Each service may contain
characteristics, which each have a value. Characteristics can also contain
descriptors, which themselves have values.
These values are stored locally, and are accessed by their "value handle" which
is generated during service registration. They can also be read from or written
to by a remote client device. Additionally, a server can "notify" a
characteristic to a connected client via a connection handle.
A device in either central or peripheral roles may function as a GATT server,
however in most cases it will be more common for a peripheral device to act
as the server.
Characteristics and descriptors have a default maximum size of 20 bytes.
Anything written to them by a client will be truncated to this length. However,
any local write will increase the maximum size, so if you want to allow larger
writes from a client to a given characteristic, use
:meth:`gatts_write` after registration. e.g.
``gatts_write(char_handle, bytes(100))``.
"""
def gattc_discover_services(
self, conn_handle: memoryview, uuid: UUID | None = None, /
) -> None:
"""
Query a connected server for its services.
Optionally specify a service *uuid* to query for that service only.
For each service discovered, the ``_IRQ_GATTC_SERVICE_RESULT`` event will
be raised, followed by ``_IRQ_GATTC_SERVICE_DONE`` on completion.
GATT Client
-----------
A GATT client can discover and read/write characteristics on a remote GATT server.
It is more common for a central role device to act as the GATT client, however
it's also possible for a peripheral to act as a client in order to discover
information about the central that has connected to it (e.g. to read the
device name from the device information service).
"""
def gattc_discover_characteristics(
self,
conn_handle: memoryview,
start_handle: int,
end_handle: int,
uuid: UUID | None = None,
/,
) -> None:
"""
Query a connected server for characteristics in the specified range.
Optionally specify a characteristic *uuid* to query for that
characteristic only.
You can use ``start_handle=1``, ``end_handle=0xffff`` to search for a
characteristic in any service.
For each characteristic discovered, the ``_IRQ_GATTC_CHARACTERISTIC_RESULT``
event will be raised, followed by ``_IRQ_GATTC_CHARACTERISTIC_DONE`` on completion.
GATT Client
-----------
A GATT client can discover and read/write characteristics on a remote GATT server.
It is more common for a central role device to act as the GATT client, however
it's also possible for a peripheral to act as a client in order to discover
information about the central that has connected to it (e.g. to read the
device name from the device information service).
"""
def gattc_discover_descriptors(
self, conn_handle: memoryview, start_handle: int, end_handle: int, /
) -> None:
"""
Query a connected server for descriptors in the specified range.
For each descriptor discovered, the ``_IRQ_GATTC_DESCRIPTOR_RESULT`` event
will be raised, followed by ``_IRQ_GATTC_DESCRIPTOR_DONE`` on completion.
GATT Client
-----------
A GATT client can discover and read/write characteristics on a remote GATT server.
It is more common for a central role device to act as the GATT client, however
it's also possible for a peripheral to act as a client in order to discover
information about the central that has connected to it (e.g. to read the
device name from the device information service).
"""
def gattc_read(self, conn_handle: memoryview, value_handle: memoryview, /) -> None:
"""
Issue a remote read to a connected server for the specified
characteristic or descriptor handle.
When a value is available, the ``_IRQ_GATTC_READ_RESULT`` event will be
raised. Additionally, the ``_IRQ_GATTC_READ_DONE`` will be raised.
GATT Client
-----------
A GATT client can discover and read/write characteristics on a remote GATT server.
It is more common for a central role device to act as the GATT client, however
it's also possible for a peripheral to act as a client in order to discover
information about the central that has connected to it (e.g. to read the
device name from the device information service).
"""
def gattc_write(
self,
conn_handle: memoryview,
value_handle: memoryview,
data: bytes,
mode: int = 0,
/,
) -> None:
"""
Issue a remote write to a connected server for the specified
characteristic or descriptor handle.
The argument *mode* specifies the write behaviour, with the currently
supported values being:
* ``mode=0`` (default) is a write-without-response: the write will
be sent to the remote server but no confirmation will be
returned, and no event will be raised.
* ``mode=1`` is a write-with-response: the remote server is
requested to send a response/acknowledgement that it received the
data.
If a response is received from the remote server the
``_IRQ_GATTC_WRITE_DONE`` event will be raised.
GATT Client
-----------
A GATT client can discover and read/write characteristics on a remote GATT server.
It is more common for a central role device to act as the GATT client, however
it's also possible for a peripheral to act as a client in order to discover
information about the central that has connected to it (e.g. to read the
device name from the device information service).
"""
def gattc_exchange_mtu(self, conn_handle: memoryview, /) -> None:
"""
Initiate MTU exchange with a connected server, using the preferred MTU
set using ``BLE.config(mtu=value)``.
The ``_IRQ_MTU_EXCHANGED`` event will be raised when MTU exchange
completes.
**Note:** MTU exchange is typically initiated by the central. When using
the BlueKitchen stack in the central role, it does not support a remote
peripheral initiating the MTU exchange. NimBLE works for both roles.
GATT Client
-----------
A GATT client can discover and read/write characteristics on a remote GATT server.
It is more common for a central role device to act as the GATT client, however
it's also possible for a peripheral to act as a client in order to discover
information about the central that has connected to it (e.g. to read the
device name from the device information service).
"""
def l2cap_listen(self, psm: memoryview, mtu: memoryview, /) -> None:
"""
Start listening for incoming L2CAP channel requests on the specified *psm*
with the local MTU set to *mtu*.
When a remote device initiates a connection, the ``_IRQ_L2CAP_ACCEPT``
event will be raised, which gives the listening server a chance to reject
the incoming connection (by returning a non-zero integer).
Once the connection is accepted, the ``_IRQ_L2CAP_CONNECT`` event will be
raised, allowing the server to obtain the channel id (CID) and the local and
remote MTU.
**Note:** It is not currently possible to stop listening.
L2CAP connection-oriented-channels
----------------------------------
This feature allows for socket-like data exchange between two BLE devices.
Once the devices are connected via GAP, either device can listen for the
other to connect on a numeric PSM (Protocol/Service Multiplexer).
**Note:** This is currently only supported when using the NimBLE stack on
STM32 and Unix (not ESP32). Only one L2CAP channel may be active at a given
time (i.e. you cannot connect while listening).
Active L2CAP channels are identified by the connection handle that they were
established on and a CID (channel ID).
Connection-oriented channels have built-in credit-based flow control. Unlike
ATT, where devices negotiate a shared MTU, both the listening and connecting
devices each set an independent MTU which limits the maximum amount of
outstanding data that the remote device can send before it is fully consumed
in :meth:`l2cap_recvinto `.
"""
def l2cap_connect(
self, conn_handle: memoryview, psm: memoryview, mtu: memoryview, /
) -> None:
"""
Connect to a listening peer on the specified *psm* with local MTU set to *mtu*.
On successful connection, the the ``_IRQ_L2CAP_CONNECT`` event will be
raised, allowing the client to obtain the CID and the local and remote (peer) MTU.
An unsuccessful connection will raise the ``_IRQ_L2CAP_DISCONNECT`` event
with a non-zero status.
L2CAP connection-oriented-channels
----------------------------------
This feature allows for socket-like data exchange between two BLE devices.
Once the devices are connected via GAP, either device can listen for the
other to connect on a numeric PSM (Protocol/Service Multiplexer).
**Note:** This is currently only supported when using the NimBLE stack on
STM32 and Unix (not ESP32). Only one L2CAP channel may be active at a given
time (i.e. you cannot connect while listening).
Active L2CAP channels are identified by the connection handle that they were
established on and a CID (channel ID).
Connection-oriented channels have built-in credit-based flow control. Unlike
ATT, where devices negotiate a shared MTU, both the listening and connecting
devices each set an independent MTU which limits the maximum amount of
outstanding data that the remote device can send before it is fully consumed
in :meth:`l2cap_recvinto `.
"""
def l2cap_disconnect(self, conn_handle: memoryview, cid: memoryview, /) -> None:
"""
Disconnect an active L2CAP channel with the specified *conn_handle* and
*cid*.
L2CAP connection-oriented-channels
----------------------------------
This feature allows for socket-like data exchange between two BLE devices.
Once the devices are connected via GAP, either device can listen for the
other to connect on a numeric PSM (Protocol/Service Multiplexer).
**Note:** This is currently only supported when using the NimBLE stack on
STM32 and Unix (not ESP32). Only one L2CAP channel may be active at a given
time (i.e. you cannot connect while listening).
Active L2CAP channels are identified by the connection handle that they were
established on and a CID (channel ID).
Connection-oriented channels have built-in credit-based flow control. Unlike
ATT, where devices negotiate a shared MTU, both the listening and connecting
devices each set an independent MTU which limits the maximum amount of
outstanding data that the remote device can send before it is fully consumed
in :meth:`l2cap_recvinto `.
"""
def l2cap_send(self, conn_handle: memoryview, cid: memoryview, /) -> None:
"""
Send the specified *buf* (which must support the buffer protocol) on the
L2CAP channel identified by *conn_handle* and *cid*.
The specified buffer cannot be larger than the remote (peer) MTU, and no
more than twice the size of the local MTU.
This will return ``False`` if the channel is now "stalled", which means that
:meth:`l2cap_send ` must not be called again until the
``_IRQ_L2CAP_SEND_READY`` event is received (which will happen when the
remote device grants more credits, typically after it has received and
processed the data).
L2CAP connection-oriented-channels
----------------------------------
This feature allows for socket-like data exchange between two BLE devices.
Once the devices are connected via GAP, either device can listen for the
other to connect on a numeric PSM (Protocol/Service Multiplexer).
**Note:** This is currently only supported when using the NimBLE stack on
STM32 and Unix (not ESP32). Only one L2CAP channel may be active at a given
time (i.e. you cannot connect while listening).
Active L2CAP channels are identified by the connection handle that they were
established on and a CID (channel ID).
Connection-oriented channels have built-in credit-based flow control. Unlike
ATT, where devices negotiate a shared MTU, both the listening and connecting
devices each set an independent MTU which limits the maximum amount of
outstanding data that the remote device can send before it is fully consumed
in :meth:`l2cap_recvinto `.
"""
def l2cap_recvinto(
self, conn_handle: memoryview, cid: memoryview, buf: AnyWritableBuf | None, /
) -> int:
"""
Receive data from the specified *conn_handle* and *cid* into the provided
*buf* (which must support the buffer protocol, e.g. bytearray or
memoryview).
Returns the number of bytes read from the channel.
If *buf* is None, then returns the number of bytes available.
**Note:** After receiving the ``_IRQ_L2CAP_RECV`` event, the application should
continue calling :meth:`l2cap_recvinto ` until no more
bytes are available in the receive buffer (typically up to the size of the
remote (peer) MTU).
Until the receive buffer is empty, the remote device will not be granted
more channel credits and will be unable to send any more data.
L2CAP connection-oriented-channels
----------------------------------
This feature allows for socket-like data exchange between two BLE devices.
Once the devices are connected via GAP, either device can listen for the
other to connect on a numeric PSM (Protocol/Service Multiplexer).
**Note:** This is currently only supported when using the NimBLE stack on
STM32 and Unix (not ESP32). Only one L2CAP channel may be active at a given
time (i.e. you cannot connect while listening).
Active L2CAP channels are identified by the connection handle that they were
established on and a CID (channel ID).
Connection-oriented channels have built-in credit-based flow control. Unlike
ATT, where devices negotiate a shared MTU, both the listening and connecting
devices each set an independent MTU which limits the maximum amount of
outstanding data that the remote device can send before it is fully consumed
in :meth:`l2cap_recvinto `.
"""
def gap_pair(self, conn_handle: memoryview, /) -> None:
"""
Initiate pairing with the remote device.
Before calling this, ensure that the ``io``, ``mitm``, ``le_secure``, and
``bond`` configuration options are set (via :meth:`config`).
On successful pairing, the ``_IRQ_ENCRYPTION_UPDATE`` event will be raised.
Pairing and bonding
-------------------
Pairing allows a connection to be encrypted and authenticated via exchange
of secrets (with optional MITM protection via passkey authentication).
Bonding is the process of storing those secrets into non-volatile storage.
When bonded, a device is able to resolve a resolvable private address (RPA)
from another device based on the stored identity resolving key (IRK).
To support bonding, an application must implement the ``_IRQ_GET_SECRET``
and ``_IRQ_SET_SECRET`` events.
**Note:** This is currently only supported when using the NimBLE stack on
STM32 and Unix (not ESP32).
"""
def gap_passkey(
self, conn_handle: memoryview, action: int, passkey: int, /
) -> None:
"""
Respond to a ``_IRQ_PASSKEY_ACTION`` event for the specified *conn_handle*
and *action*.
The *passkey* is a numeric value and will depend on on the
*action* (which will depend on what I/O capability has been set):
* When the *action* is ``_PASSKEY_ACTION_INPUT``, then the application should
prompt the user to enter the passkey that is shown on the remote device.
* When the *action* is ``_PASSKEY_ACTION_DISPLAY``, then the application should
generate a random 6-digit passkey and show it to the user.
* When the *action* is ``_PASSKEY_ACTION_NUMERIC_COMPARISON``, then the application
should show the passkey that was provided in the ``_IRQ_PASSKEY_ACTION`` event
and then respond with either ``0`` (cancel pairing), or ``1`` (accept pairing).
Pairing and bonding
-------------------
Pairing allows a connection to be encrypted and authenticated via exchange
of secrets (with optional MITM protection via passkey authentication).
Bonding is the process of storing those secrets into non-volatile storage.
When bonded, a device is able to resolve a resolvable private address (RPA)
from another device based on the stored identity resolving key (IRK).
To support bonding, an application must implement the ``_IRQ_GET_SECRET``
and ``_IRQ_SET_SECRET`` events.
**Note:** This is currently only supported when using the NimBLE stack on
STM32 and Unix (not ESP32).
"""
class UUID:
"""
class UUID
----------
"""
def __init__(self, value: int | str, /):
"""
Creates a UUID instance with the specified **value**.
The **value** can be either:
- A 16-bit integer. e.g. ``0x2908``.
- A 128-bit UUID string. e.g. ``'6E400001-B5A3-F393-E0A9-E50E24DCCA9E'``.
"""
================================================
FILE: typehints/micropython/btree.pyi
================================================
"""
simple BTree database.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/btree.rst.
=====================================
.. module:: btree
:synopsis: simple BTree database
The ``btree`` module implements a simple key-value database using external
storage (disk files, or in general case, a random-access `stream`). Keys are
stored sorted in the database, and besides efficient retrieval by a key
value, a database also supports efficient ordered range scans (retrieval
of values with the keys in a given range). On the application interface
side, BTree database work as close a possible to a way standard `dict`
type works, one notable difference is that both keys and values must
be `bytes` objects (so, if you want to store objects of other types, you
need to serialize them to `bytes` first).
The module is based on the well-known BerkelyDB library, version 1.xx.
Example::
import btree
# First, we need to open a stream which holds a database
# This is usually a file, but can be in-memory database
# using io.BytesIO, a raw flash partition, etc.
# Oftentimes, you want to create a database file if it doesn't
# exist and open if it exists. Idiom below takes care of this.
# DO NOT open database with "a+b" access mode.
try:
f = open("mydb", "r+b")
except OSError:
f = open("mydb", "w+b")
# Now open a database itself
db = btree.open(f)
# The keys you add will be sorted internally in the database
db[b"3"] = b"three"
db[b"1"] = b"one"
db[b"2"] = b"two"
# Assume that any changes are cached in memory unless
# explicitly flushed (or database closed). Flush database
# at the end of each "transaction".
db.flush()
# Prints b'two'
print(db[b"2"])
# Iterate over sorted keys in the database, starting from b"2"
# until the end of the database, returning only values.
# Mind that arguments passed to values() method are *key* values.
# Prints:
# b'two'
# b'three'
for word in db.values(b"2"):
print(word)
del db[b"2"]
# No longer true, prints False
print(b"2" in db)
# Prints:
# b"1"
# b"3"
for key in db:
print(key)
db.close()
# Don't forget to close the underlying stream!
f.close()
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import Any, Final, Iterable
from uio import IOBase
def open(
stream: IOBase[bytes, Any],
/,
*,
flags: int = 0,
pagesize: int = 0,
cachesize: int = 0,
minkeypage: int = 0,
) -> _BTree:
"""
Open a database from a random-access `stream` (like an open file). All
other parameters are optional and keyword-only, and allow to tweak advanced
parameters of the database operation (most users will not need them):
* *flags* - Currently unused.
* *pagesize* - Page size used for the nodes in BTree. Acceptable range
is 512-65536. If 0, a port-specific default will be used, optimized for
port's memory usage and/or performance.
* *cachesize* - Suggested memory cache size in bytes. For a
board with enough memory using larger values may improve performance.
Cache policy is as follows: entire cache is not allocated at once;
instead, accessing a new page in database will allocate a memory buffer
for it, until value specified by *cachesize* is reached. Then, these
buffers will be managed using LRU (least recently used) policy. More
buffers may still be allocated if needed (e.g., if a database contains
big keys and/or values). Allocated cache buffers aren't reclaimed.
* *minkeypage* - Minimum number of keys to store per page. Default value
of 0 equivalent to 2.
Returns a BTree object, which implements a dictionary protocol (set
of methods), and some additional methods described below.
"""
INCL: Final[int] = ...
"""
A flag for `keys()`, `values()`, `items()` methods to specify that
scanning should be inclusive of the end key.
"""
DESC: Final[int] = ...
"""
A flag for `keys()`, `values()`, `items()` methods to specify that
scanning should be in descending direction of keys.
"""
class _BTree:
"""
"""
def close(self) -> None:
"""
Close the database. It's mandatory to close the database at the end of
processing, as some unwritten data may be still in the cache. Note that
this does not close underlying stream with which the database was opened,
it should be closed separately (which is also mandatory to make sure that
data flushed from buffer to the underlying storage).
"""
def flush(self) -> None:
"""
Flush any data in cache to the underlying stream.
"""
def __getitem__(self, key: bytes, /) -> bytes:
"""
Standard dictionary methods.
"""
def get(self, key: bytes, default: bytes | None = None, /) -> bytes | None:
"""
Standard dictionary methods.
"""
def __setitem__(self, key: bytes, val: bytes, /) -> None:
"""
Standard dictionary methods.
"""
def __delitem__(self, key: bytes, /) -> None:
"""
Standard dictionary methods.
"""
def __contains__(self, key: bytes, /) -> bool:
"""
Standard dictionary methods.
"""
def __iter__(self) -> Iterable[bytes]:
"""
A BTree object can be iterated over directly (similar to a dictionary)
to get access to all keys in order.
"""
def keys(
self,
start_key: bytes | None = None,
end_key: bytes | None = None,
flags: int = 0,
/,
) -> Iterable[bytes]:
"""
These methods are similar to standard dictionary methods, but also can
take optional parameters to iterate over a key sub-range, instead of
the entire database. Note that for all 3 methods, *start_key* and
*end_key* arguments represent key values. For example, `values()`
method will iterate over values corresponding to they key range
given. None values for *start_key* means "from the first key", no
*end_key* or its value of None means "until the end of database".
By default, range is inclusive of *start_key* and exclusive of
*end_key*, you can include *end_key* in iteration by passing *flags*
of `btree.INCL`. You can iterate in descending key direction
by passing *flags* of `btree.DESC`. The flags values can be ORed
together.
"""
def values(
self,
start_key: bytes | None = None,
end_key: bytes | None = None,
flags: int = 0,
/,
) -> Iterable[bytes]:
"""
These methods are similar to standard dictionary methods, but also can
take optional parameters to iterate over a key sub-range, instead of
the entire database. Note that for all 3 methods, *start_key* and
*end_key* arguments represent key values. For example, `values()`
method will iterate over values corresponding to they key range
given. None values for *start_key* means "from the first key", no
*end_key* or its value of None means "until the end of database".
By default, range is inclusive of *start_key* and exclusive of
*end_key*, you can include *end_key* in iteration by passing *flags*
of `btree.INCL`. You can iterate in descending key direction
by passing *flags* of `btree.DESC`. The flags values can be ORed
together.
"""
def items(
self,
start_key: bytes | None = None,
end_key: bytes | None = None,
flags: int = 0,
/,
) -> Iterable[tuple[bytes, bytes]]:
"""
These methods are similar to standard dictionary methods, but also can
take optional parameters to iterate over a key sub-range, instead of
the entire database. Note that for all 3 methods, *start_key* and
*end_key* arguments represent key values. For example, `values()`
method will iterate over values corresponding to they key range
given. None values for *start_key* means "from the first key", no
*end_key* or its value of None means "until the end of database".
By default, range is inclusive of *start_key* and exclusive of
*end_key*, you can include *end_key* in iteration by passing *flags*
of `btree.INCL`. You can iterate in descending key direction
by passing *flags* of `btree.DESC`. The flags values can be ORed
together.
"""
================================================
FILE: typehints/micropython/cryptolib.pyi
================================================
"""
cryptographic ciphers.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/cryptolib.rst.
=========================================
.. module:: cryptolib
:synopsis: cryptographic ciphers
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import overload
from uio import AnyReadableBuf, AnyWritableBuf
# noinspection PyPep8Naming
class aes:
"""
.. class:: aes
"""
@overload
def __init__(self, key: AnyReadableBuf, mode: int, /):
"""
Initialize cipher object, suitable for encryption/decryption. Note:
after initialization, cipher object can be use only either for
encryption or decryption. Running decrypt() operation after encrypt()
or vice versa is not supported.
Parameters are:
* *key* is an encryption/decryption key (bytes-like).
* *mode* is:
* ``1`` (or ``cryptolib.MODE_ECB`` if it exists) for Electronic Code Book (ECB).
* ``2`` (or ``cryptolib.MODE_CBC`` if it exists) for Cipher Block Chaining (CBC).
* ``6`` (or ``cryptolib.MODE_CTR`` if it exists) for Counter mode (CTR).
* *IV* is an initialization vector for CBC mode.
* For Counter mode, *IV* is the initial value for the counter.
"""
@overload
def __init__(self, key: AnyReadableBuf, mode: int, IV: AnyReadableBuf, /):
"""
Initialize cipher object, suitable for encryption/decryption. Note:
after initialization, cipher object can be use only either for
encryption or decryption. Running decrypt() operation after encrypt()
or vice versa is not supported.
Parameters are:
* *key* is an encryption/decryption key (bytes-like).
* *mode* is:
* ``1`` (or ``cryptolib.MODE_ECB`` if it exists) for Electronic Code Book (ECB).
* ``2`` (or ``cryptolib.MODE_CBC`` if it exists) for Cipher Block Chaining (CBC).
* ``6`` (or ``cryptolib.MODE_CTR`` if it exists) for Counter mode (CTR).
* *IV* is an initialization vector for CBC mode.
* For Counter mode, *IV* is the initial value for the counter.
"""
@overload
def encrypt(self, in_buf: AnyReadableBuf, /) -> bytes:
"""
Encrypt *in_buf*. If no *out_buf* is given result is returned as a
newly allocated `bytes` object. Otherwise, result is written into
mutable buffer *out_buf*. *in_buf* and *out_buf* can also refer
to the same mutable buffer, in which case data is encrypted in-place.
"""
@overload
def encrypt(self, in_buf: AnyReadableBuf, out_buf: AnyWritableBuf, /) -> None:
"""
Encrypt *in_buf*. If no *out_buf* is given result is returned as a
newly allocated `bytes` object. Otherwise, result is written into
mutable buffer *out_buf*. *in_buf* and *out_buf* can also refer
to the same mutable buffer, in which case data is encrypted in-place.
"""
@overload
def decrypt(self, in_buf: AnyReadableBuf, /) -> bytes:
"""
Like `encrypt()`, but for decryption.
"""
@overload
def decrypt(self, in_buf: AnyReadableBuf, out_buf: AnyWritableBuf, /) -> None:
"""
Like `encrypt()`, but for decryption.
"""
================================================
FILE: typehints/micropython/framebuf.pyi
================================================
"""
Frame buffer manipulation.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/framebuf.rst.
This module provides a general frame buffer which can be used to create
bitmap images, which can then be sent to a display.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import overload, Final
from uio import AnyWritableBuf
MONO_VLSB: Final[int] = ...
"""
Monochrome (1-bit) color format
This defines a mapping where the bits in a byte are vertically mapped with
bit 0 being nearest the top of the screen. Consequently each byte occupies
8 vertical pixels. Subsequent bytes appear at successive horizontal
locations until the rightmost edge is reached. Further bytes are rendered
at locations starting at the leftmost edge, 8 pixels lower.
"""
MONO_HLSB: Final[int] = ...
"""
Monochrome (1-bit) color format
This defines a mapping where the bits in a byte are horizontally mapped.
Each byte occupies 8 horizontal pixels with bit 7 being the leftmost.
Subsequent bytes appear at successive horizontal locations until the
rightmost edge is reached. Further bytes are rendered on the next row, one
pixel lower.
"""
MONO_HMSB: Final[int] = ...
"""
Monochrome (1-bit) color format
This defines a mapping where the bits in a byte are horizontally mapped.
Each byte occupies 8 horizontal pixels with bit 0 being the leftmost.
Subsequent bytes appear at successive horizontal locations until the
rightmost edge is reached. Further bytes are rendered on the next row, one
pixel lower.
"""
RGB565: Final[int] = ...
"""
Red Green Blue (16-bit, 5+6+5) color format
"""
GS2_HMSB: Final[int] = ...
"""
Grayscale (2-bit) color format
"""
GS4_HMSB: Final[int] = ...
"""
Grayscale (4-bit) color format
"""
GS8: Final[int] = ...
"""
Grayscale (8-bit) color format
"""
class FrameBuffer:
"""
The FrameBuffer class provides a pixel buffer which can be drawn upon with
pixels, lines, rectangles, text and even other FrameBuffer's. It is useful
when generating output for displays.
For example::
import framebuf
# FrameBuffer needs 2 bytes for every RGB565 pixel
fbuf = framebuf.FrameBuffer(bytearray(10 * 100 * 2), 10, 100, framebuf.RGB565)
fbuf.fill(0)
fbuf.text('MicroPython!', 0, 0, 0xffff)
fbuf.hline(0, 10, 96, 0xffff)
"""
def __init__(
self,
buffer: AnyWritableBuf,
width: int,
height: int,
format: int,
stride: int = ...,
/,
):
"""
Construct a FrameBuffer object. The parameters are:
- *buffer* is an object with a buffer protocol which must be large
enough to contain every pixel defined by the width, height and
format of the FrameBuffer.
- *width* is the width of the FrameBuffer in pixels
- *height* is the height of the FrameBuffer in pixels
- *format* specifies the type of pixel used in the FrameBuffer;
permissible values are listed under Constants below. These set the
number of bits used to encode a color value and the layout of these
bits in *buffer*.
Where a color value c is passed to a method, c is a small integer
with an encoding that is dependent on the format of the FrameBuffer.
- *stride* is the number of pixels between each horizontal line
of pixels in the FrameBuffer. This defaults to *width* but may
need adjustments when implementing a FrameBuffer within another
larger FrameBuffer or screen. The *buffer* size must accommodate
an increased step size.
One must specify valid *buffer*, *width*, *height*, *format* and
optionally *stride*. Invalid *buffer* size or dimensions may lead to
unexpected errors.
"""
def fill(self, c: int, /) -> None:
"""
Fill the entire FrameBuffer with the specified color.
"""
@overload
def pixel(self, x: int, y: int, /) -> int:
"""
If *c* is not given, get the color value of the specified pixel.
If *c* is given, set the specified pixel to the given color.
"""
@overload
def pixel(self, x: int, y: int, c: int, /) -> None:
"""
If *c* is not given, get the color value of the specified pixel.
If *c* is given, set the specified pixel to the given color.
"""
def hline(self, x: int, y: int, w: int, c: int, /) -> None:
"""
Draw a line from a set of coordinates using the given color and
a thickness of 1 pixel. The `line` method draws the line up to
a second set of coordinates whereas the `hline` and `vline`
methods draw horizontal and vertical lines respectively up to
a given length.
"""
def vline(self, x: int, y: int, h: int, c: int, /) -> None:
"""
Draw a line from a set of coordinates using the given color and
a thickness of 1 pixel. The `line` method draws the line up to
a second set of coordinates whereas the `hline` and `vline`
methods draw horizontal and vertical lines respectively up to
a given length.
"""
def line(self, x1: int, y1: int, x2: int, y2: int, c: int, /) -> None:
"""
Draw a line from a set of coordinates using the given color and
a thickness of 1 pixel. The `line` method draws the line up to
a second set of coordinates whereas the `hline` and `vline`
methods draw horizontal and vertical lines respectively up to
a given length.
"""
def rect(self, x: int, y: int, w: int, h: int, c: int, /) -> None:
"""
Draw a rectangle at the given location, size and color. The `rect`
method draws only a 1 pixel outline whereas the `fill_rect` method
draws both the outline and interior.
"""
def fill_rect(self, x: int, y: int, w: int, h: int, c: int, /) -> None:
"""
Draw a rectangle at the given location, size and color. The `rect`
method draws only a 1 pixel outline whereas the `fill_rect` method
draws both the outline and interior.
"""
def text(self, s: str, x: int, y: int, c: int = 1, /) -> None:
"""
Write text to the FrameBuffer using the the coordinates as the upper-left
corner of the text. The color of the text can be defined by the optional
argument but is otherwise a default value of 1. All characters have
dimensions of 8x8 pixels and there is currently no way to change the font.
"""
def scroll(self, xstep: int, ystep: int, /) -> None:
"""
Shift the contents of the FrameBuffer by the given vector. This may
leave a footprint of the previous colors in the FrameBuffer.
"""
def blit(
self,
fbuf: FrameBuffer,
x: int,
y: int,
key: int = -1,
pallet: FrameBuffer | None = None,
/,
) -> None:
"""
Draw another FrameBuffer on top of the current one at the given coordinates.
If *key* is specified then it should be a color integer and the
corresponding color will be considered transparent: all pixels with that
color value will not be drawn.
The *palette* argument enables blitting between FrameBuffers with differing
formats. Typical usage is to render a monochrome or grayscale glyph/icon to
a color display. The *palette* is a FrameBuffer instance whose format is
that of the current FrameBuffer. The *palette* height is one pixel and its
pixel width is the number of colors in the source FrameBuffer. The *palette*
for an N-bit source needs 2**N pixels; the *palette* for a monochrome source
would have 2 pixels representing background and foreground colors. The
application assigns a color to each pixel in the *palette*. The color of the
current pixel will be that of that *palette* pixel whose x position is the
color of the corresponding source pixel.
"""
================================================
FILE: typehints/micropython/machine.pyi
================================================
"""
functions related to the hardware.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/machine.rst.
====================================================
.. module:: machine
:synopsis: functions related to the hardware
The ``machine`` module contains specific functions related to the hardware
on a particular board. Most functions in this module allow to achieve direct
and unrestricted access to and control of hardware blocks on a system
(like CPU, timers, buses, etc.). Used incorrectly, this can lead to
malfunction, lockups, crashes of your board, and in extreme cases, hardware
damage.
.. _machine_callbacks:
A note of callbacks used by functions and class methods of :mod:`machine` module:
all these callbacks should be considered as executing in an interrupt context.
This is true for both physical devices with IDs >= 0 and "virtual" devices
with negative IDs like -1 (these "virtual" devices are still thin shims on
top of real hardware and real hardware interrupts). See :ref:`isr_rules`.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import overload, NoReturn, Callable
from typing import Sequence, ClassVar, Any, Final
from uos import AbstractBlockDev
from uio import AnyReadableBuf, AnyWritableBuf
def reset() -> NoReturn:
"""
Resets the device in a manner similar to pushing the external RESET
button.
"""
def soft_reset() -> NoReturn:
"""
Performs a soft reset of the interpreter, deleting all Python objects and
resetting the Python heap. It tries to retain the method by which the user
is connected to the MicroPython REPL (eg serial, USB, Wifi).
"""
def reset_cause() -> int:
"""
Get the reset cause. See :ref:`constants ` for the possible return values.
"""
def disable_irq() -> bool:
"""
Disable interrupt requests.
Returns the previous IRQ state which should be considered an opaque value.
This return value should be passed to the `enable_irq()` function to restore
interrupts to their original state, before `disable_irq()` was called.
"""
def enable_irq(state: bool = True, /) -> None:
"""
Re-enable interrupt requests.
The *state* parameter should be the value that was returned from the most
recent call to the `disable_irq()` function.
"""
@overload
def freq() -> int:
"""
Returns the CPU frequency in hertz.
On some ports this can also be used to set the CPU frequency by passing in *hz*.
"""
@overload
def freq(hz: int, /) -> None:
"""
Returns the CPU frequency in hertz.
On some ports this can also be used to set the CPU frequency by passing in *hz*.
"""
def idle() -> None:
"""
Gates the clock to the CPU, useful to reduce power consumption at any time during
short or long periods. Peripherals continue working and execution resumes as soon
as any interrupt is triggered (on many ports this includes system timer
interrupt occurring at regular intervals on the order of millisecond).
"""
def sleep() -> None:
"""
.. note:: This function is deprecated, use `lightsleep()` instead with no arguments.
"""
@overload
def lightsleep() -> None:
"""
Stops execution in an attempt to enter a low power state.
If *time_ms* is specified then this will be the maximum time in milliseconds that
the sleep will last for. Otherwise the sleep can last indefinitely.
With or without a timeout, execution may resume at any time if there are events
that require processing. Such events, or wake sources, should be configured before
sleeping, like `Pin` change or `RTC` timeout.
The precise behaviour and power-saving capabilities of lightsleep and deepsleep is
highly dependent on the underlying hardware, but the general properties are:
* A lightsleep has full RAM and state retention. Upon wake execution is resumed
from the point where the sleep was requested, with all subsystems operational.
* A deepsleep may not retain RAM or any other state of the system (for example
peripherals or network interfaces). Upon wake execution is resumed from the main
script, similar to a hard or power-on reset. The `reset_cause()` function will
return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake
from other resets.
"""
@overload
def lightsleep(time_ms: int, /) -> None:
"""
Stops execution in an attempt to enter a low power state.
If *time_ms* is specified then this will be the maximum time in milliseconds that
the sleep will last for. Otherwise the sleep can last indefinitely.
With or without a timeout, execution may resume at any time if there are events
that require processing. Such events, or wake sources, should be configured before
sleeping, like `Pin` change or `RTC` timeout.
The precise behaviour and power-saving capabilities of lightsleep and deepsleep is
highly dependent on the underlying hardware, but the general properties are:
* A lightsleep has full RAM and state retention. Upon wake execution is resumed
from the point where the sleep was requested, with all subsystems operational.
* A deepsleep may not retain RAM or any other state of the system (for example
peripherals or network interfaces). Upon wake execution is resumed from the main
script, similar to a hard or power-on reset. The `reset_cause()` function will
return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake
from other resets.
"""
@overload
def deepsleep() -> NoReturn:
"""
Stops execution in an attempt to enter a low power state.
If *time_ms* is specified then this will be the maximum time in milliseconds that
the sleep will last for. Otherwise the sleep can last indefinitely.
With or without a timeout, execution may resume at any time if there are events
that require processing. Such events, or wake sources, should be configured before
sleeping, like `Pin` change or `RTC` timeout.
The precise behaviour and power-saving capabilities of lightsleep and deepsleep is
highly dependent on the underlying hardware, but the general properties are:
* A lightsleep has full RAM and state retention. Upon wake execution is resumed
from the point where the sleep was requested, with all subsystems operational.
* A deepsleep may not retain RAM or any other state of the system (for example
peripherals or network interfaces). Upon wake execution is resumed from the main
script, similar to a hard or power-on reset. The `reset_cause()` function will
return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake
from other resets.
"""
@overload
def deepsleep(time_ms: int, /) -> NoReturn:
"""
Stops execution in an attempt to enter a low power state.
If *time_ms* is specified then this will be the maximum time in milliseconds that
the sleep will last for. Otherwise the sleep can last indefinitely.
With or without a timeout, execution may resume at any time if there are events
that require processing. Such events, or wake sources, should be configured before
sleeping, like `Pin` change or `RTC` timeout.
The precise behaviour and power-saving capabilities of lightsleep and deepsleep is
highly dependent on the underlying hardware, but the general properties are:
* A lightsleep has full RAM and state retention. Upon wake execution is resumed
from the point where the sleep was requested, with all subsystems operational.
* A deepsleep may not retain RAM or any other state of the system (for example
peripherals or network interfaces). Upon wake execution is resumed from the main
script, similar to a hard or power-on reset. The `reset_cause()` function will
return `machine.DEEPSLEEP` and this can be used to distinguish a deepsleep wake
from other resets.
"""
def wake_reason() -> int:
"""
Get the wake reason. See :ref:`constants ` for the possible return values.
Availability: ESP32, WiPy.
"""
def unique_id() -> bytes:
"""
Returns a byte string with a unique identifier of a board/SoC. It will vary
from a board/SoC instance to another, if underlying hardware allows. Length
varies by hardware (so use substring of a full value if you expect a short
ID). In some MicroPython ports, ID corresponds to the network MAC address.
"""
def time_pulse_us(pin: Pin, pulse_level: int, timeout_us: int = 1_000_000, /) -> int:
"""
Time a pulse on the given *pin*, and return the duration of the pulse in
microseconds. The *pulse_level* argument should be 0 to time a low pulse
or 1 to time a high pulse.
If the current input value of the pin is different to *pulse_level*,
the function first (*) waits until the pin input becomes equal to *pulse_level*,
then (**) times the duration that the pin is equal to *pulse_level*.
If the pin is already equal to *pulse_level* then timing starts straight away.
The function will return -2 if there was timeout waiting for condition marked
(*) above, and -1 if there was timeout during the main measurement, marked (**)
above. The timeout is the same for both cases and given by *timeout_us* (which
is in microseconds).
"""
def rng() -> int:
"""
Return a 24-bit software generated random number.
Availability: WiPy.
"""
IDLE: Final[int] = ...
"""
IRQ wake values.
"""
SLEEP: Final[int] = ...
"""
IRQ wake values.
"""
DEEPSLEEP: Final[int] = ...
"""
IRQ wake values.
"""
PWRON_RESET: Final[int] = ...
"""
Reset causes.
"""
HARD_RESET: Final[int] = ...
"""
Reset causes.
"""
WDT_RESET: Final[int] = ...
"""
Reset causes.
"""
DEEPSLEEP_RESET: Final[int] = ...
"""
Reset causes.
"""
SOFT_RESET: Final[int] = ...
"""
Reset causes.
"""
WLAN_WAKE: Final[int] = ...
"""
Wake-up reasons.
"""
PIN_WAKE: Final[int] = ...
"""
Wake-up reasons.
"""
RTC_WAKE: Final[int] = ...
"""
Wake-up reasons.
"""
class Pin:
"""
A pin object is used to control I/O pins (also known as GPIO - general-purpose
input/output). Pin objects are commonly associated with a physical pin that can
drive an output voltage and read input voltages. The pin class has methods to set the mode of
the pin (IN, OUT, etc) and methods to get and set the digital logic level.
For analog control of a pin, see the :class:`ADC` class.
A pin object is constructed by using an identifier which unambiguously
specifies a certain I/O pin. The allowed forms of the identifier and the
physical pin that the identifier maps to are port-specific. Possibilities
for the identifier are an integer, a string or a tuple with port and pin
number.
Usage Model::
from machine import Pin
# create an output pin on pin #0
p0 = Pin(0, Pin.OUT)
# set the value low then high
p0.value(0)
p0.value(1)
# create an input pin on pin #2, with a pull up resistor
p2 = Pin(2, Pin.IN, Pin.PULL_UP)
# read and print the pin value
print(p2.value())
# reconfigure pin #0 in input mode with a pull down resistor
p0.init(p0.IN, p0.PULL_DOWN)
# configure an irq callback
p0.irq(lambda p:print(p))
"""
IN: ClassVar[int] = ...
"""
Selects the pin mode.
"""
OUT: ClassVar[int] = ...
"""
Selects the pin mode.
"""
OPEN_DRAIN: ClassVar[int] = ...
"""
Selects the pin mode.
"""
ALT: ClassVar[int] = ...
"""
Selects the pin mode.
"""
ALT_OPEN_DRAIN: ClassVar[int] = ...
"""
Selects the pin mode.
"""
PULL_UP: ClassVar[int] = ...
"""
Selects whether there is a pull up/down resistor. Use the value
``None`` for no pull.
"""
PULL_DOWN: ClassVar[int] = ...
"""
Selects whether there is a pull up/down resistor. Use the value
``None`` for no pull.
"""
PULL_HOLD: ClassVar[int] = ...
"""
Selects whether there is a pull up/down resistor. Use the value
``None`` for no pull.
"""
LOW_POWER: ClassVar[int] = ...
"""
Selects the pin drive strength.
"""
MED_POWER: ClassVar[int] = ...
"""
Selects the pin drive strength.
"""
HIGH_POWER: ClassVar[int] = ...
"""
Selects the pin drive strength.
"""
IRQ_FALLING: ClassVar[int] = ...
"""
Selects the IRQ trigger type.
"""
IRQ_RISING: ClassVar[int] = ...
"""
Selects the IRQ trigger type.
"""
IRQ_LOW_LEVEL: ClassVar[int] = ...
"""
Selects the IRQ trigger type.
"""
IRQ_HIGH_LEVEL: ClassVar[int] = ...
"""
Selects the IRQ trigger type.
"""
def __init__(
self,
id: Any,
/,
mode: int = -1,
pull: int = -1,
*,
value: Any = None,
drive: int | None = None,
alt: int | None = None,
):
"""
Access the pin peripheral (GPIO pin) associated with the given ``id``. If
additional arguments are given in the constructor then they are used to initialise
the pin. Any settings that are not specified will remain in their previous state.
The arguments are:
- ``id`` is mandatory and can be an arbitrary object. Among possible value
types are: int (an internal Pin identifier), str (a Pin name), and tuple
(pair of [port, pin]).
- ``mode`` specifies the pin mode, which can be one of:
- ``Pin.IN`` - Pin is configured for input. If viewed as an output the pin
is in high-impedance state.
- ``Pin.OUT`` - Pin is configured for (normal) output.
- ``Pin.OPEN_DRAIN`` - Pin is configured for open-drain output. Open-drain
output works in the following way: if the output value is set to 0 the pin
is active at a low level; if the output value is 1 the pin is in a high-impedance
state. Not all ports implement this mode, or some might only on certain pins.
- ``Pin.ALT`` - Pin is configured to perform an alternative function, which is
port specific. For a pin configured in such a way any other Pin methods
(except :meth:`Pin.init`) are not applicable (calling them will lead to undefined,
or a hardware-specific, result). Not all ports implement this mode.
- ``Pin.ALT_OPEN_DRAIN`` - The Same as ``Pin.ALT``, but the pin is configured as
open-drain. Not all ports implement this mode.
- ``pull`` specifies if the pin has a (weak) pull resistor attached, and can be
one of:
- ``None`` - No pull up or down resistor.
- ``Pin.PULL_UP`` - Pull up resistor enabled.
- ``Pin.PULL_DOWN`` - Pull down resistor enabled.
- ``value`` is valid only for Pin.OUT and Pin.OPEN_DRAIN modes and specifies initial
output pin value if given, otherwise the state of the pin peripheral remains
unchanged.
- ``drive`` specifies the output power of the pin and can be one of: ``Pin.LOW_POWER``,
``Pin.MED_POWER`` or ``Pin.HIGH_POWER``. The actual current driving capabilities
are port dependent. Not all ports implement this argument.
- ``alt`` specifies an alternate function for the pin and the values it can take are
port dependent. This argument is valid only for ``Pin.ALT`` and ``Pin.ALT_OPEN_DRAIN``
modes. It may be used when a pin supports more than one alternate function. If only
one pin alternate function is supported the this argument is not required. Not all
ports implement this argument.
As specified above, the Pin class allows to set an alternate function for a particular
pin, but it does not specify any further operations on such a pin. Pins configured in
alternate-function mode are usually not used as GPIO but are instead driven by other
hardware peripherals. The only operation supported on such a pin is re-initialising,
by calling the constructor or :meth:`Pin.init` method. If a pin that is configured in
alternate-function mode is re-initialised with ``Pin.IN``, ``Pin.OUT``, or
``Pin.OPEN_DRAIN``, the alternate function will be removed from the pin.
"""
def init(
self,
mode: int = -1,
pull: int = -1,
*,
value: Any = None,
drive: int | None = None,
alt: int | None = None,
) -> None:
"""
Re-initialise the pin using the given parameters. Only those arguments that
are specified will be set. The rest of the pin peripheral state will remain
unchanged. See the constructor documentation for details of the arguments.
Returns ``None``.
"""
@overload
def value(self) -> int:
"""
This method allows to set and get the value of the pin, depending on whether
the argument ``x`` is supplied or not.
If the argument is omitted then this method gets the digital logic level of
the pin, returning 0 or 1 corresponding to low and high voltage signals
respectively. The behaviour of this method depends on the mode of the pin:
- ``Pin.IN`` - The method returns the actual input value currently present
on the pin.
- ``Pin.OUT`` - The behaviour and return value of the method is undefined.
- ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and
return value of the method is undefined. Otherwise, if the pin is in
state '1', the method returns the actual input value currently present
on the pin.
If the argument is supplied then this method sets the digital logic level of
the pin. The argument ``x`` can be anything that converts to a boolean.
If it converts to ``True``, the pin is set to state '1', otherwise it is set
to state '0'. The behaviour of this method depends on the mode of the pin:
- ``Pin.IN`` - The value is stored in the output buffer for the pin. The
pin state does not change, it remains in the high-impedance state. The
stored value will become active on the pin as soon as it is changed to
``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode.
- ``Pin.OUT`` - The output buffer is set to the given value immediately.
- ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage
state. Otherwise the pin is set to high-impedance state.
When setting the value this method returns ``None``.
"""
@overload
def value(self, x: Any, /) -> None:
"""
This method allows to set and get the value of the pin, depending on whether
the argument ``x`` is supplied or not.
If the argument is omitted then this method gets the digital logic level of
the pin, returning 0 or 1 corresponding to low and high voltage signals
respectively. The behaviour of this method depends on the mode of the pin:
- ``Pin.IN`` - The method returns the actual input value currently present
on the pin.
- ``Pin.OUT`` - The behaviour and return value of the method is undefined.
- ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and
return value of the method is undefined. Otherwise, if the pin is in
state '1', the method returns the actual input value currently present
on the pin.
If the argument is supplied then this method sets the digital logic level of
the pin. The argument ``x`` can be anything that converts to a boolean.
If it converts to ``True``, the pin is set to state '1', otherwise it is set
to state '0'. The behaviour of this method depends on the mode of the pin:
- ``Pin.IN`` - The value is stored in the output buffer for the pin. The
pin state does not change, it remains in the high-impedance state. The
stored value will become active on the pin as soon as it is changed to
``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode.
- ``Pin.OUT`` - The output buffer is set to the given value immediately.
- ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage
state. Otherwise the pin is set to high-impedance state.
When setting the value this method returns ``None``.
"""
@overload
def __call__(self) -> int:
"""
Pin objects are callable. The call method provides a (fast) shortcut to set
and get the value of the pin. It is equivalent to Pin.value([x]).
See :meth:`Pin.value` for more details.
"""
@overload
def __call__(self, x: Any, /) -> None:
"""
Pin objects are callable. The call method provides a (fast) shortcut to set
and get the value of the pin. It is equivalent to Pin.value([x]).
See :meth:`Pin.value` for more details.
"""
def on(self) -> None:
"""
Set pin to "1" output level.
"""
def off(self) -> None:
"""
Set pin to "0" output level.
"""
def irq(
self,
/,
handler: Callable[[Pin], None] | None = None,
trigger: int = (IRQ_FALLING | IRQ_RISING),
*,
priority: int = 1,
wake: int | None = None,
hard: bool = False,
) -> Callable[[Pin], None] | None:
"""
Configure an interrupt handler to be called when the trigger source of the
pin is active. If the pin mode is ``Pin.IN`` then the trigger source is
the external value on the pin. If the pin mode is ``Pin.OUT`` then the
trigger source is the output buffer of the pin. Otherwise, if the pin mode
is ``Pin.OPEN_DRAIN`` then the trigger source is the output buffer for
state '0' and the external pin value for state '1'.
The arguments are:
- ``handler`` is an optional function to be called when the interrupt
triggers. The handler must take exactly one argument which is the
``Pin`` instance.
- ``trigger`` configures the event which can generate an interrupt.
Possible values are:
- ``Pin.IRQ_FALLING`` interrupt on falling edge.
- ``Pin.IRQ_RISING`` interrupt on rising edge.
- ``Pin.IRQ_LOW_LEVEL`` interrupt on low level.
- ``Pin.IRQ_HIGH_LEVEL`` interrupt on high level.
These values can be OR'ed together to trigger on multiple events.
- ``priority`` sets the priority level of the interrupt. The values it
can take are port-specific, but higher values always represent higher
priorities.
- ``wake`` selects the power mode in which this interrupt can wake up the
system. It can be ``machine.IDLE``, ``machine.SLEEP`` or ``machine.DEEPSLEEP``.
These values can also be OR'ed together to make a pin generate interrupts in
more than one power mode.
- ``hard`` if true a hardware interrupt is used. This reduces the delay
between the pin change and the handler being called. Hard interrupt
handlers may not allocate memory; see :ref:`isr_rules`.
Not all ports support this argument.
This method returns a callback object.
"""
def low(self) -> None:
"""
Set pin to "0" output level.
Availability: nrf, rp2, stm32 ports.
"""
def high(self) -> None:
"""
Set pin to "1" output level.
Availability: nrf, rp2, stm32 ports.
"""
@overload
def mode(self) -> int:
"""
Get or set the pin mode.
See the constructor documentation for details of the ``mode`` argument.
Availability: cc3200, stm32 ports.
"""
@overload
def mode(self, mode: int, /) -> None:
"""
Get or set the pin mode.
See the constructor documentation for details of the ``mode`` argument.
Availability: cc3200, stm32 ports.
"""
@overload
def pull(self) -> int:
"""
Get or set the pin pull state.
See the constructor documentation for details of the ``pull`` argument.
Availability: cc3200, stm32 ports.
"""
@overload
def pull(self, pull: int, /) -> None:
"""
Get or set the pin pull state.
See the constructor documentation for details of the ``pull`` argument.
Availability: cc3200, stm32 ports.
"""
@overload
def drive(self) -> int:
"""
Get or set the pin drive strength.
See the constructor documentation for details of the ``drive`` argument.
Availability: cc3200 port.
"""
@overload
def drive(self, drive: int, /) -> None:
"""
Get or set the pin drive strength.
See the constructor documentation for details of the ``drive`` argument.
Availability: cc3200 port.
"""
class Signal:
"""
The Signal class is a simple extension of the `Pin` class. Unlike Pin, which
can be only in "absolute" 0 and 1 states, a Signal can be in "asserted"
(on) or "deasserted" (off) states, while being inverted (active-low) or
not. In other words, it adds logical inversion support to Pin functionality.
While this may seem a simple addition, it is exactly what is needed to
support wide array of simple digital devices in a way portable across
different boards, which is one of the major MicroPython goals. Regardless
of whether different users have an active-high or active-low LED, a normally
open or normally closed relay - you can develop a single, nicely looking
application which works with each of them, and capture hardware
configuration differences in few lines in the config file of your app.
Example::
from machine import Pin, Signal
# Suppose you have an active-high LED on pin 0
led1_pin = Pin(0, Pin.OUT)
# ... and active-low LED on pin 1
led2_pin = Pin(1, Pin.OUT)
# Now to light up both of them using Pin class, you'll need to set
# them to different values
led1_pin.value(1)
led2_pin.value(0)
# Signal class allows to abstract away active-high/active-low
# difference
led1 = Signal(led1_pin, invert=False)
led2 = Signal(led2_pin, invert=True)
# Now lighting up them looks the same
led1.value(1)
led2.value(1)
# Even better:
led1.on()
led2.on()
Following is the guide when Signal vs Pin should be used:
* Use Signal: If you want to control a simple on/off (including software
PWM!) devices like LEDs, multi-segment indicators, relays, buzzers, or
read simple binary sensors, like normally open or normally closed buttons,
pulled high or low, Reed switches, moisture/flame detectors, etc. etc.
Summing up, if you have a real physical device/sensor requiring GPIO
access, you likely should use a Signal.
* Use Pin: If you implement a higher-level protocol or bus to communicate
with more complex devices.
The split between Pin and Signal come from the use cases above and the
architecture of MicroPython: Pin offers the lowest overhead, which may
be important when bit-banging protocols. But Signal adds additional
flexibility on top of Pin, at the cost of minor overhead (much smaller
than if you implemented active-high vs active-low device differences in
Python manually!). Also, Pin is a low-level object which needs to be
implemented for each support board, while Signal is a high-level object
which comes for free once Pin is implemented.
If in doubt, give the Signal a try! Once again, it is offered to save
developers from the need to handle unexciting differences like active-low
vs active-high signals, and allow other users to share and enjoy your
application, instead of being frustrated by the fact that it doesn't
work for them simply because their LEDs or relays are wired in a slightly
different way.
"""
@overload
def __init__(self, pin_obj: Pin, invert: bool = False, /):
"""
Create a Signal object. There're two ways to create it:
* By wrapping existing Pin object - universal method which works for
any board.
* By passing required Pin parameters directly to Signal constructor,
skipping the need to create intermediate Pin object. Available on
many, but not all boards.
The arguments are:
- ``pin_obj`` is existing Pin object.
- ``pin_arguments`` are the same arguments as can be passed to Pin constructor.
- ``invert`` - if True, the signal will be inverted (active low).
"""
@overload
def __init__(
self,
id: Pin | str,
/,
mode: int = -1,
pull: int = -1,
*,
value: Any = None,
drive: int | None = None,
alt: int | None = None,
invert: bool = False,
):
"""
Create a Signal object. There're two ways to create it:
* By wrapping existing Pin object - universal method which works for
any board.
* By passing required Pin parameters directly to Signal constructor,
skipping the need to create intermediate Pin object. Available on
many, but not all boards.
The arguments are:
- ``pin_obj`` is existing Pin object.
- ``pin_arguments`` are the same arguments as can be passed to Pin constructor.
- ``invert`` - if True, the signal will be inverted (active low).
"""
@overload
def value(self) -> int:
"""
This method allows to set and get the value of the signal, depending on whether
the argument ``x`` is supplied or not.
If the argument is omitted then this method gets the signal level, 1 meaning
signal is asserted (active) and 0 - signal inactive.
If the argument is supplied then this method sets the signal level. The
argument ``x`` can be anything that converts to a boolean. If it converts
to ``True``, the signal is active, otherwise it is inactive.
Correspondence between signal being active and actual logic level on the
underlying pin depends on whether signal is inverted (active-low) or not.
For non-inverted signal, active status corresponds to logical 1, inactive -
to logical 0. For inverted/active-low signal, active status corresponds
to logical 0, while inactive - to logical 1.
"""
@overload
def value(self, x: Any, /) -> None:
"""
This method allows to set and get the value of the signal, depending on whether
the argument ``x`` is supplied or not.
If the argument is omitted then this method gets the signal level, 1 meaning
signal is asserted (active) and 0 - signal inactive.
If the argument is supplied then this method sets the signal level. The
argument ``x`` can be anything that converts to a boolean. If it converts
to ``True``, the signal is active, otherwise it is inactive.
Correspondence between signal being active and actual logic level on the
underlying pin depends on whether signal is inverted (active-low) or not.
For non-inverted signal, active status corresponds to logical 1, inactive -
to logical 0. For inverted/active-low signal, active status corresponds
to logical 0, while inactive - to logical 1.
"""
def on(self) -> None:
"""
Activate signal.
"""
def off(self) -> None:
"""
Deactivate signal.
"""
class ADC:
"""
The ADC class provides an interface to analog-to-digital convertors, and
represents a single endpoint that can sample a continuous voltage and
convert it to a discretised value.
Example usage::
import machine
adc = machine.ADC(pin) # create an ADC object acting on a pin
val = adc.read_u16() # read a raw analog value in the range 0-65535
"""
def __init__(self, pin: int | Pin, /):
"""
Access the ADC associated with a source identified by *id*. This
*id* may be an integer (usually specifying a channel number), a
:ref:`Pin ` object, or other value supported by the
underlying machine.
"""
def read_u16(self) -> int:
"""
Take an analog reading and return an integer in the range 0-65535.
The return value represents the raw reading taken by the ADC, scaled
such that the minimum value is 0 and the maximum value is 65535.
"""
# noinspection PyShadowingNames
class PWM:
"""
This class provides pulse width modulation output.
Example usage::
from machine import PWM
pwm = PWM(pin) # create a PWM object on a pin
pwm.duty_u16(32768) # set duty to 50%
# reinitialise with a period of 200us, duty of 5us
pwm.init(freq=5000, duty_ns=5000)
pwm.duty_ns(3000) # set pulse width to 3us
pwm.deinit()
"""
def __init__(
self,
dest: Pin | int,
/,
*,
freq: int = ...,
duty_u16: int = ...,
duty_ns: int = ...,
):
"""
Construct and return a new PWM object using the following parameters:
- *dest* is the entity on which the PWM is output, which is usually a
:ref:`machine.Pin ` object, but a port may allow other values,
like integers.
- *freq* should be an integer which sets the frequency in Hz for the
PWM cycle.
- *duty_u16* sets the duty cycle as a ratio ``duty_u16 / 65535``.
- *duty_ns* sets the pulse width in nanoseconds.
Setting *freq* may affect other PWM objects if the objects share the same
underlying PWM generator (this is hardware specific).
Only one of *duty_u16* and *duty_ns* should be specified at a time.
"""
def init(self, *, freq: int = ..., duty_u16: int = ..., duty_ns: int = ...) -> None:
"""
Modify settings for the PWM object. See the above constructor for details
about the parameters.
"""
def deinit(self) -> None:
"""
Disable the PWM output.
"""
@overload
def freq(self) -> int:
"""
Get or set the current frequency of the PWM output.
With no arguments the frequency in Hz is returned.
With a single *value* argument the frequency is set to that value in Hz. The
method may raise a ``ValueError`` if the frequency is outside the valid range.
"""
@overload
def freq(self, value: int, /,) -> None:
"""
Get or set the current frequency of the PWM output.
With no arguments the frequency in Hz is returned.
With a single *value* argument the frequency is set to that value in Hz. The
method may raise a ``ValueError`` if the frequency is outside the valid range.
"""
@overload
def duty_u16(self) -> int:
"""
Get or set the current duty cycle of the PWM output, as an unsigned 16-bit
value in the range 0 to 65535 inclusive.
With no arguments the duty cycle is returned.
With a single *value* argument the duty cycle is set to that value, measured
as the ratio ``value / 65535``.
"""
@overload
def duty_u16(self, value: int, /,) -> None:
"""
Get or set the current duty cycle of the PWM output, as an unsigned 16-bit
value in the range 0 to 65535 inclusive.
With no arguments the duty cycle is returned.
With a single *value* argument the duty cycle is set to that value, measured
as the ratio ``value / 65535``.
"""
@overload
def duty_ns(self) -> int:
"""
Get or set the current pulse width of the PWM output, as a value in nanoseconds.
With no arguments the pulse width in nanoseconds is returned.
With a single *value* argument the pulse width is set to that value.
"""
@overload
def duty_ns(self, value: int, /,) -> None:
"""
Get or set the current pulse width of the PWM output, as a value in nanoseconds.
With no arguments the pulse width in nanoseconds is returned.
With a single *value* argument the pulse width is set to that value.
"""
class UART:
"""
UART implements the standard UART/USART duplex serial communications protocol. At
the physical level it consists of 2 lines: RX and TX. The unit of communication
is a character (not to be confused with a string character) which can be 8 or 9
bits wide.
UART objects can be created and initialised using::
from machine import UART
uart = UART(1, 9600) # init with given baudrate
uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters
Supported parameters differ on a board:
Pyboard: Bits can be 7, 8 or 9. Stop can be 1 or 2. With *parity=None*,
only 8 and 9 bits are supported. With parity enabled, only 7 and 8 bits
are supported.
WiPy/CC3200: Bits can be 5, 6, 7, 8. Stop can be 1 or 2.
A UART object acts like a `stream` object and reading and writing is done
using the standard stream methods::
uart.read(10) # read 10 characters, returns a bytes object
uart.read() # read all available characters
uart.readline() # read a line
uart.readinto(buf) # read and store into the given buffer
uart.write('abc') # write the 3 characters
"""
RX_ANY: ClassVar[int] = ...
"""
IRQ trigger sources
Availability: WiPy.
"""
@overload
def __init__(
self,
id: int | str,
baudrate: int = 9600,
bits: int = 8,
parity: int | None = None,
stop: int = 1,
/,
*,
tx: Pin | None = None,
rx: Pin | None = None,
txbuf: int | None = None,
rxbuf: int | None = None,
timeout: int | None = None,
timeout_char: int | None = None,
invert: int | None = None,
):
"""
Construct a UART object of the given id.
"""
@overload
def __init__(
self,
id: int | str,
baudrate: int = 9600,
bits: int = 8,
parity: int | None = None,
stop: int = 1,
/,
*,
pins: tuple[Pin, Pin] | None = None,
):
"""
Construct a UART object of the given id.
"""
@overload
def __init__(
self,
id: int | str,
baudrate: int = 9600,
bits: int = 8,
parity: int | None = None,
stop: int = 1,
/,
*,
pins: tuple[Pin, Pin, Pin, Pin] | None = None,
):
"""
Construct a UART object of the given id.
"""
@overload
def init(
self,
baudrate: int = 9600,
bits: int = 8,
parity: int | None = None,
stop: int = 1,
/,
*,
tx: Pin | None = None,
rx: Pin | None = None,
txbuf: int | None = None,
rxbuf: int | None = None,
timeout: int | None = None,
timeout_char: int | None = None,
invert: int | None = None,
) -> None:
"""
Initialise the UART bus with the given parameters:
- *baudrate* is the clock rate.
- *bits* is the number of bits per character, 7, 8 or 9.
- *parity* is the parity, ``None``, 0 (even) or 1 (odd).
- *stop* is the number of stop bits, 1 or 2.
Additional keyword-only parameters that may be supported by a port are:
- *tx* specifies the TX pin to use.
- *rx* specifies the RX pin to use.
- *rts* specifies the RTS (output) pin to use for hardware receive flow control.
- *cts* specifies the CTS (input) pin to use for hardware transmit flow control.
- *txbuf* specifies the length in characters of the TX buffer.
- *rxbuf* specifies the length in characters of the RX buffer.
- *timeout* specifies the time to wait for the first character (in ms).
- *timeout_char* specifies the time to wait between characters (in ms).
- *invert* specifies which lines to invert.
- *flow* specifies which hardware flow control signals to use. The value
is a bitmask.
- ``0`` will ignore hardware flow control signals.
- ``UART.RTS`` will enable receive flow control by using the RTS output pin to
signal if the receive FIFO has sufficient space to accept more data.
- ``UART.CTS`` will enable transmit flow control by pausing transmission when the
CTS input pin signals that the receiver is running low on buffer space.
- ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control.
On the WiPy only the following keyword-only parameter is supported:
- *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order).
Any of the pins can be None if one wants the UART to operate with limited functionality.
If the RTS pin is given the the RX pin must be given as well. The same applies to CTS.
When no pins are given, then the default set of TX and RX pins is taken, and hardware
flow control will be disabled. If *pins* is ``None``, no pin assignment will be made.
"""
@overload
def init(
self,
baudrate: int = 9600,
bits: int = 8,
parity: int | None = None,
stop: int = 1,
/,
*,
pins: tuple[Pin, Pin] | None = None,
) -> None:
"""
Initialise the UART bus with the given parameters:
- *baudrate* is the clock rate.
- *bits* is the number of bits per character, 7, 8 or 9.
- *parity* is the parity, ``None``, 0 (even) or 1 (odd).
- *stop* is the number of stop bits, 1 or 2.
Additional keyword-only parameters that may be supported by a port are:
- *tx* specifies the TX pin to use.
- *rx* specifies the RX pin to use.
- *rts* specifies the RTS (output) pin to use for hardware receive flow control.
- *cts* specifies the CTS (input) pin to use for hardware transmit flow control.
- *txbuf* specifies the length in characters of the TX buffer.
- *rxbuf* specifies the length in characters of the RX buffer.
- *timeout* specifies the time to wait for the first character (in ms).
- *timeout_char* specifies the time to wait between characters (in ms).
- *invert* specifies which lines to invert.
- *flow* specifies which hardware flow control signals to use. The value
is a bitmask.
- ``0`` will ignore hardware flow control signals.
- ``UART.RTS`` will enable receive flow control by using the RTS output pin to
signal if the receive FIFO has sufficient space to accept more data.
- ``UART.CTS`` will enable transmit flow control by pausing transmission when the
CTS input pin signals that the receiver is running low on buffer space.
- ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control.
On the WiPy only the following keyword-only parameter is supported:
- *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order).
Any of the pins can be None if one wants the UART to operate with limited functionality.
If the RTS pin is given the the RX pin must be given as well. The same applies to CTS.
When no pins are given, then the default set of TX and RX pins is taken, and hardware
flow control will be disabled. If *pins* is ``None``, no pin assignment will be made.
"""
@overload
def init(
self,
baudrate: int = 9600,
bits: int = 8,
parity: int | None = None,
stop: int = 1,
/,
*,
pins: tuple[Pin, Pin, Pin, Pin] | None = None,
) -> None:
"""
Initialise the UART bus with the given parameters:
- *baudrate* is the clock rate.
- *bits* is the number of bits per character, 7, 8 or 9.
- *parity* is the parity, ``None``, 0 (even) or 1 (odd).
- *stop* is the number of stop bits, 1 or 2.
Additional keyword-only parameters that may be supported by a port are:
- *tx* specifies the TX pin to use.
- *rx* specifies the RX pin to use.
- *rts* specifies the RTS (output) pin to use for hardware receive flow control.
- *cts* specifies the CTS (input) pin to use for hardware transmit flow control.
- *txbuf* specifies the length in characters of the TX buffer.
- *rxbuf* specifies the length in characters of the RX buffer.
- *timeout* specifies the time to wait for the first character (in ms).
- *timeout_char* specifies the time to wait between characters (in ms).
- *invert* specifies which lines to invert.
- *flow* specifies which hardware flow control signals to use. The value
is a bitmask.
- ``0`` will ignore hardware flow control signals.
- ``UART.RTS`` will enable receive flow control by using the RTS output pin to
signal if the receive FIFO has sufficient space to accept more data.
- ``UART.CTS`` will enable transmit flow control by pausing transmission when the
CTS input pin signals that the receiver is running low on buffer space.
- ``UART.RTS | UART.CTS`` will enable both, for full hardware flow control.
On the WiPy only the following keyword-only parameter is supported:
- *pins* is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order).
Any of the pins can be None if one wants the UART to operate with limited functionality.
If the RTS pin is given the the RX pin must be given as well. The same applies to CTS.
When no pins are given, then the default set of TX and RX pins is taken, and hardware
flow control will be disabled. If *pins* is ``None``, no pin assignment will be made.
"""
def deinit(self) -> None:
"""
Turn off the UART bus.
"""
def any(self) -> int:
"""
Returns an integer counting the number of characters that can be read without
blocking. It will return 0 if there are no characters available and a positive
number if there are characters. The method may return 1 even if there is more
than one character available for reading.
For more sophisticated querying of available characters use select.poll::
poll = select.poll()
poll.register(uart, select.POLLIN)
poll.poll(timeout)
"""
@overload
def read(self) -> bytes | None:
"""
Read characters. If ``nbytes`` is specified then read at most that many bytes,
otherwise read as much data as possible. It may return sooner if a timeout
is reached. The timeout is configurable in the constructor.
Return value: a bytes object containing the bytes read in. Returns ``None``
on timeout.
"""
@overload
def read(self, nbytes: int, /) -> bytes | None:
"""
Read characters. If ``nbytes`` is specified then read at most that many bytes,
otherwise read as much data as possible. It may return sooner if a timeout
is reached. The timeout is configurable in the constructor.
Return value: a bytes object containing the bytes read in. Returns ``None``
on timeout.
"""
@overload
def readinto(self, buf: AnyWritableBuf, /) -> int | None:
"""
Read bytes into the ``buf``. If ``nbytes`` is specified then read at most
that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout
is reached. The timeout is configurable in the constructor.
Return value: number of bytes read and stored into ``buf`` or ``None`` on
timeout.
"""
@overload
def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None:
"""
Read bytes into the ``buf``. If ``nbytes`` is specified then read at most
that many bytes. Otherwise, read at most ``len(buf)`` bytes. It may return sooner if a timeout
is reached. The timeout is configurable in the constructor.
Return value: number of bytes read and stored into ``buf`` or ``None`` on
timeout.
"""
def readline(self) -> bytes | None:
"""
Read a line, ending in a newline character. It may return sooner if a timeout
is reached. The timeout is configurable in the constructor.
Return value: the line read or ``None`` on timeout.
"""
def write(self, buf: AnyReadableBuf, /) -> int | None:
"""
Write the buffer of bytes to the bus.
Return value: number of bytes written or ``None`` on timeout.
"""
def sendbreak(self) -> None:
"""
Send a break condition on the bus. This drives the bus low for a duration
longer than required for a normal transmission of a character.
"""
def irq(
self,
trigger: int,
priority: int = 1,
handler: Callable[[UART], None] | None = None,
wake: int = IDLE,
/,
) -> Any:
"""
Create a callback to be triggered when data is received on the UART.
- *trigger* can only be ``UART.RX_ANY``
- *priority* level of the interrupt. Can take values in the range 1-7.
Higher values represent higher priorities.
- *handler* an optional function to be called when new characters arrive.
- *wake* can only be ``machine.IDLE``.
.. note::
The handler will be called whenever any of the following two conditions are met:
- 8 new characters have been received.
- At least 1 new character is waiting in the Rx buffer and the Rx line has been
silent for the duration of 1 complete frame.
This means that when the handler function is called there will be between 1 to 8
characters waiting.
Returns an irq object.
Availability: WiPy.
"""
class SPI:
"""
SPI is a synchronous serial protocol that is driven by a controller. At the
physical level, a bus consists of 3 lines: SCK, MOSI, MISO. Multiple devices
can share the same bus. Each device should have a separate, 4th signal,
CS (Chip Select), to select a particular device on a bus with which
communication takes place. Management of a CS signal should happen in
user code (via machine.Pin class).
Both hardware and software SPI implementations exist via the
:ref:`machine.SPI ` and `machine.SoftSPI` classes. Hardware SPI uses underlying
hardware support of the system to perform the reads/writes and is usually
efficient and fast but may have restrictions on which pins can be used.
Software SPI is implemented by bit-banging and can be used on any pin but
is not as efficient. These classes have the same methods available and
differ primarily in the way they are constructed.
"""
CONTROLLER: ClassVar[int] = ...
"""
for initialising the SPI bus to controller; this is only used for the WiPy
"""
MSB: ClassVar[int] = ...
"""
set the first bit to be the most significant bit
"""
LSB: ClassVar[int] = ...
"""
set the first bit to be the least significant bit
"""
@overload
def __init__(self, id: int, /):
"""
Construct an SPI object on the given bus, *id*. Values of *id* depend
on a particular port and its hardware. Values 0, 1, etc. are commonly used
to select hardware SPI block #0, #1, etc.
With no additional parameters, the SPI object is created but not
initialised (it has the settings from the last initialisation of
the bus, if any). If extra arguments are given, the bus is initialised.
See ``init`` for parameters of initialisation.
"""
@overload
def __init__(
self,
id: int,
/,
baudrate: int = 1_000_000,
*,
polarity: int = 0,
phase: int = 0,
bits: int = 8,
firstbit: int = MSB,
sck: Pin | None = None,
mosi: Pin | None = None,
miso: Pin | None = None,
):
"""
Construct an SPI object on the given bus, *id*. Values of *id* depend
on a particular port and its hardware. Values 0, 1, etc. are commonly used
to select hardware SPI block #0, #1, etc.
With no additional parameters, the SPI object is created but not
initialised (it has the settings from the last initialisation of
the bus, if any). If extra arguments are given, the bus is initialised.
See ``init`` for parameters of initialisation.
"""
@overload
def __init__(
self,
id: int,
/,
baudrate: int = 1_000_000,
*,
polarity: int = 0,
phase: int = 0,
bits: int = 8,
firstbit: int = MSB,
pins: tuple[Pin, Pin, Pin] | None = None,
):
"""
Construct an SPI object on the given bus, *id*. Values of *id* depend
on a particular port and its hardware. Values 0, 1, etc. are commonly used
to select hardware SPI block #0, #1, etc.
With no additional parameters, the SPI object is created but not
initialised (it has the settings from the last initialisation of
the bus, if any). If extra arguments are given, the bus is initialised.
See ``init`` for parameters of initialisation.
"""
@overload
def init(
self,
baudrate: int = 1_000_000,
*,
polarity: int = 0,
phase: int = 0,
bits: int = 8,
firstbit: int = MSB,
sck: Pin | None = None,
mosi: Pin | None = None,
miso: Pin | None = None,
) -> None:
"""
Initialise the SPI bus with the given parameters:
- ``baudrate`` is the SCK clock rate.
- ``polarity`` can be 0 or 1, and is the level the idle clock line sits at.
- ``phase`` can be 0 or 1 to sample data on the first or second clock edge
respectively.
- ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware.
- ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``.
- ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most
hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed
and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for
a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver
(``id`` = -1).
- ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to
specify them as a tuple of ``pins`` parameter.
In the case of hardware SPI the actual clock frequency may be lower than the
requested baudrate. This is dependant on the platform hardware. The actual
rate may be determined by printing the SPI object.
"""
@overload
def init(
self,
baudrate: int = 1_000_000,
*,
polarity: int = 0,
phase: int = 0,
bits: int = 8,
firstbit: int = MSB,
pins: tuple[Pin, Pin, Pin] | None = None,
) -> None:
"""
Initialise the SPI bus with the given parameters:
- ``baudrate`` is the SCK clock rate.
- ``polarity`` can be 0 or 1, and is the level the idle clock line sits at.
- ``phase`` can be 0 or 1 to sample data on the first or second clock edge
respectively.
- ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware.
- ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``.
- ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most
hardware SPI blocks (as selected by ``id`` parameter to the constructor), pins are fixed
and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for
a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver
(``id`` = -1).
- ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to
specify them as a tuple of ``pins`` parameter.
In the case of hardware SPI the actual clock frequency may be lower than the
requested baudrate. This is dependant on the platform hardware. The actual
rate may be determined by printing the SPI object.
"""
def deinit(self) -> None:
"""
Turn off the SPI bus.
"""
def read(self, nbytes: int, write: int = 0x00, /) -> bytes:
"""
Read a number of bytes specified by ``nbytes`` while continuously writing
the single byte given by ``write``.
Returns a ``bytes`` object with the data that was read.
"""
def readinto(self, buf: AnyWritableBuf, write: int = 0x00, /) -> int | None:
"""
Read into the buffer specified by ``buf`` while continuously writing the
single byte given by ``write``.
Returns ``None``.
Note: on WiPy this function returns the number of bytes read.
"""
def write(self, buf: AnyReadableBuf, /) -> int | None:
"""
Write the bytes contained in ``buf``.
Returns ``None``.
Note: on WiPy this function returns the number of bytes written.
"""
def write_readinto(
self, write_buf: AnyReadableBuf, read_buf: AnyWritableBuf, /
) -> int | None:
"""
Write the bytes from ``write_buf`` while reading into ``read_buf``. The
buffers can be the same or different, but both buffers must have the
same length.
Returns ``None``.
Note: on WiPy this function returns the number of bytes written.
"""
# noinspection PyShadowingNames
class I2C:
"""
I2C is a two-wire protocol for communicating between devices. At the physical
level it consists of 2 wires: SCL and SDA, the clock and data lines respectively.
I2C objects are created attached to a specific bus. They can be initialised
when created, or initialised later on.
Printing the I2C object gives you information about its configuration.
Both hardware and software I2C implementations exist via the
:ref:`machine.I2C ` and `machine.SoftI2C` classes. Hardware I2C uses
underlying hardware support of the system to perform the reads/writes and is
usually efficient and fast but may have restrictions on which pins can be used.
Software I2C is implemented by bit-banging and can be used on any pin but is not
as efficient. These classes have the same methods available and differ primarily
in the way they are constructed.
Example usage::
from machine import I2C
i2c = I2C(freq=400000) # create I2C peripheral at frequency of 400kHz
# depending on the port, extra parameters may be required
# to select the peripheral and/or pins to use
i2c.scan() # scan for peripherals, returning a list of 7-bit addresses
i2c.writeto(42, b'123') # write 3 bytes to peripheral with 7-bit address 42
i2c.readfrom(42, 4) # read 4 bytes from peripheral with 7-bit address 42
i2c.readfrom_mem(42, 8, 3) # read 3 bytes from memory of peripheral 42,
# starting at memory-address 8 in the peripheral
i2c.writeto_mem(42, 2, b'\x10') # write 1 byte to memory of peripheral 42
# starting at address 2 in the peripheral
"""
@overload
def __init__(self, id: int, /, *, freq: int = 400_000):
"""
Construct and return a new I2C object using the following parameters:
- *id* identifies a particular I2C peripheral. Allowed values for
depend on the particular port/board
- *scl* should be a pin object specifying the pin to use for SCL.
- *sda* should be a pin object specifying the pin to use for SDA.
- *freq* should be an integer which sets the maximum frequency
for SCL.
Note that some ports/boards will have default values of *scl* and *sda*
that can be changed in this constructor. Others will have fixed values
of *scl* and *sda* that cannot be changed.
"""
@overload
def __init__(self, id: int, /, *, scl: Pin, sda: Pin, freq: int = 400_000):
"""
Construct and return a new I2C object using the following parameters:
- *id* identifies a particular I2C peripheral. Allowed values for
depend on the particular port/board
- *scl* should be a pin object specifying the pin to use for SCL.
- *sda* should be a pin object specifying the pin to use for SDA.
- *freq* should be an integer which sets the maximum frequency
for SCL.
Note that some ports/boards will have default values of *scl* and *sda*
that can be changed in this constructor. Others will have fixed values
of *scl* and *sda* that cannot be changed.
"""
@overload
def init(self, *, freq: int = 400_000) -> None:
"""
Initialise the I2C bus with the given arguments:
- *scl* is a pin object for the SCL line
- *sda* is a pin object for the SDA line
- *freq* is the SCL clock rate
"""
@overload
def init(self, *, scl: Pin, sda: Pin, freq: int = 400_000) -> None:
"""
Initialise the I2C bus with the given arguments:
- *scl* is a pin object for the SCL line
- *sda* is a pin object for the SDA line
- *freq* is the SCL clock rate
"""
def deinit(self) -> None:
"""
Turn off the I2C bus.
Availability: WiPy.
"""
def scan(self) -> list[int]:
"""
Scan all I2C addresses between 0x08 and 0x77 inclusive and return a list of
those that respond. A device responds if it pulls the SDA line low after
its address (including a write bit) is sent on the bus.
"""
def start(self) -> None:
"""
Generate a START condition on the bus (SDA transitions to low while SCL is high).
Primitive I2C operations
------------------------
The following methods implement the primitive I2C controller bus operations and can
be combined to make any I2C transaction. They are provided if you need more
control over the bus, otherwise the standard methods (see below) can be used.
These methods are only available on the `machine.SoftI2C` class.
"""
def stop(self) -> None:
"""
Generate a STOP condition on the bus (SDA transitions to high while SCL is high).
Primitive I2C operations
------------------------
The following methods implement the primitive I2C controller bus operations and can
be combined to make any I2C transaction. They are provided if you need more
control over the bus, otherwise the standard methods (see below) can be used.
These methods are only available on the `machine.SoftI2C` class.
"""
def readinto(self, buf: AnyWritableBuf, nack: bool = True, /) -> None:
"""
Reads bytes from the bus and stores them into *buf*. The number of bytes
read is the length of *buf*. An ACK will be sent on the bus after
receiving all but the last byte. After the last byte is received, if *nack*
is true then a NACK will be sent, otherwise an ACK will be sent (and in this
case the peripheral assumes more bytes are going to be read in a later call).
Primitive I2C operations
------------------------
The following methods implement the primitive I2C controller bus operations and can
be combined to make any I2C transaction. They are provided if you need more
control over the bus, otherwise the standard methods (see below) can be used.
These methods are only available on the `machine.SoftI2C` class.
"""
def write(self, buf: AnyReadableBuf, /) -> int:
"""
Write the bytes from *buf* to the bus. Checks that an ACK is received
after each byte and stops transmitting the remaining bytes if a NACK is
received. The function returns the number of ACKs that were received.
Primitive I2C operations
------------------------
The following methods implement the primitive I2C controller bus operations and can
be combined to make any I2C transaction. They are provided if you need more
control over the bus, otherwise the standard methods (see below) can be used.
These methods are only available on the `machine.SoftI2C` class.
"""
def readfrom(self, addr: int, nbytes: int, stop: bool = True, /) -> bytes:
"""
Read *nbytes* from the peripheral specified by *addr*.
If *stop* is true then a STOP condition is generated at the end of the transfer.
Returns a `bytes` object with the data read.
Standard bus operations
-----------------------
The following methods implement the standard I2C controller read and write
operations that target a given peripheral device.
"""
def readfrom_into(
self, addr: int, buf: AnyWritableBuf, stop: bool = True, /
) -> None:
"""
Read into *buf* from the peripheral specified by *addr*.
The number of bytes read will be the length of *buf*.
If *stop* is true then a STOP condition is generated at the end of the transfer.
The method returns ``None``.
Standard bus operations
-----------------------
The following methods implement the standard I2C controller read and write
operations that target a given peripheral device.
"""
def writeto(self, addr: int, buf: AnyReadableBuf, stop: bool = True, /) -> int:
"""
Write the bytes from *buf* to the peripheral specified by *addr*. If a
NACK is received following the write of a byte from *buf* then the
remaining bytes are not sent. If *stop* is true then a STOP condition is
generated at the end of the transfer, even if a NACK is received.
The function returns the number of ACKs that were received.
Standard bus operations
-----------------------
The following methods implement the standard I2C controller read and write
operations that target a given peripheral device.
"""
def writevto(
self, addr: int, vector: Sequence[AnyReadableBuf], stop: bool = True, /
) -> int:
"""
Write the bytes contained in *vector* to the peripheral specified by *addr*.
*vector* should be a tuple or list of objects with the buffer protocol.
The *addr* is sent once and then the bytes from each object in *vector*
are written out sequentially. The objects in *vector* may be zero bytes
in length in which case they don't contribute to the output.
If a NACK is received following the write of a byte from one of the
objects in *vector* then the remaining bytes, and any remaining objects,
are not sent. If *stop* is true then a STOP condition is generated at
the end of the transfer, even if a NACK is received. The function
returns the number of ACKs that were received.
Standard bus operations
-----------------------
The following methods implement the standard I2C controller read and write
operations that target a given peripheral device.
"""
def readfrom_mem(
self, addr: int, memaddr: int, nbytes: int, /, *, addrsize: int = 8
) -> bytes:
"""
Read *nbytes* from the peripheral specified by *addr* starting from the memory
address specified by *memaddr*.
The argument *addrsize* specifies the address size in bits.
Returns a `bytes` object with the data read.
Memory operations
-----------------
Some I2C devices act as a memory device (or set of registers) that can be read
from and written to. In this case there are two addresses associated with an
I2C transaction: the peripheral address and the memory address. The following
methods are convenience functions to communicate with such devices.
"""
def readfrom_mem_into(
self, addr: int, memaddr: int, buf: AnyWritableBuf, /, *, addrsize: int = 8
) -> None:
"""
Read into *buf* from the peripheral specified by *addr* starting from the
memory address specified by *memaddr*. The number of bytes read is the
length of *buf*.
The argument *addrsize* specifies the address size in bits (on ESP8266
this argument is not recognised and the address size is always 8 bits).
The method returns ``None``.
Memory operations
-----------------
Some I2C devices act as a memory device (or set of registers) that can be read
from and written to. In this case there are two addresses associated with an
I2C transaction: the peripheral address and the memory address. The following
methods are convenience functions to communicate with such devices.
"""
def writeto_mem(
self, addr: int, memaddr: int, buf: AnyReadableBuf, /, *, addrsize: int = 8
) -> None:
"""
Write *buf* to the peripheral specified by *addr* starting from the
memory address specified by *memaddr*.
The argument *addrsize* specifies the address size in bits (on ESP8266
this argument is not recognised and the address size is always 8 bits).
The method returns ``None``.
Memory operations
-----------------
Some I2C devices act as a memory device (or set of registers) that can be read
from and written to. In this case there are two addresses associated with an
I2C transaction: the peripheral address and the memory address. The following
methods are convenience functions to communicate with such devices.
"""
class I2S:
"""
I2S is a synchronous serial protocol used to connect digital audio devices.
At the physical level, a bus consists of 3 lines: SCK, WS, SD.
The I2S class supports controller operation. Peripheral operation is not supported.
The I2S class is currently available as a Technical Preview. During the preview period, feedback from
users is encouraged. Based on this feedback, the I2S class API and implementation may be changed.
I2S objects can be created and initialized using::
from machine import I2S
from machine import Pin
# ESP32
sck_pin = Pin(14) # Serial clock output
ws_pin = Pin(13) # Word clock output
sd_pin = Pin(12) # Serial data output
or
# PyBoards
sck_pin = Pin("Y6") # Serial clock output
ws_pin = Pin("Y5") # Word clock output
sd_pin = Pin("Y8") # Serial data output
audio_out = I2S(2,
sck=sck_pin, ws=ws_pin, sd=sd_pin,
mode=I2S.TX,
bits=16,
format=I2S.MONO,
rate=44100,
ibuf=20000)
audio_in = I2S(2,
sck=sck_pin, ws=ws_pin, sd=sd_pin,
mode=I2S.RX,
bits=32,
format=I2S.STEREO,
rate=22050,
ibuf=20000)
3 modes of operation are supported:
- blocking
- non-blocking
- uasyncio
blocking::
num_written = audio_out.write(buf) # blocks until buf emptied
num_read = audio_in.readinto(buf) # blocks until buf filled
non-blocking::
audio_out.irq(i2s_callback) # i2s_callback is called when buf is emptied
num_written = audio_out.write(buf) # returns immediately
audio_in.irq(i2s_callback) # i2s_callback is called when buf is filled
num_read = audio_in.readinto(buf) # returns immediately
uasyncio::
swriter = uasyncio.StreamWriter(audio_out)
swriter.write(buf)
await swriter.drain()
sreader = uasyncio.StreamReader(audio_in)
num_read = await sreader.readinto(buf)
"""
RX: ClassVar[int] = ...
"""
for initialising the I2S bus ``mode`` to receive
"""
TX: ClassVar[int] = ...
"""
for initialising the I2S bus ``mode`` to transmit
"""
STEREO: ClassVar[int] = ...
"""
for initialising the I2S bus ``format`` to stereo
"""
MONO: ClassVar[int] = ...
"""
for initialising the I2S bus ``format`` to mono
"""
def __init__(
self,
id: int,
/,
*,
sck: Pin,
ws: Pin,
sd: Pin,
mode: int,
bits: int,
format: int,
rate: int,
ibuf: int,
):
"""
Construct an I2S object of the given id:
- ``id`` identifies a particular I2S bus.
``id`` is board and port specific:
- PYBv1.0/v1.1: has one I2S bus with id=2.
- PYBD-SFxW: has two I2S buses with id=1 and id=2.
- ESP32: has two I2S buses with id=0 and id=1.
Keyword-only parameters that are supported on all ports:
- ``sck`` is a pin object for the serial clock line
- ``ws`` is a pin object for the word select line
- ``sd`` is a pin object for the serial data line
- ``mode`` specifies receive or transmit
- ``bits`` specifies sample size (bits), 16 or 32
- ``format`` specifies channel format, STEREO or MONO
- ``rate`` specifies audio sampling rate (samples/s)
- ``ibuf`` specifies internal buffer length (bytes)
For all ports, DMA runs continuously in the background and allows user applications to perform other operations while
sample data is transfered between the internal buffer and the I2S peripheral unit.
Increasing the size of the internal buffer has the potential to increase the time that user applications can perform non-I2S operations
before underflow (e.g. ``write`` method) or overflow (e.g. ``readinto`` method).
"""
def init(
self,
*,
sck: Pin,
ws: Pin,
sd: Pin,
mode: int,
bits: int,
format: int,
rate: int,
ibuf: int,
) -> None:
"""
see Constructor for argument descriptions
"""
def deinit(self) -> None:
"""
Deinitialize the I2S bus
"""
def readinto(self, buf: AnyWritableBuf, /,) -> int:
"""
Read audio samples into the buffer specified by ``buf``. ``buf`` must support the buffer protocol, such as bytearray or array.
"buf" byte ordering is little-endian. For Stereo format, left channel sample precedes right channel sample. For Mono format,
the left channel sample data is used.
Returns number of bytes read
"""
def write(self, buf: AnyReadableBuf, /,) -> int:
"""
Write audio samples contained in ``buf``. ``buf`` must support the buffer protocol, such as bytearray or array.
"buf" byte ordering is little-endian. For Stereo format, left channel sample precedes right channel sample. For Mono format,
the sample data is written to both the right and left channels.
Returns number of bytes written
"""
def irq(self, handler: Callable[[], None], /,) -> None:
"""
Set a callback. ``handler`` is called when ``buf`` is emptied (``write`` method) or becomes full (``readinto`` method).
Setting a callback changes the ``write`` and ``readinto`` methods to non-blocking operation.
``handler`` is called in the context of the MicroPython scheduler.
"""
@staticmethod
def shift(buf: AnyWritableBuf, bits: int, shift: int, /,) -> None:
"""
bitwise shift of all samples contained in ``buf``. ``bits`` specifies sample size in bits. ``shift`` specifies the number of bits to shift each sample.
Positive for left shift, negative for right shift.
Typically used for volume control. Each bit shift changes sample volume by 6dB.
"""
class RTC:
"""
The RTC is an independent clock that keeps track of the date
and time.
Example usage::
rtc = machine.RTC()
rtc.datetime((2020, 1, 21, 2, 10, 32, 36, 0))
print(rtc.datetime())
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
ALARM0: ClassVar[int] = ...
"""
irq trigger source
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
@overload
def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int]):
"""
Create an RTC object. See init for parameters of initialization.
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
@overload
def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int]):
"""
Create an RTC object. See init for parameters of initialization.
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
@overload
def __init__(self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int]):
"""
Create an RTC object. See init for parameters of initialization.
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
@overload
def __init__(
self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int]
):
"""
Create an RTC object. See init for parameters of initialization.
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
@overload
def __init__(
self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int]
):
"""
Create an RTC object. See init for parameters of initialization.
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
@overload
def __init__(
self, id: int = 0, /, *, datetime: tuple[int, int, int, int, int, int, int, int]
):
"""
Create an RTC object. See init for parameters of initialization.
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
@overload
def init(self) -> None:
"""
Initialise the RTC. Datetime is a tuple of the form:
``(year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]])``
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
@overload
def init(self, datetime: tuple[int, int, int], /) -> None:
"""
Initialise the RTC. Datetime is a tuple of the form:
``(year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]])``
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
@overload
def init(self, datetime: tuple[int, int, int, int], /) -> None:
"""
Initialise the RTC. Datetime is a tuple of the form:
``(year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]])``
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
@overload
def init(self, datetime: tuple[int, int, int, int, int], /) -> None:
"""
Initialise the RTC. Datetime is a tuple of the form:
``(year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]])``
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
@overload
def init(self, datetime: tuple[int, int, int, int, int, int], /) -> None:
"""
Initialise the RTC. Datetime is a tuple of the form:
``(year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]])``
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
@overload
def init(self, datetime: tuple[int, int, int, int, int, int, int], /) -> None:
"""
Initialise the RTC. Datetime is a tuple of the form:
``(year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]])``
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
@overload
def init(self, datetime: tuple[int, int, int, int, int, int, int, int], /) -> None:
"""
Initialise the RTC. Datetime is a tuple of the form:
``(year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]])``
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
def now(self) -> tuple[int, int, int, int, int, int, int, int]:
"""
Get get the current datetime tuple.
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
def deinit(self) -> None:
"""
Resets the RTC to the time of January 1, 2015 and starts running it again.
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
@overload
def alarm(self, id: int, time: int, /, *, repeat: bool = False) -> None:
"""
Set the RTC alarm. Time might be either a millisecond value to program the alarm to
current time + time_in_ms in the future, or a datetimetuple. If the time passed is in
milliseconds, repeat can be set to ``True`` to make the alarm periodic.
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
@overload
def alarm(self, id: int, time: tuple[int, int, int], /) -> None:
"""
Set the RTC alarm. Time might be either a millisecond value to program the alarm to
current time + time_in_ms in the future, or a datetimetuple. If the time passed is in
milliseconds, repeat can be set to ``True`` to make the alarm periodic.
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
@overload
def alarm(self, id: int, time: tuple[int, int, int, int], /) -> None:
"""
Set the RTC alarm. Time might be either a millisecond value to program the alarm to
current time + time_in_ms in the future, or a datetimetuple. If the time passed is in
milliseconds, repeat can be set to ``True`` to make the alarm periodic.
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
@overload
def alarm(self, id: int, time: tuple[int, int, int, int, int], /) -> None:
"""
Set the RTC alarm. Time might be either a millisecond value to program the alarm to
current time + time_in_ms in the future, or a datetimetuple. If the time passed is in
milliseconds, repeat can be set to ``True`` to make the alarm periodic.
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
@overload
def alarm(self, id: int, time: tuple[int, int, int, int, int, int], /) -> None:
"""
Set the RTC alarm. Time might be either a millisecond value to program the alarm to
current time + time_in_ms in the future, or a datetimetuple. If the time passed is in
milliseconds, repeat can be set to ``True`` to make the alarm periodic.
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
@overload
def alarm(self, id: int, time: tuple[int, int, int, int, int, int, int], /) -> None:
"""
Set the RTC alarm. Time might be either a millisecond value to program the alarm to
current time + time_in_ms in the future, or a datetimetuple. If the time passed is in
milliseconds, repeat can be set to ``True`` to make the alarm periodic.
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
@overload
def alarm(
self, id: int, time: tuple[int, int, int, int, int, int, int, int], /
) -> None:
"""
Set the RTC alarm. Time might be either a millisecond value to program the alarm to
current time + time_in_ms in the future, or a datetimetuple. If the time passed is in
milliseconds, repeat can be set to ``True`` to make the alarm periodic.
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
def alarm_left(self, alarm_id: int = 0, /) -> int:
"""
Get the number of milliseconds left before the alarm expires.
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
def cancel(self, alarm_id: int = 0, /) -> None:
"""
Cancel a running alarm.
The documentation for RTC is in a poor state; better to experiment and use `dir`!
"""
def irq(
self,
/,
*,
trigger: int,
handler: Callable[[RTC], None] | None = None,
wake: int = IDLE,
) -> None:
"""
Create an irq object triggered by a real time clock alarm.
- ``trigger`` must be ``RTC.ALARM0``
- ``handler`` is the function to be called when the callback is triggered.
- ``wake`` specifies the sleep mode from where this interrupt can wake
up the system.
"""
class Timer:
"""
Hardware timers deal with timing of periods and events. Timers are perhaps
the most flexible and heterogeneous kind of hardware in MCUs and SoCs,
differently greatly from a model to a model. MicroPython's Timer class
defines a baseline operation of executing a callback with a given period
(or once after some delay), and allow specific boards to define more
non-standard behaviour (which thus won't be portable to other boards).
See discussion of :ref:`important constraints ` on
Timer callbacks.
.. note::
Memory can't be allocated inside irq handlers (an interrupt) and so
exceptions raised within a handler don't give much information. See
:func:`micropython.alloc_emergency_exception_buf` for how to get around this
limitation.
If you are using a WiPy board please refer to :ref:`machine.TimerWiPy `
instead of this class.
"""
ONE_SHOT: ClassVar[int] = ...
"""
Timer operating mode.
"""
PERIODIC: ClassVar[int] = ...
"""
Timer operating mode.
"""
@overload
def __init__(self, id: int, /):
"""
Construct a new timer object of the given id. Id of -1 constructs a
virtual timer (if supported by a board).
See ``init`` for parameters of initialisation.
"""
@overload
def __init__(
self,
id: int,
/,
*,
mode: int = PERIODIC,
period: int = -1,
callback: Callable[[Timer], None] | None = None,
):
"""
Construct a new timer object of the given id. Id of -1 constructs a
virtual timer (if supported by a board).
See ``init`` for parameters of initialisation.
"""
def init(
self,
*,
mode: int = PERIODIC,
period: int = -1,
callback: Callable[[Timer], None] | None = None,
) -> None:
"""
Initialise the timer. Example::
tim.init(period=100) # periodic with 100ms period
tim.init(mode=Timer.ONE_SHOT, period=1000) # one shot firing after 1000ms
Keyword arguments:
- ``mode`` can be one of:
- ``Timer.ONE_SHOT`` - The timer runs once until the configured
period of the channel expires.
- ``Timer.PERIODIC`` - The timer runs periodically at the configured
frequency of the channel.
"""
def deinit(self) -> None:
"""
Deinitialises the timer. Stops the timer, and disables the timer peripheral.
"""
class WDT:
"""
The WDT is used to restart the system when the application crashes and ends
up into a non recoverable state. Once started it cannot be stopped or
reconfigured in any way. After enabling, the application must "feed" the
watchdog periodically to prevent it from expiring and resetting the system.
Example usage::
from machine import WDT
wdt = WDT(timeout=2000) # enable it with a timeout of 2s
wdt.feed()
Availability of this class: pyboard, WiPy, esp8266, esp32.
"""
def __init__(self, *, id: int = 0, timeout: int = 5000):
"""
Create a WDT object and start it. The timeout must be given in milliseconds.
Once it is running the timeout cannot be changed and the WDT cannot be stopped either.
Notes: On the esp32 the minimum timeout is 1 second. On the esp8266 a timeout
cannot be specified, it is determined by the underlying system.
"""
def feed(self) -> None:
"""
Feed the WDT to prevent it from resetting the system. The application
should place this call in a sensible place ensuring that the WDT is
only fed after verifying that everything is functioning correctly.
"""
class SD:
"""
.. warning::
This is a non-standard class and is only available on the cc3200 port.
The SD card class allows to configure and enable the memory card
module of the WiPy and automatically mount it as ``/sd`` as part
of the file system. There are several pin combinations that can be
used to wire the SD card socket to the WiPy and the pins used can
be specified in the constructor. Please check the `pinout and alternate functions
table. `_ for
more info regarding the pins which can be remapped to be used with a SD card.
Example usage::
from machine import SD
import os
# clk cmd and dat0 pins must be passed along with
# their respective alternate functions
sd = machine.SD(pins=('GP10', 'GP11', 'GP15'))
os.mount(sd, '/sd')
# do normal file operations
"""
def __init__(
self,
id: int = 0,
pins: tuple[str, str, str] | tuple[Pin, Pin, Pin] = ("GP10", "GP11", "GP15"),
/,
):
"""
Create a SD card object. See ``init()`` for parameters if initialization.
"""
def init(
self,
id: int = 0,
pins: tuple[str, str, str] | tuple[Pin, Pin, Pin] = ("GP10", "GP11", "GP15"),
/,
) -> None:
"""
Enable the SD card. In order to initialize the card, give it a 3-tuple:
``(clk_pin, cmd_pin, dat0_pin)``.
"""
def deinit(self) -> None:
"""
Disable the SD card.
"""
# noinspection PyShadowingNames
class SDCard(AbstractBlockDev):
"""
SD cards are one of the most common small form factor removable storage media.
SD cards come in a variety of sizes and physical form factors. MMC cards are
similar removable storage devices while eMMC devices are electrically similar
storage devices designed to be embedded into other systems. All three form
share a common protocol for communication with their host system and high-level
support looks the same for them all. As such in MicroPython they are implemented
in a single class called :class:`machine.SDCard` .
Both SD and MMC interfaces support being accessed with a variety of bus widths.
When being accessed with a 1-bit wide interface they can be accessed using the
SPI protocol. Different MicroPython hardware platforms support different widths
and pin configurations but for most platforms there is a standard configuration
for any given hardware. In general constructing an ``SDCard`` object with without
passing any parameters will initialise the interface to the default card slot
for the current hardware. The arguments listed below represent the common
arguments that might need to be set in order to use either a non-standard slot
or a non-standard pin assignment. The exact subset of arguments supported will
vary from platform to platform.
Implementation-specific details
-------------------------------
Different implementations of the ``SDCard`` class on different hardware support
varying subsets of the options above.
PyBoard
```````
The standard PyBoard has just one slot. No arguments are necessary or supported.
ESP32
`````
The ESP32 provides two channels of SD/MMC hardware and also supports
access to SD Cards through either of the two SPI ports that are
generally available to the user. As a result the *slot* argument can
take a value between 0 and 3, inclusive. Slots 0 and 1 use the
built-in SD/MMC hardware while slots 2 and 3 use the SPI ports. Slot 0
supports 1, 4 or 8-bit wide access while slot 1 supports 1 or 4-bit
access; the SPI slots only support 1-bit access.
.. note:: Slot 0 is used to communicate with on-board flash memory
on most ESP32 modules and so will be unavailable to the
user.
.. note:: Most ESP32 modules that provide an SD card slot using the
dedicated hardware only wire up 1 data pin, so the default
value for *width* is 1.
The pins used by the dedicated SD/MMC hardware are fixed. The pins
used by the SPI hardware can be reassigned.
.. note:: If any of the SPI signals are remapped then all of the SPI
signals will pass through a GPIO multiplexer unit which
can limit the performance of high frequency signals. Since
the normal operating speed for SD cards is 40MHz this can
cause problems on some cards.
The default (and preferred) pin assignment are as follows:
====== ====== ====== ====== ======
Slot 0 1 2 3
------ ------ ------ ------ ------
Signal Pin Pin Pin Pin
====== ====== ====== ====== ======
sck 6 14 18 14
cmd 11 15
cs 5 15
miso 19 12
mosi 23 13
D0 7 2
D1 8 4
D2 9 12
D3 10 13
D4 16
D5 17
D6 5
D7 18
====== ====== ====== ====== ======
cc3200
``````
You can set the pins used for SPI access by passing a tuple as the
*pins* argument.
*Note:* The current cc3200 SD card implementation names the this class
:class:`machine.SD` rather than :class:`machine.SDCard` .
"""
def __init__(
self,
slot: int = 1,
width: int = 1,
cd: int | str | Pin | None = None,
wp: int | str | Pin | None = None,
sck: int | str | Pin | None = None,
miso: int | str | Pin | None = None,
mosi: int | str | Pin | None = None,
cs: int | str | Pin | None = None,
freq: int = 20000000,
/,
):
"""
This class provides access to SD or MMC storage cards using either
a dedicated SD/MMC interface hardware or through an SPI channel.
The class implements the block protocol defined by :class:`os.AbstractBlockDev`.
This allows the mounting of an SD card to be as simple as::
os.mount(machine.SDCard(), "/sd")
The constructor takes the following parameters:
- *slot* selects which of the available interfaces to use. Leaving this
unset will select the default interface.
- *width* selects the bus width for the SD/MMC interface.
- *cd* can be used to specify a card-detect pin.
- *wp* can be used to specify a write-protect pin.
- *sck* can be used to specify an SPI clock pin.
- *miso* can be used to specify an SPI miso pin.
- *mosi* can be used to specify an SPI mosi pin.
- *cs* can be used to specify an SPI chip select pin.
- *freq* selects the SD/MMC interface frequency in Hz (only supported on the ESP32).
"""
================================================
FILE: typehints/micropython/micropython.pyi
================================================
"""
access and control MicroPython internals.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/micropython.rst.
==============================================================
.. module:: micropython
:synopsis: access and control MicroPython internals
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import TypeVar, overload, Callable, Any, Final
_T: Final = TypeVar("_T")
_F: Final = TypeVar("_F", bound=Callable[..., Any])
def native(func: _F) -> _F:
"""
This causes the MicroPython compiler to emit unoptimised native CPU opcodes
rather than bytecode (normal) or optimised opcodes (viper) and is an optimisation,
for more information see
https://docs.micropython.org/en/latest/reference/speed_python.html#the-native-code-emitter.
"""
def viper(func: _F) -> _F:
"""
This causes the MicroPython compiler to emit optimised native CPU opcodes based on special typehints
rather than bytecode (normal) or unoptimised opcodes (native) and is an optimisation,
for more information see
https://docs.micropython.org/en/latest/reference/speed_python.html#the-viper-code-emitter.
"""
def const(expr: _T, /) -> _T:
"""
Used to declare that the expression is a constant so that the compile can
optimise it. The use of this function should be as follows::
from micropython import const
CONST_X = const(123)
CONST_Y = const(2 * CONST_X + 1)
Constants declared this way are still accessible as global variables from
outside the module they are declared in. On the other hand, if a constant
begins with an underscore then it is hidden, it is not available as a global
variable, and does not take up any memory during execution.
This `const` function is recognised directly by the MicroPython parser and is
provided as part of the :mod:`micropython` module mainly so that scripts can be
written which run under both CPython and MicroPython, by following the above
pattern.
"""
@overload
def opt_level() -> int:
"""
If *level* is given then this function sets the optimisation level for subsequent
compilation of scripts, and returns ``None``. Otherwise it returns the current
optimisation level.
The optimisation level controls the following compilation features:
- Assertions: at level 0 assertion statements are enabled and compiled into the
bytecode; at levels 1 and higher assertions are not compiled.
- Built-in ``__debug__`` variable: at level 0 this variable expands to ``True``;
at levels 1 and higher it expands to ``False``.
- Source-code line numbers: at levels 0, 1 and 2 source-code line number are
stored along with the bytecode so that exceptions can report the line number
they occurred at; at levels 3 and higher line numbers are not stored.
The default optimisation level is usually level 0.
"""
@overload
def opt_level(level: int, /) -> None:
"""
If *level* is given then this function sets the optimisation level for subsequent
compilation of scripts, and returns ``None``. Otherwise it returns the current
optimisation level.
The optimisation level controls the following compilation features:
- Assertions: at level 0 assertion statements are enabled and compiled into the
bytecode; at levels 1 and higher assertions are not compiled.
- Built-in ``__debug__`` variable: at level 0 this variable expands to ``True``;
at levels 1 and higher it expands to ``False``.
- Source-code line numbers: at levels 0, 1 and 2 source-code line number are
stored along with the bytecode so that exceptions can report the line number
they occurred at; at levels 3 and higher line numbers are not stored.
The default optimisation level is usually level 0.
"""
def alloc_emergency_exception_buf(size: int, /) -> None:
"""
Allocate *size* bytes of RAM for the emergency exception buffer (a good
size is around 100 bytes). The buffer is used to create exceptions in cases
when normal RAM allocation would fail (eg within an interrupt handler) and
therefore give useful traceback information in these situations.
A good way to use this function is to put it at the start of your main script
(eg ``boot.py`` or ``main.py``) and then the emergency exception buffer will be active
for all the code following it.
"""
@overload
def mem_info() -> None:
"""
Print information about currently used memory. If the *verbose* argument
is given then extra information is printed.
The information that is printed is implementation dependent, but currently
includes the amount of stack and heap used. In verbose mode it prints out
the entire heap indicating which blocks are used and which are free.
"""
@overload
def mem_info(verbose: Any, /) -> None:
"""
Print information about currently used memory. If the *verbose* argument
is given then extra information is printed.
The information that is printed is implementation dependent, but currently
includes the amount of stack and heap used. In verbose mode it prints out
the entire heap indicating which blocks are used and which are free.
"""
@overload
def qstr_info() -> None:
"""
Print information about currently interned strings. If the *verbose*
argument is given then extra information is printed.
The information that is printed is implementation dependent, but currently
includes the number of interned strings and the amount of RAM they use. In
verbose mode it prints out the names of all RAM-interned strings.
"""
@overload
def qstr_info(verbose: bool, /) -> None:
"""
Print information about currently interned strings. If the *verbose*
argument is given then extra information is printed.
The information that is printed is implementation dependent, but currently
includes the number of interned strings and the amount of RAM they use. In
verbose mode it prints out the names of all RAM-interned strings.
"""
def stack_use() -> int:
"""
Return an integer representing the current amount of stack that is being
used. The absolute value of this is not particularly useful, rather it
should be used to compute differences in stack usage at different points.
"""
def heap_lock() -> None:
"""
Lock or unlock the heap. When locked no memory allocation can occur and a
`MemoryError` will be raised if any heap allocation is attempted.
`heap_locked()` returns a true value if the heap is currently locked.
These functions can be nested, ie `heap_lock()` can be called multiple times
in a row and the lock-depth will increase, and then `heap_unlock()` must be
called the same number of times to make the heap available again.
Both `heap_unlock()` and `heap_locked()` return the current lock depth
(after unlocking for the former) as a non-negative integer, with 0 meaning
the heap is not locked.
If the REPL becomes active with the heap locked then it will be forcefully
unlocked.
Note: `heap_locked()` is not enabled on most ports by default,
requires ``MICROPY_PY_MICROPYTHON_HEAP_LOCKED``.
"""
def heap_unlock() -> None:
"""
Lock or unlock the heap. When locked no memory allocation can occur and a
`MemoryError` will be raised if any heap allocation is attempted.
`heap_locked()` returns a true value if the heap is currently locked.
These functions can be nested, ie `heap_lock()` can be called multiple times
in a row and the lock-depth will increase, and then `heap_unlock()` must be
called the same number of times to make the heap available again.
Both `heap_unlock()` and `heap_locked()` return the current lock depth
(after unlocking for the former) as a non-negative integer, with 0 meaning
the heap is not locked.
If the REPL becomes active with the heap locked then it will be forcefully
unlocked.
Note: `heap_locked()` is not enabled on most ports by default,
requires ``MICROPY_PY_MICROPYTHON_HEAP_LOCKED``.
"""
def heap_locked() -> bool:
"""
Lock or unlock the heap. When locked no memory allocation can occur and a
`MemoryError` will be raised if any heap allocation is attempted.
`heap_locked()` returns a true value if the heap is currently locked.
These functions can be nested, ie `heap_lock()` can be called multiple times
in a row and the lock-depth will increase, and then `heap_unlock()` must be
called the same number of times to make the heap available again.
Both `heap_unlock()` and `heap_locked()` return the current lock depth
(after unlocking for the former) as a non-negative integer, with 0 meaning
the heap is not locked.
If the REPL becomes active with the heap locked then it will be forcefully
unlocked.
Note: `heap_locked()` is not enabled on most ports by default,
requires ``MICROPY_PY_MICROPYTHON_HEAP_LOCKED``.
"""
def kbd_intr(chr: int) -> None:
"""
Set the character that will raise a `KeyboardInterrupt` exception. By
default this is set to 3 during script execution, corresponding to Ctrl-C.
Passing -1 to this function will disable capture of Ctrl-C, and passing 3
will restore it.
This function can be used to prevent the capturing of Ctrl-C on the
incoming stream of characters that is usually used for the REPL, in case
that stream is used for other purposes.
"""
def schedule(func: Callable[[_T], None], arg: _T, /) -> None:
"""
Schedule the function *func* to be executed "very soon". The function
is passed the value *arg* as its single argument. "Very soon" means that
the MicroPython runtime will do its best to execute the function at the
earliest possible time, given that it is also trying to be efficient, and
that the following conditions hold:
- A scheduled function will never preempt another scheduled function.
- Scheduled functions are always executed "between opcodes" which means
that all fundamental Python operations (such as appending to a list)
are guaranteed to be atomic.
- A given port may define "critical regions" within which scheduled
functions will never be executed. Functions may be scheduled within
a critical region but they will not be executed until that region
is exited. An example of a critical region is a preempting interrupt
handler (an IRQ).
A use for this function is to schedule a callback from a preempting IRQ.
Such an IRQ puts restrictions on the code that runs in the IRQ (for example
the heap may be locked) and scheduling a function to call later will lift
those restrictions.
Note: If `schedule()` is called from a preempting IRQ, when memory
allocation is not allowed and the callback to be passed to `schedule()` is
a bound method, passing this directly will fail. This is because creating a
reference to a bound method causes memory allocation. A solution is to
create a reference to the method in the class constructor and to pass that
reference to `schedule()`. This is discussed in detail here
:ref:`reference documentation ` under "Creation of Python
objects".
There is a finite queue to hold the scheduled functions and `schedule()`
will raise a `RuntimeError` if the queue is full.
"""
================================================
FILE: typehints/micropython/neopixel.pyi
================================================
"""
control of WS2812 / NeoPixel LEDs.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/neopixel.rst.
=====================================================
.. module:: neopixel
:synopsis: control of WS2812 / NeoPixel LEDs
This module provides a driver for WS2818 / NeoPixel LEDs.
.. note:: This module is only included by default on the ESP8266 and ESP32
ports. On STM32 / Pyboard, you can `download the module
`_
and copy it to the filesystem.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import Final
from machine import Pin
_Color: Final = tuple[int, int, int] | tuple[int, int, int, int]
class NeoPixel:
"""
This class stores pixel data for a WS2812 LED strip connected to a pin. The
application should set pixel data and then call :meth:`NeoPixel.write`
when it is ready to update the strip.
For example::
import neopixel
# 32 LED strip connected to X8.
p = machine.Pin.board.X8
n = neopixel.NeoPixel(p, 32)
# Draw a red gradient.
for i in range(32):
n[i] = (i * 8, 0, 0)
# Update the strip.
n.write()
"""
def __init__(self, pin: Pin, n: int, /, *, bpp: int = 3, timing: int = 1):
"""
Construct an NeoPixel object. The parameters are:
- *pin* is a machine.Pin instance.
- *n* is the number of LEDs in the strip.
- *bpp* is 3 for RGB LEDs, and 4 for RGBW LEDs.
- *timing* is 0 for 400KHz, and 1 for 800kHz LEDs (most are 800kHz).
"""
def fill(self, pixel: _Color, /) -> None:
"""
Sets the value of all pixels to the specified *pixel* value (i.e. an
RGB/RGBW tuple).
"""
def __len__(self) -> int:
"""
Returns the number of LEDs in the strip.
"""
def __setitem__(self, index: int, val: _Color, /) -> None:
"""
Set the pixel at *index* to the value, which is an RGB/RGBW tuple.
"""
def __getitem__(self, index: int, /) -> _Color:
"""
Returns the pixel at *index* as an RGB/RGBW tuple.
"""
def write(self) -> None:
"""
Writes the current pixel data to the strip.
"""
================================================
FILE: typehints/micropython/network.pyi
================================================
"""
network configuration.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/network.rst.
https://github.com/Josverl/micropython-stubs/blob/main/stubs/micropython-v1_19_1-esp32-GENERIC/network.py
****************************************
.. module:: network
:synopsis: network configuration
This module provides network drivers and routing configuration. To use this
module, a MicroPython variant/build with network capabilities must be installed.
Network drivers for specific hardware are available within this module and are
used to configure hardware network interface(s). Network services provided
by configured interfaces are then available for use via the :mod:`socket`
module.
For example::
# connect/ show IP config a specific network interface
# see below for examples of specific drivers
import network
import time
nic = network.Driver(...)
if not nic.isconnected():
nic.connect()
print("Waiting for connection...")
while not nic.isconnected():
time.sleep(1)
print(nic.ifconfig())
# now use socket as usual
import socket
addr = socket.getaddrinfo('micropython.org', 80)[0][-1]
s = socket.socket()
s.connect(addr)
s.send(b'GET / HTTP/1.1\r\nHost: micropython.org\r\n\r\n')
data = s.recv(1000)
s.close()
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from abc import abstractmethod
from typing import Protocol, Callable, overload, Any, ClassVar, Final
import pyb
@overload
def country() -> str:
"""
Get the two-letter ISO 3166-1 Alpha-2 country code to be used for
radio compliance.
The default code ``"XX"`` represents the "worldwide" region.
"""
@overload
def country(code: str) -> None:
"""
Set the two-letter ISO 3166-1 Alpha-2 country code to be used for
radio compliance.
The default code ``"XX"`` represents the "worldwide" region.
"""
@overload
def hostname() -> str:
"""Get the hostname that will identify this device on the network. It will
be used by all interfaces.
This hostname is used for:
* Sending to the DHCP server in the client request. (If using DHCP)
* Broadcasting via mDNS. (If enabled)
The default hostname is typically the name of the board.
"""
@overload
def hostname(name: str) -> None:
"""Set the hostname that will identify this device on the network. It will
be used by all interfaces.
This hostname is used for:
* Sending to the DHCP server in the client request. (If using DHCP)
* Broadcasting via mDNS. (If enabled)
A change in hostname is typically only applied during connection. For DHCP
this is because the hostname is part of the DHCP client request, and the
implementation of mDNS in most ports only initialises the hostname once
during connection. For this reason, you must set the hostname before
activating/connecting your network interfaces.
The length of the hostname is limited to 32 characters.
:term:`MicroPython ports ` may choose to set a lower
limit for memory reasons. If the given name does not fit, a `ValueError`
is raised.
The default hostname is typically the name of the board.
"""
MODE_11B: Final[int] = ...
"""IEEE 802.11b"""
MODE_11G: Final[int] = ...
"""IEEE 802.11g"""
MODE_11N: Final[int] = ...
"""IEEE 802.11n"""
STA_IF: int = 0
"""station interface"""
AP_IF: int = 1
"""access point interface"""
STAT_IDLE: int = 0
"""no connection and no activity"""
STAT_CONNECTING: int = 1
"""connecting in progress"""
STAT_WRONG_PASSWORD: int = 2
"""failed due to incorrect password"""
STAT_NO_AP_FOUND: int = 3
"""failed because no access point replied"""
STAT_CONNECT_FAIL: int = 4
"""failed due to other problems"""
STAT_GOT_IP: int = 5
"""connection successful"""
AUTH_OPEN: int = 0
AUTH_WEP:int = 1
AUTH_WPA_PSK: int = 2
AUTH_WPA2_PSK: int = 3
AUTH_WPA_WPA2_PSK: int = 4
@overload
def phy_mode() -> int:
"""
Get or set the PHY mode.
If the *mode* parameter is provided, sets the mode to its value. If
the function is called without parameters, returns the current mode.
The possible modes are defined as constants:
* ``MODE_11B`` -- IEEE 802.11b,
* ``MODE_11G`` -- IEEE 802.11g,
* ``MODE_11N`` -- IEEE 802.11n.
Availability: ESP8266.
"""
@overload
def phy_mode(mode: int, /) -> None:
"""
Get or set the PHY mode.
If the *mode* parameter is provided, sets the mode to its value. If
the function is called without parameters, returns the current mode.
The possible modes are defined as constants:
* ``MODE_11B`` -- IEEE 802.11b,
* ``MODE_11G`` -- IEEE 802.11g,
* ``MODE_11N`` -- IEEE 802.11n.
Availability: ESP8266.
"""
class AbstractNIC(Protocol):
"""
Common network adapter interface
================================
This section describes an (implied) abstract base class for all network
interface classes implemented by :term:`MicroPython ports `
for different hardware. This means that MicroPython does not actually
provide ``AbstractNIC`` class, but any actual NIC class, as described
in the following sections, implements methods as described here.
"""
@abstractmethod
def __init__(self, id: Any = None, /, *args: Any, **kwargs: Any):
"""
Instantiate a network interface object. Parameters are network interface
dependent. If there are more than one interface of the same type, the first
parameter should be `id`.
"""
@overload
@abstractmethod
def active(self, /) -> bool:
"""
Activate ("up") or deactivate ("down") the network interface, if
a boolean argument is passed. Otherwise, query current state if
no argument is provided. Most other methods require an active
interface (behaviour of calling them on inactive interface is
undefined).
"""
@overload
@abstractmethod
def active(self, is_active: bool, /) -> None:
"""
Activate ("up") or deactivate ("down") the network interface, if
a boolean argument is passed. Otherwise, query current state if
no argument is provided. Most other methods require an active
interface (behaviour of calling them on inactive interface is
undefined).
"""
@overload
@abstractmethod
def connect(self, key: str | None = None, /, **kwargs: Any) -> None:
"""
Connect the interface to a network. This method is optional, and
available only for interfaces which are not "always connected".
If no parameters are given, connect to the default (or the only)
service. If a single parameter is given, it is the primary identifier
of a service to connect to. It may be accompanied by a key
(password) required to access said service. There can be further
arbitrary keyword-only parameters, depending on the networking medium
type and/or particular device. Parameters can be used to: a)
specify alternative service identifier types; b) provide additional
connection parameters. For various medium types, there are different
sets of predefined/recommended parameters, among them:
* WiFi: *bssid* keyword to connect to a specific BSSID (MAC address)
"""
@overload
@abstractmethod
def connect(
self, service_id: Any, key: str | None = None, /, **kwargs: Any
) -> None:
"""
Connect the interface to a network. This method is optional, and
available only for interfaces which are not "always connected".
If no parameters are given, connect to the default (or the only)
service. If a single parameter is given, it is the primary identifier
of a service to connect to. It may be accompanied by a key
(password) required to access said service. There can be further
arbitrary keyword-only parameters, depending on the networking medium
type and/or particular device. Parameters can be used to: a)
specify alternative service identifier types; b) provide additional
connection parameters. For various medium types, there are different
sets of predefined/recommended parameters, among them:
* WiFi: *bssid* keyword to connect to a specific BSSID (MAC address)
"""
@abstractmethod
def disconnect(self) -> None:
"""
Disconnect from network.
"""
@abstractmethod
def isconnected(self) -> bool:
"""
Returns ``True`` if connected to network, otherwise returns ``False``.
"""
@abstractmethod
def scan(self, **kwargs: Any) -> list[tuple[str, ...]]:
"""
Scan for the available network services/connections. Returns a
list of tuples with discovered service parameters. For various
network media, there are different variants of predefined/
recommended tuple formats, among them:
* WiFi: (ssid, bssid, channel, RSSI, authmode, hidden). There
may be further fields, specific to a particular device.
The function may accept additional keyword arguments to filter scan
results (e.g. scan for a particular service, on a particular channel,
for services of a particular set, etc.), and to affect scan
duration and other parameters. Where possible, parameter names
should match those in connect().
"""
@overload
@abstractmethod
def status(self) -> Any:
"""
Query dynamic status information of the interface. When called with no
argument the return value describes the network link status. Otherwise
*param* should be a string naming the particular status parameter to
retrieve.
The return types and values are dependent on the network
medium/technology. Some of the parameters that may be supported are:
* WiFi STA: use ``'rssi'`` to retrieve the RSSI of the AP signal
* WiFi AP: use ``'stations'`` to retrieve a list of all the STAs
connected to the AP. The list contains tuples of the form
(MAC, RSSI).
"""
@overload
@abstractmethod
def status(self, param: str, /) -> Any:
"""
Query dynamic status information of the interface. When called with no
argument the return value describes the network link status. Otherwise
*param* should be a string naming the particular status parameter to
retrieve.
The return types and values are dependent on the network
medium/technology. Some of the parameters that may be supported are:
* WiFi STA: use ``'rssi'`` to retrieve the RSSI of the AP signal
* WiFi AP: use ``'stations'`` to retrieve a list of all the STAs
connected to the AP. The list contains tuples of the form
(MAC, RSSI).
"""
@overload
@abstractmethod
def ifconfig(self) -> tuple[str, str, str, str]:
"""
Get/set IP-level network interface parameters: IP address, subnet mask,
gateway and DNS server. When called with no arguments, this method returns
a 4-tuple with the above information. To set the above values, pass a
4-tuple with the required information. For example::
nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
"""
@overload
@abstractmethod
def ifconfig(self, ip_mask_gateway_dns: tuple[str, str, str, str], /) -> None:
"""
Get/set IP-level network interface parameters: IP address, subnet mask,
gateway and DNS server. When called with no arguments, this method returns
a 4-tuple with the above information. To set the above values, pass a
4-tuple with the required information. For example::
nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
"""
@overload
@abstractmethod
def config(self, param: str, /) -> Any:
"""
Get or set general network interface parameters. These methods allow to work
with additional parameters beyond standard IP configuration (as dealt with by
`ifconfig()`). These include network-specific and hardware-specific
parameters. For setting parameters, the keyword argument
syntax should be used, and multiple parameters can be set at once. For
querying, a parameter name should be quoted as a string, and only one
parameter can be queried at a time::
# Set WiFi access point name (formally known as ESSID) and WiFi channel
ap.config(essid='My AP', channel=11)
# Query params one by one
print(ap.config('essid'))
print(ap.config('channel'))
"""
@overload
@abstractmethod
def config(self, **kwargs: Any) -> None:
"""
Get or set general network interface parameters. These methods allow to work
with additional parameters beyond standard IP configuration (as dealt with by
`ifconfig()`). These include network-specific and hardware-specific
parameters. For setting parameters, the keyword argument
syntax should be used, and multiple parameters can be set at once. For
querying, a parameter name should be quoted as a string, and only one
parameter can be queried at a time::
# Set WiFi access point name (formally known as ESSID) and WiFi channel
ap.config(essid='My AP', channel=11)
# Query params one by one
print(ap.config('essid'))
print(ap.config('channel'))
"""
class WLAN:
"""
This class provides a driver for WiFi network processors. Example usage::
import network
# enable station interface and connect to WiFi access point
nic = network.WLAN(network.STA_IF)
nic.active(True)
nic.connect('your-ssid', 'your-password')
# now use sockets as usual
"""
def __init__(self, interface_id: int, /):
"""
Create a WLAN network interface object. Supported interfaces are
``network.STA_IF`` (station aka client, connects to upstream WiFi access
points) and ``network.AP_IF`` (access point, allows other WiFi clients to
connect). Availability of the methods below depends on interface type.
For example, only STA interface may `WLAN.connect()` to an access point.
"""
@overload
def active(self, /) -> bool:
"""
Activate ("up") or deactivate ("down") network interface, if boolean
argument is passed. Otherwise, query current state if no argument is
provided. Most other methods require active interface.
"""
@overload
def active(self, is_active: bool, /) -> None:
"""
Activate ("up") or deactivate ("down") network interface, if boolean
argument is passed. Otherwise, query current state if no argument is
provided. Most other methods require active interface.
"""
def connect(
self,
ssid: str | None = None,
password: str | None = None,
/,
*,
bssid: bytes | None = None,
) -> None:
"""
Connect to the specified wireless network, using the specified password.
If *bssid* is given then the connection will be restricted to the
access-point with that MAC address (the *ssid* must also be specified
in this case).
"""
def disconnect(self) -> None:
"""
Disconnect from the currently connected wireless network.
"""
def scan(self) -> tuple[str, bytes, int, int, int]:
"""
Scan for the available wireless networks.
Hidden networks -- where the SSID is not broadcast -- will also be scanned
if the WLAN interface allows it.
Scanning is only possible on STA interface. Returns list of tuples with
the information about WiFi access points:
(ssid, bssid, channel, RSSI, authmode, hidden)
*bssid* is hardware address of an access point, in binary form, returned as
bytes object. You can use `binascii.hexlify()` to convert it to ASCII form.
There are five values for authmode:
* 0 -- open
* 1 -- WEP
* 2 -- WPA-PSK
* 3 -- WPA2-PSK
* 4 -- WPA/WPA2-PSK
and two for hidden:
* 0 -- visible
* 1 -- hidden
"""
@overload
def status(self) -> int:
"""
Return the current status of the wireless connection.
When called with no argument the return value describes the network link status.
The possible statuses are defined as constants:
* ``STAT_IDLE`` -- no connection and no activity,
* ``STAT_CONNECTING`` -- connecting in progress,
* ``STAT_WRONG_PASSWORD`` -- failed due to incorrect password,
* ``STAT_NO_AP_FOUND`` -- failed because no access point replied,
* ``STAT_CONNECT_FAIL`` -- failed due to other problems,
* ``STAT_GOT_IP`` -- connection successful.
When called with one argument *param* should be a string naming the status
parameter to retrieve. Supported parameters in WiFI STA mode are: ``'rssi'``.
"""
@overload
def status(self, param: str, /) -> int:
"""
Return the current status of the wireless connection.
When called with no argument the return value describes the network link status.
The possible statuses are defined as constants:
* ``STAT_IDLE`` -- no connection and no activity,
* ``STAT_CONNECTING`` -- connecting in progress,
* ``STAT_WRONG_PASSWORD`` -- failed due to incorrect password,
* ``STAT_NO_AP_FOUND`` -- failed because no access point replied,
* ``STAT_CONNECT_FAIL`` -- failed due to other problems,
* ``STAT_GOT_IP`` -- connection successful.
When called with one argument *param* should be a string naming the status
parameter to retrieve. Supported parameters in WiFI STA mode are: ``'rssi'``.
"""
def isconnected(self) -> bool:
"""
In case of STA mode, returns ``True`` if connected to a WiFi access
point and has a valid IP address. In AP mode returns ``True`` when a
station is connected. Returns ``False`` otherwise.
"""
@overload
def ifconfig(self) -> tuple[str, str, str, str]:
"""
Get/set IP-level network interface parameters: IP address, subnet mask,
gateway and DNS server. When called with no arguments, this method returns
a 4-tuple with the above information. To set the above values, pass a
4-tuple with the required information. For example::
nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
"""
@overload
def ifconfig(self, ip_mask_gateway_dns: tuple[str, str, str, str], /) -> None:
"""
Get/set IP-level network interface parameters: IP address, subnet mask,
gateway and DNS server. When called with no arguments, this method returns
a 4-tuple with the above information. To set the above values, pass a
4-tuple with the required information. For example::
nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
"""
@overload
def config(self, param: str, /) -> Any:
"""
Get or set general network interface parameters. These methods allow to work
with additional parameters beyond standard IP configuration (as dealt with by
`WLAN.ifconfig()`). These include network-specific and hardware-specific
parameters. For setting parameters, keyword argument syntax should be used,
multiple parameters can be set at once. For querying, parameters name should
be quoted as a string, and only one parameter can be queries at time::
# Set WiFi access point name (formally known as ESSID) and WiFi channel
ap.config(essid='My AP', channel=11)
# Query params one by one
print(ap.config('essid'))
print(ap.config('channel'))
Following are commonly supported parameters (availability of a specific parameter
depends on network technology type, driver, and :term:`MicroPython port`).
============= ===========
Parameter Description
============= ===========
mac MAC address (bytes)
essid WiFi access point name (string)
channel WiFi channel (integer)
hidden Whether ESSID is hidden (boolean)
authmode Authentication mode supported (enumeration, see module constants)
password Access password (string)
dhcp_hostname The DHCP hostname to use
reconnects Number of reconnect attempts to make (integer, 0=none, -1=unlimited)
============= ===========
"""
@overload
def config(self, **kwargs: Any) -> None:
"""
Get or set general network interface parameters. These methods allow to work
with additional parameters beyond standard IP configuration (as dealt with by
`WLAN.ifconfig()`). These include network-specific and hardware-specific
parameters. For setting parameters, keyword argument syntax should be used,
multiple parameters can be set at once. For querying, parameters name should
be quoted as a string, and only one parameter can be queries at time::
# Set WiFi access point name (formally known as ESSID) and WiFi channel
ap.config(essid='My AP', channel=11)
# Query params one by one
print(ap.config('essid'))
print(ap.config('channel'))
Following are commonly supported parameters (availability of a specific parameter
depends on network technology type, driver, and :term:`MicroPython port`).
============= ===========
Parameter Description
============= ===========
mac MAC address (bytes)
essid WiFi access point name (string)
channel WiFi channel (integer)
hidden Whether ESSID is hidden (boolean)
authmode Authentication mode supported (enumeration, see module constants)
password Access password (string)
dhcp_hostname The DHCP hostname to use
reconnects Number of reconnect attempts to make (integer, 0=none, -1=unlimited)
============= ===========
"""
class WLANWiPy:
"""
.. note::
This class is a non-standard WLAN implementation for the WiPy.
It is available simply as ``network.WLAN`` on the WiPy but is named in the
documentation below as ``network.WLANWiPy`` to distinguish it from the
more general :ref:`network.WLAN ` class.
This class provides a driver for the WiFi network processor in the WiPy. Example usage::
import network
import time
# setup as a station
wlan = network.WLAN(mode=WLAN.STA)
wlan.connect('your-ssid', auth=(WLAN.WPA2, 'your-key'))
while not wlan.isconnected():
time.sleep_ms(50)
print(wlan.ifconfig())
# now use socket as usual
...
"""
STA: ClassVar[int] = ...
"""
selects the WLAN mode
"""
AP: ClassVar[int] = ...
"""
selects the WLAN mode
"""
WEP: ClassVar[int] = ...
"""
selects the network security
"""
WPA: ClassVar[int] = ...
"""
selects the network security
"""
WPA2: ClassVar[int] = ...
"""
selects the network security
"""
INT_ANT: ClassVar[int] = ...
"""
selects the antenna type
"""
EXT_ANT: ClassVar[int] = ...
"""
selects the antenna type
"""
@overload
def __init__(self, id: int = 0, /):
"""
Create a WLAN object, and optionally configure it. See `init()` for params of configuration.
.. note::
The ``WLAN`` constructor is special in the sense that if no arguments besides the id are given,
it will return the already existing ``WLAN`` instance without re-configuring it. This is
because ``WLAN`` is a system feature of the WiPy. If the already existing instance is not
initialized it will do the same as the other constructors an will initialize it with default
values.
"""
@overload
def __init__(
self,
id: int,
/,
*,
mode: int,
ssid: str,
auth: tuple[str, str],
channel: int,
antenna: int,
):
"""
Create a WLAN object, and optionally configure it. See `init()` for params of configuration.
.. note::
The ``WLAN`` constructor is special in the sense that if no arguments besides the id are given,
it will return the already existing ``WLAN`` instance without re-configuring it. This is
because ``WLAN`` is a system feature of the WiPy. If the already existing instance is not
initialized it will do the same as the other constructors an will initialize it with default
values.
"""
def init(
self,
mode: int,
/,
*,
ssid: str,
auth: tuple[str, str],
channel: int,
antenna: int,
) -> bool:
"""
Set or get the WiFi network processor configuration.
Arguments are:
- *mode* can be either ``WLAN.STA`` or ``WLAN.AP``.
- *ssid* is a string with the ssid name. Only needed when mode is ``WLAN.AP``.
- *auth* is a tuple with (sec, key). Security can be ``None``, ``WLAN.WEP``,
``WLAN.WPA`` or ``WLAN.WPA2``. The key is a string with the network password.
If ``sec`` is ``WLAN.WEP`` the key must be a string representing hexadecimal
values (e.g. 'ABC1DE45BF'). Only needed when mode is ``WLAN.AP``.
- *channel* a number in the range 1-11. Only needed when mode is ``WLAN.AP``.
- *antenna* selects between the internal and the external antenna. Can be either
``WLAN.INT_ANT`` or ``WLAN.EXT_ANT``.
For example, you can do::
# create and configure as an access point
wlan.init(mode=WLAN.AP, ssid='wipy-wlan', auth=(WLAN.WPA2,'www.wipy.io'), channel=7, antenna=WLAN.INT_ANT)
or::
# configure as an station
wlan.init(mode=WLAN.STA)
"""
def connect(
self,
ssid: str,
/,
*,
auth: tuple[str, str] | None = None,
bssid: bytes | None = None,
timeout: int | None = None,
) -> None:
"""
Connect to a WiFi access point using the given SSID, and other security
parameters.
- *auth* is a tuple with (sec, key). Security can be ``None``, ``WLAN.WEP``,
``WLAN.WPA`` or ``WLAN.WPA2``. The key is a string with the network password.
If ``sec`` is ``WLAN.WEP`` the key must be a string representing hexadecimal
values (e.g. 'ABC1DE45BF').
- *bssid* is the MAC address of the AP to connect to. Useful when there are several
APs with the same ssid.
- *timeout* is the maximum time in milliseconds to wait for the connection to succeed.
"""
def scan(self) -> tuple[str, bytes, int, int | None, int]:
"""
Performs a network scan and returns a list of named tuples with (ssid, bssid, sec, channel, rssi).
Note that channel is always ``None`` since this info is not provided by the WiPy.
"""
def disconnect(self) -> None:
"""
Disconnect from the WiFi access point.
"""
def isconnected(self) -> bool:
"""
In case of STA mode, returns ``True`` if connected to a WiFi access point and has a valid IP address.
In AP mode returns ``True`` when a station is connected, ``False`` otherwise.
"""
@overload
def ifconfig(self, if_id: int = 0, /) -> tuple[str, str, str, str]:
"""
With no parameters given returns a 4-tuple of *(ip, subnet_mask, gateway, DNS_server)*.
if ``'dhcp'`` is passed as a parameter then the DHCP client is enabled and the IP params
are negotiated with the AP.
If the 4-tuple config is given then a static IP is configured. For instance::
wlan.ifconfig(config=('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
"""
@overload
def ifconfig(
self, if_id: int = 0, /, *, config: str | tuple[str, str, str, str]
) -> None:
"""
With no parameters given returns a 4-tuple of *(ip, subnet_mask, gateway, DNS_server)*.
if ``'dhcp'`` is passed as a parameter then the DHCP client is enabled and the IP params
are negotiated with the AP.
If the 4-tuple config is given then a static IP is configured. For instance::
wlan.ifconfig(config=('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
"""
@overload
def mode(self) -> int:
"""
Get or set the WLAN mode.
"""
@overload
def mode(self, mode: int, /) -> None:
"""
Get or set the WLAN mode.
"""
@overload
def ssid(self) -> str:
"""
Get or set the SSID when in AP mode.
"""
@overload
def ssid(self, ssid: str, /) -> None:
"""
Get or set the SSID when in AP mode.
"""
@overload
def auth(self) -> int:
"""
Get or set the authentication type when in AP mode.
"""
@overload
def auth(self, auth: int, /) -> None:
"""
Get or set the authentication type when in AP mode.
"""
@overload
def channel(self) -> int:
"""
Get or set the channel (only applicable in AP mode).
"""
@overload
def channel(self, channel: int, /) -> None:
"""
Get or set the channel (only applicable in AP mode).
"""
@overload
def antenna(self) -> int:
"""
Get or set the antenna type (external or internal).
"""
@overload
def antenna(self, antenna: int, /) -> None:
"""
Get or set the antenna type (external or internal).
"""
@overload
def mac(self) -> bytes:
"""
Get or set a 6-byte long bytes object with the MAC address.
"""
@overload
def mac(self, mac: bytes, /) -> None:
"""
Get or set a 6-byte long bytes object with the MAC address.
"""
def irq(self, *, handler: Callable[[], None], wake: int) -> Any:
"""
Create a callback to be triggered when a WLAN event occurs during ``machine.SLEEP``
mode. Events are triggered by socket activity or by WLAN connection/disconnection.
- *handler* is the function that gets called when the IRQ is triggered.
- *wake* must be ``machine.SLEEP``.
Returns an IRQ object.
"""
class CC3K:
"""
This class provides a driver for CC3000 WiFi modules. Example usage::
import network
nic = network.CC3K(pyb.SPI(2), pyb.Pin.board.Y5, pyb.Pin.board.Y4, pyb.Pin.board.Y3)
nic.connect('your-ssid', 'your-password')
while not nic.isconnected():
pyb.delay(50)
print(nic.ifconfig())
# now use socket as usual
...
For this example to work the CC3000 module must have the following connections:
- MOSI connected to Y8
- MISO connected to Y7
- CLK connected to Y6
- CS connected to Y5
- VBEN connected to Y4
- IRQ connected to Y3
It is possible to use other SPI buses and other pins for CS, VBEN and IRQ.
"""
WEP: ClassVar[int] = ...
"""
security type to use
"""
WPA: ClassVar[int] = ...
"""
security type to use
"""
WPA2: ClassVar[int] = ...
"""
security type to use
"""
def __init__(
self, spi: pyb.SPI, pin_cs: pyb.Pin, pin_en: pyb.Pin, pin_irq: pyb.Pin, /
):
"""
Create a CC3K driver object, initialise the CC3000 module using the given SPI bus
and pins, and return the CC3K object.
Arguments are:
- *spi* is an :ref:`SPI object ` which is the SPI bus that the CC3000 is
connected to (the MOSI, MISO and CLK pins).
- *pin_cs* is a :ref:`Pin object ` which is connected to the CC3000 CS pin.
- *pin_en* is a :ref:`Pin object ` which is connected to the CC3000 VBEN pin.
- *pin_irq* is a :ref:`Pin object ` which is connected to the CC3000 IRQ pin.
All of these objects will be initialised by the driver, so there is no need to
initialise them yourself. For example, you can use::
nic = network.CC3K(pyb.SPI(2), pyb.Pin.board.Y5, pyb.Pin.board.Y4, pyb.Pin.board.Y3)
"""
def connect(
self,
ssid: str,
key: str | None = None,
/,
*,
security: int = WPA2,
bssid: bytes | None = None,
) -> None:
"""
Connect to a WiFi access point using the given SSID, and other security
parameters.
"""
def disconnect(self) -> None:
"""
Disconnect from the WiFi access point.
"""
def isconnected(self) -> bool:
"""
Returns True if connected to a WiFi access point and has a valid IP address,
False otherwise.
"""
def ifconfig(self) -> tuple[str, str, str, str, str, str, str]:
"""
Returns a 7-tuple with (ip, subnet mask, gateway, DNS server, DHCP server,
MAC address, SSID).
"""
def patch_version(self) -> str:
"""
Return the version of the patch program (firmware) on the CC3000.
"""
def patch_program(self, cmd: str, /) -> None:
"""
Upload the current firmware to the CC3000. You must pass 'pgm' as the first
argument in order for the upload to proceed.
"""
class WIZNET5K:
"""
This class allows you to control WIZnet5x00 Ethernet adaptors based on
the W5200 and W5500 chipsets. The particular chipset that is supported
by the firmware is selected at compile-time via the MICROPY_PY_WIZNET5K
option.
Example usage::
import network
nic = network.WIZNET5K(pyb.SPI(1), pyb.Pin.board.X5, pyb.Pin.board.X4)
print(nic.ifconfig())
# now use socket as usual
...
For this example to work the WIZnet5x00 module must have the following connections:
- MOSI connected to X8
- MISO connected to X7
- SCLK connected to X6
- nSS connected to X5
- nRESET connected to X4
It is possible to use other SPI buses and other pins for nSS and nRESET.
"""
def __init__(self, spi: pyb.SPI, pin_cs: pyb.Pin, pin_rst: pyb.Pin, /):
"""
Create a WIZNET5K driver object, initialise the WIZnet5x00 module using the given
SPI bus and pins, and return the WIZNET5K object.
Arguments are:
- *spi* is an :ref:`SPI object ` which is the SPI bus that the WIZnet5x00 is
connected to (the MOSI, MISO and SCLK pins).
- *pin_cs* is a :ref:`Pin object ` which is connected to the WIZnet5x00 nSS pin.
- *pin_rst* is a :ref:`Pin object ` which is connected to the WIZnet5x00 nRESET pin.
All of these objects will be initialised by the driver, so there is no need to
initialise them yourself. For example, you can use::
nic = network.WIZNET5K(pyb.SPI(1), pyb.Pin.board.X5, pyb.Pin.board.X4)
"""
def isconnected(self) -> bool:
"""
Returns ``True`` if the physical Ethernet link is connected and up.
Returns ``False`` otherwise.
"""
@overload
def ifconfig(self) -> tuple[str, str, str, str]:
"""
Get/set IP address, subnet mask, gateway and DNS.
When called with no arguments, this method returns a 4-tuple with the above information.
To set the above values, pass a 4-tuple with the required information. For example::
nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
"""
@overload
def ifconfig(self, config: tuple[str, str, str, str], /):
"""
Get/set IP address, subnet mask, gateway and DNS.
When called with no arguments, this method returns a 4-tuple with the above information.
To set the above values, pass a 4-tuple with the required information. For example::
nic.ifconfig(('192.168.0.4', '255.255.255.0', '192.168.0.1', '8.8.8.8'))
"""
def regs(self) -> Any:
"""
Dump the WIZnet5x00 registers. Useful for debugging.
"""
================================================
FILE: typehints/micropython/ubluetooth.pyi
================================================
"""
Low-level Bluetooth radio functionality.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/bluetooth.rst.
This module provides an interface to a Bluetooth controller on a board.
Currently this supports Bluetooth Low Energy (BLE) in Central, Peripheral,
Broadcaster, and Observer roles, as well as GATT Server and Client and L2CAP
connection-oriented-channels. A device may operate in multiple roles
concurrently. Pairing (and bonding) is supported on some ports.
This API is intended to match the low-level Bluetooth protocol and provide
building-blocks for higher-level abstractions such as specific device types.
.. note:: This module is still under development and its classes, functions,
methods and constants are subject to change.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import overload, Any, Callable, Final
from uio import AnyReadableBuf, AnyWritableBuf
# noinspection SpellCheckingInspection
class BLE:
"""
class BLE
---------
"""
def __init__(self):
"""
Returns the singleton BLE object.
"""
@overload
def active(self) -> bool:
"""
Optionally changes the active state of the BLE radio, and returns the
current state.
The radio must be made active before using any other methods on this class.
"""
@overload
def active(self, active: bool, /) -> None:
"""
Optionally changes the active state of the BLE radio, and returns the
current state.
The radio must be made active before using any other methods on this class.
"""
@overload
def config(self, param: str, /) -> Any:
"""
Get or set configuration values of the BLE interface. To get a value the
parameter name should be quoted as a string, and just one parameter is
queried at a time. To set values use the keyword syntax, and one ore more
parameter can be set at a time.
Currently supported values are:
- ``'mac'``: The current address in use, depending on the current address mode.
This returns a tuple of ``(addr_type, addr)``.
See :meth:`gatts_write ` for details about address type.
This may only be queried while the interface is currently active.
- ``'addr_mode'``: Sets the address mode. Values can be:
* 0x00 - PUBLIC - Use the controller's public address.
* 0x01 - RANDOM - Use a generated static address.
* 0x02 - RPA - Use resolvable private addresses.
* 0x03 - NRPA - Use non-resolvable private addresses.
By default the interface mode will use a PUBLIC address if available, otherwise
it will use a RANDOM address.
- ``'gap_name'``: Get/set the GAP device name used by service 0x1800,
characteristic 0x2a00. This can be set at any time and changed multiple
times.
- ``'rxbuf'``: Get/set the size in bytes of the internal buffer used to store
incoming events. This buffer is global to the entire BLE driver and so
handles incoming data for all events, including all characteristics.
Increasing this allows better handling of bursty incoming data (for
example scan results) and the ability to receive larger characteristic values.
- ``'mtu'``: Get/set the MTU that will be used during a ATT MTU exchange. The
resulting MTU will be the minimum of this and the remote device's MTU.
ATT MTU exchange will not happen automatically (unless the remote device initiates
it), and must be manually initiated with
:meth:`gattc_exchange_mtu`.
Use the ``_IRQ_MTU_EXCHANGED`` event to discover the MTU for a given connection.
- ``'bond'``: Sets whether bonding will be enabled during pairing. When
enabled, pairing requests will set the "bond" flag and the keys will be stored
by both devices.
- ``'mitm'``: Sets whether MITM-protection is required for pairing.
- ``'io'``: Sets the I/O capabilities of this device.
Available options are::
_IO_CAPABILITY_DISPLAY_ONLY = const(0)
_IO_CAPABILITY_DISPLAY_YESNO = const(1)
_IO_CAPABILITY_KEYBOARD_ONLY = const(2)
_IO_CAPABILITY_NO_INPUT_OUTPUT = const(3)
_IO_CAPABILITY_KEYBOARD_DISPLAY = const(4)
- ``'le_secure'``: Sets whether "LE Secure" pairing is required. Default is
false (i.e. allow "Legacy Pairing").
"""
@overload
def config(self, **kwargs) -> None:
"""
Get or set configuration values of the BLE interface. To get a value the
parameter name should be quoted as a string, and just one parameter is
queried at a time. To set values use the keyword syntax, and one ore more
parameter can be set at a time.
Currently supported values are:
- ``'mac'``: The current address in use, depending on the current address mode.
This returns a tuple of ``(addr_type, addr)``.
See :meth:`gatts_write ` for details about address type.
This may only be queried while the interface is currently active.
- ``'addr_mode'``: Sets the address mode. Values can be:
* 0x00 - PUBLIC - Use the controller's public address.
* 0x01 - RANDOM - Use a generated static address.
* 0x02 - RPA - Use resolvable private addresses.
* 0x03 - NRPA - Use non-resolvable private addresses.
By default the interface mode will use a PUBLIC address if available, otherwise
it will use a RANDOM address.
- ``'gap_name'``: Get/set the GAP device name used by service 0x1800,
characteristic 0x2a00. This can be set at any time and changed multiple
times.
- ``'rxbuf'``: Get/set the size in bytes of the internal buffer used to store
incoming events. This buffer is global to the entire BLE driver and so
handles incoming data for all events, including all characteristics.
Increasing this allows better handling of bursty incoming data (for
example scan results) and the ability to receive larger characteristic values.
- ``'mtu'``: Get/set the MTU that will be used during a ATT MTU exchange. The
resulting MTU will be the minimum of this and the remote device's MTU.
ATT MTU exchange will not happen automatically (unless the remote device initiates
it), and must be manually initiated with
:meth:`gattc_exchange_mtu`.
Use the ``_IRQ_MTU_EXCHANGED`` event to discover the MTU for a given connection.
- ``'bond'``: Sets whether bonding will be enabled during pairing. When
enabled, pairing requests will set the "bond" flag and the keys will be stored
by both devices.
- ``'mitm'``: Sets whether MITM-protection is required for pairing.
- ``'io'``: Sets the I/O capabilities of this device.
Available options are::
_IO_CAPABILITY_DISPLAY_ONLY = const(0)
_IO_CAPABILITY_DISPLAY_YESNO = const(1)
_IO_CAPABILITY_KEYBOARD_ONLY = const(2)
_IO_CAPABILITY_NO_INPUT_OUTPUT = const(3)
_IO_CAPABILITY_KEYBOARD_DISPLAY = const(4)
- ``'le_secure'``: Sets whether "LE Secure" pairing is required. Default is
false (i.e. allow "Legacy Pairing").
"""
def irq(self, handler: Callable[[int, tuple[memoryview, ...]], Any], /) -> None:
"""
Registers a callback for events from the BLE stack. The *handler* takes two
arguments, ``event`` (which will be one of the codes below) and ``data``
(which is an event-specific tuple of values).
**Note:** As an optimisation to prevent unnecessary allocations, the ``addr``,
``adv_data``, ``char_data``, ``notify_data``, and ``uuid`` entries in the
tuples are read-only memoryview instances pointing to :mod:`bluetooth`'s internal
ringbuffer, and are only valid during the invocation of the IRQ handler
function. If your program needs to save one of these values to access after
the IRQ handler has returned (e.g. by saving it in a class instance or global
variable), then it needs to take a copy of the data, either by using ``bytes()``
or ``bluetooth.UUID()``, like this::
connected_addr = bytes(addr) # equivalently: adv_data, char_data, or notify_data
matched_uuid = bluetooth.UUID(uuid)
For example, the IRQ handler for a scan result might inspect the ``adv_data``
to decide if it's the correct device, and only then copy the address data to be
used elsewhere in the program. And to print data from within the IRQ handler,
``print(bytes(addr))`` will be needed.
An event handler showing all possible events::
def bt_irq(event, data):
if event == _IRQ_CENTRAL_CONNECT:
# A central has connected to this peripheral.
conn_handle, addr_type, addr = data
elif event == _IRQ_CENTRAL_DISCONNECT:
# A central has disconnected from this peripheral.
conn_handle, addr_type, addr = data
elif event == _IRQ_GATTS_WRITE:
# A client has written to this characteristic or descriptor.
conn_handle, attr_handle = data
elif event == _IRQ_GATTS_READ_REQUEST:
# A client has issued a read. Note: this is only supported on STM32.
# Return a non-zero integer to deny the read (see below), or zero (or None)
# to accept the read.
conn_handle, attr_handle = data
elif event == _IRQ_SCAN_RESULT:
# A single scan result.
addr_type, addr, adv_type, rssi, adv_data = data
elif event == _IRQ_SCAN_DONE:
# Scan duration finished or manually stopped.
pass
elif event == _IRQ_PERIPHERAL_CONNECT:
# A successful gap_connect().
conn_handle, addr_type, addr = data
elif event == _IRQ_PERIPHERAL_DISCONNECT:
# Connected peripheral has disconnected.
conn_handle, addr_type, addr = data
elif event == _IRQ_GATTC_SERVICE_RESULT:
# Called for each service found by gattc_discover_services().
conn_handle, start_handle, end_handle, uuid = data
elif event == _IRQ_GATTC_SERVICE_DONE:
# Called once service discovery is complete.
# Note: Status will be zero on success, implementation-specific value otherwise.
conn_handle, status = data
elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT:
# Called for each characteristic found by gattc_discover_services().
conn_handle, def_handle, value_handle, properties, uuid = data
elif event == _IRQ_GATTC_CHARACTERISTIC_DONE:
# Called once service discovery is complete.
# Note: Status will be zero on success, implementation-specific value otherwise.
conn_handle, status = data
elif event == _IRQ_GATTC_DESCRIPTOR_RESULT:
# Called for each descriptor found by gattc_discover_descriptors().
conn_handle, dsc_handle, uuid = data
elif event == _IRQ_GATTC_DESCRIPTOR_DONE:
# Called once service discovery is complete.
# Note: Status will be zero on success, implementation-specific value otherwise.
conn_handle, status = data
elif event == _IRQ_GATTC_READ_RESULT:
# A gattc_read() has completed.
conn_handle, value_handle, char_data = data
elif event == _IRQ_GATTC_READ_DONE:
# A gattc_read() has completed.
# Note: The value_handle will be zero on btstack (but present on NimBLE).
# Note: Status will be zero on success, implementation-specific value otherwise.
conn_handle, value_handle, status = data
elif event == _IRQ_GATTC_WRITE_DONE:
# A gattc_write() has completed.
# Note: The value_handle will be zero on btstack (but present on NimBLE).
# Note: Status will be zero on success, implementation-specific value otherwise.
conn_handle, value_handle, status = data
elif event == _IRQ_GATTC_NOTIFY:
# A server has sent a notify request.
conn_handle, value_handle, notify_data = data
elif event == _IRQ_GATTC_INDICATE:
# A server has sent an indicate request.
conn_handle, value_handle, notify_data = data
elif event == _IRQ_GATTS_INDICATE_DONE:
# A client has acknowledged the indication.
# Note: Status will be zero on successful acknowledgment, implementation-specific value otherwise.
conn_handle, value_handle, status = data
elif event == _IRQ_MTU_EXCHANGED:
# ATT MTU exchange complete (either initiated by us or the remote device).
conn_handle, mtu = data
elif event == _IRQ_L2CAP_ACCEPT:
# A new channel has been accepted.
# Return a non-zero integer to reject the connection, or zero (or None) to accept.
conn_handle, cid, psm, our_mtu, peer_mtu = data
elif event == _IRQ_L2CAP_CONNECT:
# A new channel is now connected (either as a result of connecting or accepting).
conn_handle, cid, psm, our_mtu, peer_mtu = data
elif event == _IRQ_L2CAP_DISCONNECT:
# Existing channel has disconnected (status is zero), or a connection attempt failed (non-zero status).
conn_handle, cid, psm, status = data
elif event == _IRQ_L2CAP_RECV:
# New data is available on the channel. Use l2cap_recvinto to read.
conn_handle, cid = data
elif event == _IRQ_L2CAP_SEND_READY:
# A previous l2cap_send that returned False has now completed and the channel is ready to send again.
# If status is non-zero, then the transmit buffer overflowed and the application should re-send the data.
conn_handle, cid, status = data
elif event == _IRQ_CONNECTION_UPDATE:
# The remote device has updated connection parameters.
conn_handle, conn_interval, conn_latency, supervision_timeout, status = data
elif event == _IRQ_ENCRYPTION_UPDATE:
# The encryption state has changed (likely as a result of pairing or bonding).
conn_handle, encrypted, authenticated, bonded, key_size = data
elif event == _IRQ_GET_SECRET:
# Return a stored secret.
# If key is None, return the index'th value of this sec_type.
# Otherwise return the corresponding value for this sec_type and key.
sec_type, index, key = data
return value
elif event == _IRQ_SET_SECRET:
# Save a secret to the store for this sec_type and key.
sec_type, key, value = data
return True
elif event == _IRQ_PASSKEY_ACTION:
# Respond to a passkey request during pairing.
# See gap_passkey() for details.
# action will be an action that is compatible with the configured "io" config.
# passkey will be non-zero if action is "numeric comparison".
conn_handle, action, passkey = data
The event codes are::
from micropython import const
_IRQ_CENTRAL_CONNECT = const(1)
_IRQ_CENTRAL_DISCONNECT = const(2)
_IRQ_GATTS_WRITE = const(3)
_IRQ_GATTS_READ_REQUEST = const(4)
_IRQ_SCAN_RESULT = const(5)
_IRQ_SCAN_DONE = const(6)
_IRQ_PERIPHERAL_CONNECT = const(7)
_IRQ_PERIPHERAL_DISCONNECT = const(8)
_IRQ_GATTC_SERVICE_RESULT = const(9)
_IRQ_GATTC_SERVICE_DONE = const(10)
_IRQ_GATTC_CHARACTERISTIC_RESULT = const(11)
_IRQ_GATTC_CHARACTERISTIC_DONE = const(12)
_IRQ_GATTC_DESCRIPTOR_RESULT = const(13)
_IRQ_GATTC_DESCRIPTOR_DONE = const(14)
_IRQ_GATTC_READ_RESULT = const(15)
_IRQ_GATTC_READ_DONE = const(16)
_IRQ_GATTC_WRITE_DONE = const(17)
_IRQ_GATTC_NOTIFY = const(18)
_IRQ_GATTC_INDICATE = const(19)
_IRQ_GATTS_INDICATE_DONE = const(20)
_IRQ_MTU_EXCHANGED = const(21)
_IRQ_L2CAP_ACCEPT = const(22)
_IRQ_L2CAP_CONNECT = const(23)
_IRQ_L2CAP_DISCONNECT = const(24)
_IRQ_L2CAP_RECV = const(25)
_IRQ_L2CAP_SEND_READY = const(26)
_IRQ_CONNECTION_UPDATE = const(27)
_IRQ_ENCRYPTION_UPDATE = const(28)
_IRQ_GET_SECRET = const(29)
_IRQ_SET_SECRET = const(30)
For the ``_IRQ_GATTS_READ_REQUEST`` event, the available return codes are::
_GATTS_NO_ERROR = const(0x00)
_GATTS_ERROR_READ_NOT_PERMITTED = const(0x02)
_GATTS_ERROR_WRITE_NOT_PERMITTED = const(0x03)
_GATTS_ERROR_INSUFFICIENT_AUTHENTICATION = const(0x05)
_GATTS_ERROR_INSUFFICIENT_AUTHORIZATION = const(0x08)
_GATTS_ERROR_INSUFFICIENT_ENCRYPTION = const(0x0f)
For the ``_IRQ_PASSKEY_ACTION`` event, the available actions are::
_PASSKEY_ACTION_NONE = const(0)
_PASSKEY_ACTION_INPUT = const(2)
_PASSKEY_ACTION_DISPLAY = const(3)
_PASSKEY_ACTION_NUMERIC_COMPARISON = const(4)
In order to save space in the firmware, these constants are not included on the
:mod:`bluetooth` module. Add the ones that you need from the list above to your
program.
"""
def gap_advertise(
self,
interval_us: int,
adv_data: AnyReadableBuf | None = None,
/,
*,
resp_data: AnyReadableBuf | None = None,
connectable: bool = True,
) -> None:
"""
Starts advertising at the specified interval (in **micro**\ seconds). This
interval will be rounded down to the nearest 625us. To stop advertising, set
*interval_us* to ``None``.
*adv_data* and *resp_data* can be any type that implements the buffer
protocol (e.g. ``bytes``, ``bytearray``, ``str``). *adv_data* is included
in all broadcasts, and *resp_data* is send in reply to an active scan.
**Note:** if *adv_data* (or *resp_data*) is ``None``, then the data passed
to the previous call to ``gap_advertise`` will be re-used. This allows a
broadcaster to resume advertising with just ``gap_advertise(interval_us)``.
To clear the advertising payload pass an empty ``bytes``, i.e. ``b''``.
"""
def gap_scan(
self,
duration_ms: int,
interval_us: int = 1280000,
window_us: int = 11250,
active: bool = False,
/,
) -> None:
"""
Run a scan operation lasting for the specified duration (in **milli**\ seconds).
To scan indefinitely, set *duration_ms* to ``0``.
To stop scanning, set *duration_ms* to ``None``.
Use *interval_us* and *window_us* to optionally configure the duty cycle.
The scanner will run for *window_us* **micro**\ seconds every *interval_us*
**micro**\ seconds for a total of *duration_ms* **milli**\ seconds. The default
interval and window are 1.28 seconds and 11.25 milliseconds respectively
(background scanning).
For each scan result the ``_IRQ_SCAN_RESULT`` event will be raised, with event
data ``(addr_type, addr, adv_type, rssi, adv_data)``.
``addr_type`` values indicate public or random addresses:
* 0x00 - PUBLIC
* 0x01 - RANDOM (either static, RPA, or NRPA, the type is encoded in the address itself)
``adv_type`` values correspond to the Bluetooth Specification:
* 0x00 - ADV_IND - connectable and scannable undirected advertising
* 0x01 - ADV_DIRECT_IND - connectable directed advertising
* 0x02 - ADV_SCAN_IND - scannable undirected advertising
* 0x03 - ADV_NONCONN_IND - non-connectable undirected advertising
* 0x04 - SCAN_RSP - scan response
``active`` can be set ``True`` if you want to receive scan responses in the results.
When scanning is stopped (either due to the duration finishing or when
explicitly stopped), the ``_IRQ_SCAN_DONE`` event will be raised.
"""
def gap_connect(
self,
addr_type: int,
addr: bytes,
scan_duration_ms: int = 2000,
min_conn_interval_us: int | None = None,
max_conn_interval_us: int | None = None,
/,
) -> None:
"""
Connect to a peripheral.
See :meth:`gap_scan ` for details about address types.
On success, the ``_IRQ_PERIPHERAL_CONNECT`` event will be raised.
The device will wait up to *scan_duration_ms* to receive an advertising
payload from the device.
The connection interval can be configured in **micro**\ seconds using either
or both of *min_conn_interval_us* and *max_conn_interval_us*. Otherwise a
default interval will be chosen, typically between 30000 and 50000
microseconds. A shorter interval will increase throughput, at the expense
of power usage.
Central Role
------------
A central device can connect to peripherals that it has discovered using the observer role (see :meth:`gap_scan`) or with a known address.
"""
def gap_disconnect(self, conn_handle: memoryview, /) -> bool:
"""
Disconnect the specified connection handle. This can either be a
central that has connected to this device (if acting as a peripheral)
or a peripheral that was previously connected to by this device (if acting
as a central).
On success, the ``_IRQ_PERIPHERAL_DISCONNECT`` or ``_IRQ_CENTRAL_DISCONNECT``
event will be raised.
Returns ``False`` if the connection handle wasn't connected, and ``True``
otherwise.
Central Role
------------
A central device can connect to peripherals that it has discovered using the observer role (see :meth:`gap_scan`) or with a known address.
Peripheral Role
---------------
A peripheral device is expected to send connectable advertisements (see
:meth:`gap_advertise`). It will usually be acting as a GATT
server, having first registered services and characteristics using
:meth:`gatts_register_services`.
When a central connects, the ``_IRQ_CENTRAL_CONNECT`` event will be raised.
"""
_Flag: Final = int
_Descriptor: Final = tuple["UUID", _Flag]
_Characteristic: Final = tuple["UUID", _Flag] | tuple[
"UUID", _Flag, tuple[_Descriptor, ...]
]
_Service: Final = tuple["UUID", tuple[_Characteristic, ...]]
def gatts_register_services(
self, services_definition: tuple[_Service, ...], /
) -> tuple[tuple[memoryview, ...], ...]:
"""
Configures the server with the specified services, replacing any
existing services.
*services_definition* is a list of **services**, where each **service** is a
two-element tuple containing a UUID and a list of **characteristics**.
Each **characteristic** is a two-or-three-element tuple containing a UUID, a
**flags** value, and optionally a list of *descriptors*.
Each **descriptor** is a two-element tuple containing a UUID and a **flags**
value.
The **flags** are a bitwise-OR combination of the flags defined below. These
set both the behaviour of the characteristic (or descriptor) as well as the
security and privacy requirements.
The return value is a list (one element per service) of tuples (each element
is a value handle). Characteristics and descriptor handles are flattened
into the same tuple, in the order that they are defined.
The following example registers two services (Heart Rate, and Nordic UART)::
HR_UUID = bluetooth.UUID(0x180D)
HR_CHAR = (bluetooth.UUID(0x2A37), bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,)
HR_SERVICE = (HR_UUID, (HR_CHAR,),)
UART_UUID = bluetooth.UUID('6E400001-B5A3-F393-E0A9-E50E24DCCA9E')
UART_TX = (bluetooth.UUID('6E400003-B5A3-F393-E0A9-E50E24DCCA9E'), bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,)
UART_RX = (bluetooth.UUID('6E400002-B5A3-F393-E0A9-E50E24DCCA9E'), bluetooth.FLAG_WRITE,)
UART_SERVICE = (UART_UUID, (UART_TX, UART_RX,),)
SERVICES = (HR_SERVICE, UART_SERVICE,)
( (hr,), (tx, rx,), ) = bt.gatts_register_services(SERVICES)
The three value handles (``hr``, ``tx``, ``rx``) can be used with
:meth:`gatts_read `, :meth:`gatts_write `, :meth:`gatts_notify `, and
:meth:`gatts_indicate `.
**Note:** Advertising must be stopped before registering services.
Available flags for characteristics and descriptors are::
from micropython import const
_FLAG_BROADCAST = const(0x0001)
_FLAG_READ = const(0x0002)
_FLAG_WRITE_NO_RESPONSE = const(0x0004)
_FLAG_WRITE = const(0x0008)
_FLAG_NOTIFY = const(0x0010)
_FLAG_INDICATE = const(0x0020)
_FLAG_AUTHENTICATED_SIGNED_WRITE = const(0x0040)
_FLAG_AUX_WRITE = const(0x0100)
_FLAG_READ_ENCRYPTED = const(0x0200)
_FLAG_READ_AUTHENTICATED = const(0x0400)
_FLAG_READ_AUTHORIZED = const(0x0800)
_FLAG_WRITE_ENCRYPTED = const(0x1000)
_FLAG_WRITE_AUTHENTICATED = const(0x2000)
_FLAG_WRITE_AUTHORIZED = const(0x4000)
As for the IRQs above, any required constants should be added to your Python code.
GATT Server
-----------
A GATT server has a set of registered services. Each service may contain
characteristics, which each have a value. Characteristics can also contain
descriptors, which themselves have values.
These values are stored locally, and are accessed by their "value handle" which
is generated during service registration. They can also be read from or written
to by a remote client device. Additionally, a server can "notify" a
characteristic to a connected client via a connection handle.
A device in either central or peripheral roles may function as a GATT server,
however in most cases it will be more common for a peripheral device to act
as the server.
Characteristics and descriptors have a default maximum size of 20 bytes.
Anything written to them by a client will be truncated to this length. However,
any local write will increase the maximum size, so if you want to allow larger
writes from a client to a given characteristic, use
:meth:`gatts_write` after registration. e.g.
``gatts_write(char_handle, bytes(100))``.
"""
def gatts_read(self, value_handle: memoryview, /) -> bytes:
"""
Reads the local value for this handle (which has either been written by
:meth:`gatts_write ` or by a remote client).
GATT Server
-----------
A GATT server has a set of registered services. Each service may contain
characteristics, which each have a value. Characteristics can also contain
descriptors, which themselves have values.
These values are stored locally, and are accessed by their "value handle" which
is generated during service registration. They can also be read from or written
to by a remote client device. Additionally, a server can "notify" a
characteristic to a connected client via a connection handle.
A device in either central or peripheral roles may function as a GATT server,
however in most cases it will be more common for a peripheral device to act
as the server.
Characteristics and descriptors have a default maximum size of 20 bytes.
Anything written to them by a client will be truncated to this length. However,
any local write will increase the maximum size, so if you want to allow larger
writes from a client to a given characteristic, use
:meth:`gatts_write` after registration. e.g.
``gatts_write(char_handle, bytes(100))``.
"""
def gatts_write(
self, value_handle: memoryview, data: bytes, send_update: bool = False, /
) -> None:
"""
Writes the local value for this handle, which can be read by a client.
If *send_update* is ``True``, then any subscribed clients will be notified
(or indicated, depending on what they're subscribed to and which operations
the characteristic supports) about this write.
GATT Server
-----------
A GATT server has a set of registered services. Each service may contain
characteristics, which each have a value. Characteristics can also contain
descriptors, which themselves have values.
These values are stored locally, and are accessed by their "value handle" which
is generated during service registration. They can also be read from or written
to by a remote client device. Additionally, a server can "notify" a
characteristic to a connected client via a connection handle.
A device in either central or peripheral roles may function as a GATT server,
however in most cases it will be more common for a peripheral device to act
as the server.
Characteristics and descriptors have a default maximum size of 20 bytes.
Anything written to them by a client will be truncated to this length. However,
any local write will increase the maximum size, so if you want to allow larger
writes from a client to a given characteristic, use
:meth:`gatts_write` after registration. e.g.
``gatts_write(char_handle, bytes(100))``.
"""
def gatts_notify(self, value_handle: memoryview, data: bytes, /) -> None:
"""
Sends a notification request to a connected client.
If *data* is not ``None``, then that value is sent to the client as part of
the notification. The local value will not be modified.
Otherwise, if *data* is ``None``, then the current local value (as
set with :meth:`gatts_write `) will be sent.
**Note:** The notification will be sent regardless of the subscription
status of the client to this characteristic.
GATT Server
-----------
A GATT server has a set of registered services. Each service may contain
characteristics, which each have a value. Characteristics can also contain
descriptors, which themselves have values.
These values are stored locally, and are accessed by their "value handle" which
is generated during service registration. They can also be read from or written
to by a remote client device. Additionally, a server can "notify" a
characteristic to a connected client via a connection handle.
A device in either central or peripheral roles may function as a GATT server,
however in most cases it will be more common for a peripheral device to act
as the server.
Characteristics and descriptors have a default maximum size of 20 bytes.
Anything written to them by a client will be truncated to this length. However,
any local write will increase the maximum size, so if you want to allow larger
writes from a client to a given characteristic, use
:meth:`gatts_write` after registration. e.g.
``gatts_write(char_handle, bytes(100))``.
"""
def gatts_indicate(
self, conn_handle: memoryview, value_handle: memoryview, /
) -> None:
"""
Sends an indication request containing the characteristic's current value to
a connected client.
On acknowledgment (or failure, e.g. timeout), the
``_IRQ_GATTS_INDICATE_DONE`` event will be raised.
**Note:** The indication will be sent regardless of the subscription
status of the client to this characteristic.
GATT Server
-----------
A GATT server has a set of registered services. Each service may contain
characteristics, which each have a value. Characteristics can also contain
descriptors, which themselves have values.
These values are stored locally, and are accessed by their "value handle" which
is generated during service registration. They can also be read from or written
to by a remote client device. Additionally, a server can "notify" a
characteristic to a connected client via a connection handle.
A device in either central or peripheral roles may function as a GATT server,
however in most cases it will be more common for a peripheral device to act
as the server.
Characteristics and descriptors have a default maximum size of 20 bytes.
Anything written to them by a client will be truncated to this length. However,
any local write will increase the maximum size, so if you want to allow larger
writes from a client to a given characteristic, use
:meth:`gatts_write` after registration. e.g.
``gatts_write(char_handle, bytes(100))``.
"""
def gatts_set_buffer(
self, conn_handle: memoryview, len: int, append: bool = False, /
) -> None:
"""
Sets the internal buffer size for a value in bytes. This will limit the
largest possible write that can be received. The default is 20.
Setting *append* to ``True`` will make all remote writes append to, rather
than replace, the current value. At most *len* bytes can be buffered in
this way. When you use :meth:`gatts_read `, the value will
be cleared after reading. This feature is useful when implementing something
like the Nordic UART Service.
GATT Server
-----------
A GATT server has a set of registered services. Each service may contain
characteristics, which each have a value. Characteristics can also contain
descriptors, which themselves have values.
These values are stored locally, and are accessed by their "value handle" which
is generated during service registration. They can also be read from or written
to by a remote client device. Additionally, a server can "notify" a
characteristic to a connected client via a connection handle.
A device in either central or peripheral roles may function as a GATT server,
however in most cases it will be more common for a peripheral device to act
as the server.
Characteristics and descriptors have a default maximum size of 20 bytes.
Anything written to them by a client will be truncated to this length. However,
any local write will increase the maximum size, so if you want to allow larger
writes from a client to a given characteristic, use
:meth:`gatts_write` after registration. e.g.
``gatts_write(char_handle, bytes(100))``.
"""
def gattc_discover_services(
self, conn_handle: memoryview, uuid: UUID | None = None, /
) -> None:
"""
Query a connected server for its services.
Optionally specify a service *uuid* to query for that service only.
For each service discovered, the ``_IRQ_GATTC_SERVICE_RESULT`` event will
be raised, followed by ``_IRQ_GATTC_SERVICE_DONE`` on completion.
GATT Client
-----------
A GATT client can discover and read/write characteristics on a remote GATT server.
It is more common for a central role device to act as the GATT client, however
it's also possible for a peripheral to act as a client in order to discover
information about the central that has connected to it (e.g. to read the
device name from the device information service).
"""
def gattc_discover_characteristics(
self,
conn_handle: memoryview,
start_handle: int,
end_handle: int,
uuid: UUID | None = None,
/,
) -> None:
"""
Query a connected server for characteristics in the specified range.
Optionally specify a characteristic *uuid* to query for that
characteristic only.
You can use ``start_handle=1``, ``end_handle=0xffff`` to search for a
characteristic in any service.
For each characteristic discovered, the ``_IRQ_GATTC_CHARACTERISTIC_RESULT``
event will be raised, followed by ``_IRQ_GATTC_CHARACTERISTIC_DONE`` on completion.
GATT Client
-----------
A GATT client can discover and read/write characteristics on a remote GATT server.
It is more common for a central role device to act as the GATT client, however
it's also possible for a peripheral to act as a client in order to discover
information about the central that has connected to it (e.g. to read the
device name from the device information service).
"""
def gattc_discover_descriptors(
self, conn_handle: memoryview, start_handle: int, end_handle: int, /
) -> None:
"""
Query a connected server for descriptors in the specified range.
For each descriptor discovered, the ``_IRQ_GATTC_DESCRIPTOR_RESULT`` event
will be raised, followed by ``_IRQ_GATTC_DESCRIPTOR_DONE`` on completion.
GATT Client
-----------
A GATT client can discover and read/write characteristics on a remote GATT server.
It is more common for a central role device to act as the GATT client, however
it's also possible for a peripheral to act as a client in order to discover
information about the central that has connected to it (e.g. to read the
device name from the device information service).
"""
def gattc_read(self, conn_handle: memoryview, value_handle: memoryview, /) -> None:
"""
Issue a remote read to a connected server for the specified
characteristic or descriptor handle.
When a value is available, the ``_IRQ_GATTC_READ_RESULT`` event will be
raised. Additionally, the ``_IRQ_GATTC_READ_DONE`` will be raised.
GATT Client
-----------
A GATT client can discover and read/write characteristics on a remote GATT server.
It is more common for a central role device to act as the GATT client, however
it's also possible for a peripheral to act as a client in order to discover
information about the central that has connected to it (e.g. to read the
device name from the device information service).
"""
def gattc_write(
self,
conn_handle: memoryview,
value_handle: memoryview,
data: bytes,
mode: int = 0,
/,
) -> None:
"""
Issue a remote write to a connected server for the specified
characteristic or descriptor handle.
The argument *mode* specifies the write behaviour, with the currently
supported values being:
* ``mode=0`` (default) is a write-without-response: the write will
be sent to the remote server but no confirmation will be
returned, and no event will be raised.
* ``mode=1`` is a write-with-response: the remote server is
requested to send a response/acknowledgement that it received the
data.
If a response is received from the remote server the
``_IRQ_GATTC_WRITE_DONE`` event will be raised.
GATT Client
-----------
A GATT client can discover and read/write characteristics on a remote GATT server.
It is more common for a central role device to act as the GATT client, however
it's also possible for a peripheral to act as a client in order to discover
information about the central that has connected to it (e.g. to read the
device name from the device information service).
"""
def gattc_exchange_mtu(self, conn_handle: memoryview, /) -> None:
"""
Initiate MTU exchange with a connected server, using the preferred MTU
set using ``BLE.config(mtu=value)``.
The ``_IRQ_MTU_EXCHANGED`` event will be raised when MTU exchange
completes.
**Note:** MTU exchange is typically initiated by the central. When using
the BlueKitchen stack in the central role, it does not support a remote
peripheral initiating the MTU exchange. NimBLE works for both roles.
GATT Client
-----------
A GATT client can discover and read/write characteristics on a remote GATT server.
It is more common for a central role device to act as the GATT client, however
it's also possible for a peripheral to act as a client in order to discover
information about the central that has connected to it (e.g. to read the
device name from the device information service).
"""
def l2cap_listen(self, psm: memoryview, mtu: memoryview, /) -> None:
"""
Start listening for incoming L2CAP channel requests on the specified *psm*
with the local MTU set to *mtu*.
When a remote device initiates a connection, the ``_IRQ_L2CAP_ACCEPT``
event will be raised, which gives the listening server a chance to reject
the incoming connection (by returning a non-zero integer).
Once the connection is accepted, the ``_IRQ_L2CAP_CONNECT`` event will be
raised, allowing the server to obtain the channel id (CID) and the local and
remote MTU.
**Note:** It is not currently possible to stop listening.
L2CAP connection-oriented-channels
----------------------------------
This feature allows for socket-like data exchange between two BLE devices.
Once the devices are connected via GAP, either device can listen for the
other to connect on a numeric PSM (Protocol/Service Multiplexer).
**Note:** This is currently only supported when using the NimBLE stack on
STM32 and Unix (not ESP32). Only one L2CAP channel may be active at a given
time (i.e. you cannot connect while listening).
Active L2CAP channels are identified by the connection handle that they were
established on and a CID (channel ID).
Connection-oriented channels have built-in credit-based flow control. Unlike
ATT, where devices negotiate a shared MTU, both the listening and connecting
devices each set an independent MTU which limits the maximum amount of
outstanding data that the remote device can send before it is fully consumed
in :meth:`l2cap_recvinto `.
"""
def l2cap_connect(
self, conn_handle: memoryview, psm: memoryview, mtu: memoryview, /
) -> None:
"""
Connect to a listening peer on the specified *psm* with local MTU set to *mtu*.
On successful connection, the the ``_IRQ_L2CAP_CONNECT`` event will be
raised, allowing the client to obtain the CID and the local and remote (peer) MTU.
An unsuccessful connection will raise the ``_IRQ_L2CAP_DISCONNECT`` event
with a non-zero status.
L2CAP connection-oriented-channels
----------------------------------
This feature allows for socket-like data exchange between two BLE devices.
Once the devices are connected via GAP, either device can listen for the
other to connect on a numeric PSM (Protocol/Service Multiplexer).
**Note:** This is currently only supported when using the NimBLE stack on
STM32 and Unix (not ESP32). Only one L2CAP channel may be active at a given
time (i.e. you cannot connect while listening).
Active L2CAP channels are identified by the connection handle that they were
established on and a CID (channel ID).
Connection-oriented channels have built-in credit-based flow control. Unlike
ATT, where devices negotiate a shared MTU, both the listening and connecting
devices each set an independent MTU which limits the maximum amount of
outstanding data that the remote device can send before it is fully consumed
in :meth:`l2cap_recvinto `.
"""
def l2cap_disconnect(self, conn_handle: memoryview, cid: memoryview, /) -> None:
"""
Disconnect an active L2CAP channel with the specified *conn_handle* and
*cid*.
L2CAP connection-oriented-channels
----------------------------------
This feature allows for socket-like data exchange between two BLE devices.
Once the devices are connected via GAP, either device can listen for the
other to connect on a numeric PSM (Protocol/Service Multiplexer).
**Note:** This is currently only supported when using the NimBLE stack on
STM32 and Unix (not ESP32). Only one L2CAP channel may be active at a given
time (i.e. you cannot connect while listening).
Active L2CAP channels are identified by the connection handle that they were
established on and a CID (channel ID).
Connection-oriented channels have built-in credit-based flow control. Unlike
ATT, where devices negotiate a shared MTU, both the listening and connecting
devices each set an independent MTU which limits the maximum amount of
outstanding data that the remote device can send before it is fully consumed
in :meth:`l2cap_recvinto `.
"""
def l2cap_send(self, conn_handle: memoryview, cid: memoryview, /) -> None:
"""
Send the specified *buf* (which must support the buffer protocol) on the
L2CAP channel identified by *conn_handle* and *cid*.
The specified buffer cannot be larger than the remote (peer) MTU, and no
more than twice the size of the local MTU.
This will return ``False`` if the channel is now "stalled", which means that
:meth:`l2cap_send ` must not be called again until the
``_IRQ_L2CAP_SEND_READY`` event is received (which will happen when the
remote device grants more credits, typically after it has received and
processed the data).
L2CAP connection-oriented-channels
----------------------------------
This feature allows for socket-like data exchange between two BLE devices.
Once the devices are connected via GAP, either device can listen for the
other to connect on a numeric PSM (Protocol/Service Multiplexer).
**Note:** This is currently only supported when using the NimBLE stack on
STM32 and Unix (not ESP32). Only one L2CAP channel may be active at a given
time (i.e. you cannot connect while listening).
Active L2CAP channels are identified by the connection handle that they were
established on and a CID (channel ID).
Connection-oriented channels have built-in credit-based flow control. Unlike
ATT, where devices negotiate a shared MTU, both the listening and connecting
devices each set an independent MTU which limits the maximum amount of
outstanding data that the remote device can send before it is fully consumed
in :meth:`l2cap_recvinto `.
"""
def l2cap_recvinto(
self, conn_handle: memoryview, cid: memoryview, buf: AnyWritableBuf | None, /
) -> int:
"""
Receive data from the specified *conn_handle* and *cid* into the provided
*buf* (which must support the buffer protocol, e.g. bytearray or
memoryview).
Returns the number of bytes read from the channel.
If *buf* is None, then returns the number of bytes available.
**Note:** After receiving the ``_IRQ_L2CAP_RECV`` event, the application should
continue calling :meth:`l2cap_recvinto ` until no more
bytes are available in the receive buffer (typically up to the size of the
remote (peer) MTU).
Until the receive buffer is empty, the remote device will not be granted
more channel credits and will be unable to send any more data.
L2CAP connection-oriented-channels
----------------------------------
This feature allows for socket-like data exchange between two BLE devices.
Once the devices are connected via GAP, either device can listen for the
other to connect on a numeric PSM (Protocol/Service Multiplexer).
**Note:** This is currently only supported when using the NimBLE stack on
STM32 and Unix (not ESP32). Only one L2CAP channel may be active at a given
time (i.e. you cannot connect while listening).
Active L2CAP channels are identified by the connection handle that they were
established on and a CID (channel ID).
Connection-oriented channels have built-in credit-based flow control. Unlike
ATT, where devices negotiate a shared MTU, both the listening and connecting
devices each set an independent MTU which limits the maximum amount of
outstanding data that the remote device can send before it is fully consumed
in :meth:`l2cap_recvinto `.
"""
def gap_pair(self, conn_handle: memoryview, /) -> None:
"""
Initiate pairing with the remote device.
Before calling this, ensure that the ``io``, ``mitm``, ``le_secure``, and
``bond`` configuration options are set (via :meth:`config`).
On successful pairing, the ``_IRQ_ENCRYPTION_UPDATE`` event will be raised.
Pairing and bonding
-------------------
Pairing allows a connection to be encrypted and authenticated via exchange
of secrets (with optional MITM protection via passkey authentication).
Bonding is the process of storing those secrets into non-volatile storage.
When bonded, a device is able to resolve a resolvable private address (RPA)
from another device based on the stored identity resolving key (IRK).
To support bonding, an application must implement the ``_IRQ_GET_SECRET``
and ``_IRQ_SET_SECRET`` events.
**Note:** This is currently only supported when using the NimBLE stack on
STM32 and Unix (not ESP32).
"""
def gap_passkey(
self, conn_handle: memoryview, action: int, passkey: int, /
) -> None:
"""
Respond to a ``_IRQ_PASSKEY_ACTION`` event for the specified *conn_handle*
and *action*.
The *passkey* is a numeric value and will depend on on the
*action* (which will depend on what I/O capability has been set):
* When the *action* is ``_PASSKEY_ACTION_INPUT``, then the application should
prompt the user to enter the passkey that is shown on the remote device.
* When the *action* is ``_PASSKEY_ACTION_DISPLAY``, then the application should
generate a random 6-digit passkey and show it to the user.
* When the *action* is ``_PASSKEY_ACTION_NUMERIC_COMPARISON``, then the application
should show the passkey that was provided in the ``_IRQ_PASSKEY_ACTION`` event
and then respond with either ``0`` (cancel pairing), or ``1`` (accept pairing).
Pairing and bonding
-------------------
Pairing allows a connection to be encrypted and authenticated via exchange
of secrets (with optional MITM protection via passkey authentication).
Bonding is the process of storing those secrets into non-volatile storage.
When bonded, a device is able to resolve a resolvable private address (RPA)
from another device based on the stored identity resolving key (IRK).
To support bonding, an application must implement the ``_IRQ_GET_SECRET``
and ``_IRQ_SET_SECRET`` events.
**Note:** This is currently only supported when using the NimBLE stack on
STM32 and Unix (not ESP32).
"""
class UUID:
"""
class UUID
----------
"""
def __init__(self, value: int | str, /):
"""
Creates a UUID instance with the specified **value**.
The **value** can be either:
- A 16-bit integer. e.g. ``0x2908``.
- A 128-bit UUID string. e.g. ``'6E400001-B5A3-F393-E0A9-E50E24DCCA9E'``.
"""
================================================
FILE: typehints/micropython/ucryptolib.pyi
================================================
"""
cryptographic ciphers.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/cryptolib.rst.
=========================================
.. module:: cryptolib
:synopsis: cryptographic ciphers
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import overload
from uio import AnyReadableBuf, AnyWritableBuf
# noinspection PyPep8Naming
class aes:
"""
.. class:: aes
"""
@overload
def __init__(self, key: AnyReadableBuf, mode: int, /):
"""
Initialize cipher object, suitable for encryption/decryption. Note:
after initialization, cipher object can be use only either for
encryption or decryption. Running decrypt() operation after encrypt()
or vice versa is not supported.
Parameters are:
* *key* is an encryption/decryption key (bytes-like).
* *mode* is:
* ``1`` (or ``cryptolib.MODE_ECB`` if it exists) for Electronic Code Book (ECB).
* ``2`` (or ``cryptolib.MODE_CBC`` if it exists) for Cipher Block Chaining (CBC).
* ``6`` (or ``cryptolib.MODE_CTR`` if it exists) for Counter mode (CTR).
* *IV* is an initialization vector for CBC mode.
* For Counter mode, *IV* is the initial value for the counter.
"""
@overload
def __init__(self, key: AnyReadableBuf, mode: int, IV: AnyReadableBuf, /):
"""
Initialize cipher object, suitable for encryption/decryption. Note:
after initialization, cipher object can be use only either for
encryption or decryption. Running decrypt() operation after encrypt()
or vice versa is not supported.
Parameters are:
* *key* is an encryption/decryption key (bytes-like).
* *mode* is:
* ``1`` (or ``cryptolib.MODE_ECB`` if it exists) for Electronic Code Book (ECB).
* ``2`` (or ``cryptolib.MODE_CBC`` if it exists) for Cipher Block Chaining (CBC).
* ``6`` (or ``cryptolib.MODE_CTR`` if it exists) for Counter mode (CTR).
* *IV* is an initialization vector for CBC mode.
* For Counter mode, *IV* is the initial value for the counter.
"""
@overload
def encrypt(self, in_buf: AnyReadableBuf, /) -> bytes:
"""
Encrypt *in_buf*. If no *out_buf* is given result is returned as a
newly allocated `bytes` object. Otherwise, result is written into
mutable buffer *out_buf*. *in_buf* and *out_buf* can also refer
to the same mutable buffer, in which case data is encrypted in-place.
"""
@overload
def encrypt(self, in_buf: AnyReadableBuf, out_buf: AnyWritableBuf, /) -> None:
"""
Encrypt *in_buf*. If no *out_buf* is given result is returned as a
newly allocated `bytes` object. Otherwise, result is written into
mutable buffer *out_buf*. *in_buf* and *out_buf* can also refer
to the same mutable buffer, in which case data is encrypted in-place.
"""
@overload
def decrypt(self, in_buf: AnyReadableBuf, /) -> bytes:
"""
Like `encrypt()`, but for decryption.
"""
@overload
def decrypt(self, in_buf: AnyReadableBuf, out_buf: AnyWritableBuf, /) -> None:
"""
Like `encrypt()`, but for decryption.
"""
================================================
FILE: typehints/micropython/uctypes.pyi
================================================
"""
access binary data in a structured way.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/uctypes.rst.
========================================================
.. module:: uctypes
:synopsis: access binary data in a structured way
This module implements "foreign data interface" for MicroPython. The idea
behind it is similar to CPython's ``ctypes`` modules, but the actual API is
different, streamlined and optimized for small size. The basic idea of the
module is to define data structure layout with about the same power as the
C language allows, and then access it using familiar dot-syntax to reference
sub-fields.
.. warning::
``uctypes`` module allows access to arbitrary memory addresses of the
machine (including I/O and control registers). Uncareful usage of it
may lead to crashes, data loss, and even hardware malfunction.
.. seealso::
Module :mod:`struct`
Standard Python way to access binary data structures (doesn't scale
well to large and complex structures).
Usage examples::
import uctypes
# Example 1: Subset of ELF file header
# https://wikipedia.org/wiki/Executable_and_Linkable_Format#File_header
ELF_HEADER = {
"EI_MAG": (0x0 | uctypes.ARRAY, 4 | uctypes.UINT8),
"EI_DATA": 0x5 | uctypes.UINT8,
"e_machine": 0x12 | uctypes.UINT16,
}
# "f" is an ELF file opened in binary mode
buf = f.read(uctypes.sizeof(ELF_HEADER, uctypes.LITTLE_ENDIAN))
header = uctypes.struct(uctypes.addressof(buf), ELF_HEADER, uctypes.LITTLE_ENDIAN)
assert header.EI_MAG == b"\x7fELF"
assert header.EI_DATA == 1, "Oops, wrong endianness. Could retry with uctypes.BIG_ENDIAN."
print("machine:", hex(header.e_machine))
# Example 2: In-memory data structure, with pointers
COORD = {
"x": 0 | uctypes.FLOAT32,
"y": 4 | uctypes.FLOAT32,
}
STRUCT1 = {
"data1": 0 | uctypes.UINT8,
"data2": 4 | uctypes.UINT32,
"ptr": (8 | uctypes.PTR, COORD),
}
# Suppose you have address of a structure of type STRUCT1 in "addr"
# uctypes.NATIVE is optional (used by default)
struct1 = uctypes.struct(addr, STRUCT1, uctypes.NATIVE)
print("x:", struct1.ptr[0].x)
# Example 3: Access to CPU registers. Subset of STM32F4xx WWDG block
WWDG_LAYOUT = {
"WWDG_CR": (0, {
# BFUINT32 here means size of the WWDG_CR register
"WDGA": 7 << uctypes.BF_POS | 1 << uctypes.BF_LEN | uctypes.BFUINT32,
"T": 0 << uctypes.BF_POS | 7 << uctypes.BF_LEN | uctypes.BFUINT32,
}),
"WWDG_CFR": (4, {
"EWI": 9 << uctypes.BF_POS | 1 << uctypes.BF_LEN | uctypes.BFUINT32,
"WDGTB": 7 << uctypes.BF_POS | 2 << uctypes.BF_LEN | uctypes.BFUINT32,
"W": 0 << uctypes.BF_POS | 7 << uctypes.BF_LEN | uctypes.BFUINT32,
}),
}
WWDG = uctypes.struct(0x40002c00, WWDG_LAYOUT)
WWDG.WWDG_CFR.WDGTB = 0b10
WWDG.WWDG_CR.WDGA = 1
print("Current counter:", WWDG.WWDG_CR.T)
Defining structure layout
-------------------------
Structure layout is defined by a "descriptor" - a Python dictionary which
encodes field names as keys and other properties required to access them as
associated values::
{
"field1": ,
"field2": ,
...
}
Currently, ``uctypes`` requires explicit specification of offsets for each
field. Offset are given in bytes from the structure start.
Following are encoding examples for various field types:
* Scalar types::
"field_name": offset | uctypes.UINT32
in other words, the value is a scalar type identifier ORed with a field offset
(in bytes) from the start of the structure.
* Recursive structures::
"sub": (offset, {
"b0": 0 | uctypes.UINT8,
"b1": 1 | uctypes.UINT8,
})
i.e. value is a 2-tuple, first element of which is an offset, and second is
a structure descriptor dictionary (note: offsets in recursive descriptors
are relative to the structure it defines). Of course, recursive structures
can be specified not just by a literal dictionary, but by referring to a
structure descriptor dictionary (defined earlier) by name.
* Arrays of primitive types::
"arr": (offset | uctypes.ARRAY, size | uctypes.UINT8),
i.e. value is a 2-tuple, first element of which is ARRAY flag ORed
with offset, and second is scalar element type ORed number of elements
in the array.
* Arrays of aggregate types::
"arr2": (offset | uctypes.ARRAY, size, {"b": 0 | uctypes.UINT8}),
i.e. value is a 3-tuple, first element of which is ARRAY flag ORed
with offset, second is a number of elements in the array, and third is
a descriptor of element type.
* Pointer to a primitive type::
"ptr": (offset | uctypes.PTR, uctypes.UINT8),
i.e. value is a 2-tuple, first element of which is PTR flag ORed
with offset, and second is a scalar element type.
* Pointer to an aggregate type::
"ptr2": (offset | uctypes.PTR, {"b": 0 | uctypes.UINT8}),
i.e. value is a 2-tuple, first element of which is PTR flag ORed
with offset, second is a descriptor of type pointed to.
* Bitfields::
"bitf0": offset | uctypes.BFUINT16 | lsbit << uctypes.BF_POS | bitsize << uctypes.BF_LEN,
i.e. value is a type of scalar value containing given bitfield (typenames are
similar to scalar types, but prefixes with ``BF``), ORed with offset for
scalar value containing the bitfield, and further ORed with values for
bit position and bit length of the bitfield within the scalar value, shifted by
BF_POS and BF_LEN bits, respectively. A bitfield position is counted
from the least significant bit of the scalar (having position of 0), and
is the number of right-most bit of a field (in other words, it's a number
of bits a scalar needs to be shifted right to extract the bitfield).
In the example above, first a UINT16 value will be extracted at offset 0
(this detail may be important when accessing hardware registers, where
particular access size and alignment are required), and then bitfield
whose rightmost bit is *lsbit* bit of this UINT16, and length
is *bitsize* bits, will be extracted. For example, if *lsbit* is 0 and
*bitsize* is 8, then effectively it will access least-significant byte
of UINT16.
Note that bitfield operations are independent of target byte endianness,
in particular, example above will access least-significant byte of UINT16
in both little- and big-endian structures. But it depends on the least
significant bit being numbered 0. Some targets may use different
numbering in their native ABI, but ``uctypes`` always uses the normalized
numbering described above.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import Final
from uio import AnyReadableBuf
_ScalarProperty: Final = int
_RecursiveProperty: Final = tuple[int, "_property"]
_ArrayProperty: Final = tuple[int, int]
_ArrayOfAggregateProperty: Final = tuple[int, int, "_property"]
_PointerToAPrimitiveProperty: Final = tuple[int, int]
_PointerToAaAggregateProperty: Final = tuple[int, "_property"]
_BitfieldProperty: Final = int
_property: Final = _ScalarProperty | _RecursiveProperty | _ArrayProperty | _ArrayOfAggregateProperty | _PointerToAPrimitiveProperty | _PointerToAaAggregateProperty | _BitfieldProperty
_descriptor: Final = tuple[str, _property]
LITTLE_ENDIAN: Final[int] = ...
"""
Layout type for a little-endian packed structure. (Packed means that every
field occupies exactly as many bytes as defined in the descriptor, i.e.
the alignment is 1).
"""
BIG_ENDIAN: Final[int] = ...
"""
Layout type for a big-endian packed structure.
"""
NATIVE: Final[int] = ...
"""
Layout type for a native structure - with data endianness and alignment
conforming to the ABI of the system on which MicroPython runs.
"""
# noinspection PyShadowingNames
def sizeof(struct: struct | _descriptor, layout_type: int = NATIVE, /) -> int:
"""
Return size of data structure in bytes. The *struct* argument can be
either a structure class or a specific instantiated structure object
(or its aggregate field).
"""
def addressof(obj: AnyReadableBuf, /) -> int:
"""
Return address of an object. Argument should be bytes, bytearray or
other object supporting buffer protocol (and address of this buffer
is what actually returned).
"""
def bytes_at(addr: int, size: int, /) -> bytes:
"""
Capture memory at the given address and size as bytes object. As bytes
object is immutable, memory is actually duplicated and copied into
bytes object, so if memory contents change later, created object
retains original value.
"""
def bytearray_at(addr: int, size: int, /) -> bytearray:
"""
Capture memory at the given address and size as bytearray object.
Unlike bytes_at() function above, memory is captured by reference,
so it can be both written too, and you will access current value
at the given memory address.
"""
UINT8: Final[int] = ...
"""
Integer types for structure descriptors. Constants for 8, 16, 32,
and 64 bit types are provided, both signed and unsigned.
"""
INT8: Final[int] = ...
"""
Integer types for structure descriptors. Constants for 8, 16, 32,
and 64 bit types are provided, both signed and unsigned.
"""
UINT16: Final[int] = ...
"""
Integer types for structure descriptors. Constants for 8, 16, 32,
and 64 bit types are provided, both signed and unsigned.
"""
INT16: Final[int] = ...
"""
Integer types for structure descriptors. Constants for 8, 16, 32,
and 64 bit types are provided, both signed and unsigned.
"""
UINT32: Final[int] = ...
"""
Integer types for structure descriptors. Constants for 8, 16, 32,
and 64 bit types are provided, both signed and unsigned.
"""
INT32: Final[int] = ...
"""
Integer types for structure descriptors. Constants for 8, 16, 32,
and 64 bit types are provided, both signed and unsigned.
"""
UINT64: Final[int] = ...
"""
Integer types for structure descriptors. Constants for 8, 16, 32,
and 64 bit types are provided, both signed and unsigned.
"""
INT64: Final[int] = ...
"""
Integer types for structure descriptors. Constants for 8, 16, 32,
and 64 bit types are provided, both signed and unsigned.
"""
FLOAT32: Final[int] = ...
"""
Floating-point types for structure descriptors.
"""
FLOAT64: Final[int] = ...
"""
Floating-point types for structure descriptors.
"""
VOID: Final[int] = ...
"""
``VOID`` is an alias for ``UINT8``, and is provided to conveniently define
C's void pointers: ``(uctypes.PTR, uctypes.VOID)``.
"""
PTR: Final[int] = ...
"""
Type constants for pointers and arrays. Note that there is no explicit
constant for structures, it's implicit: an aggregate type without ``PTR``
or ``ARRAY`` flags is a structure.
"""
ARRAY: Final[int] = ...
"""
Type constants for pointers and arrays. Note that there is no explicit
constant for structures, it's implicit: an aggregate type without ``PTR``
or ``ARRAY`` flags is a structure.
"""
# noinspection PyPep8Naming
class struct:
"""
Module contents
---------------
"""
def __init__(
self, addr: int, descriptor: _descriptor, layout_type: int = NATIVE, /
):
"""
Instantiate a "foreign data structure" object based on structure address in
memory, descriptor (encoded as a dictionary), and layout type (see below).
"""
================================================
FILE: typehints/pyboard/lcd160cr.pyi
================================================
"""
control of LCD160CR display.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/lcd160cr.rst.
===============================================
.. module:: lcd160cr
:synopsis: control of LCD160CR display
This module provides control of the MicroPython LCD160CR display.
.. image:: http://micropython.org/resources/LCD160CRv10-persp.jpg
:alt: LCD160CRv1.0 picture
:width: 640px
Further resources are available via the following links:
* `LCD160CRv1.0 reference manual `_ (100KiB PDF)
* `LCD160CRv1.0 schematics `_ (1.6MiB PDF)
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import overload, Any, Final
from pyb import Pin, I2C, SPI
from uio import AnyReadableBuf, AnyWritableBuf
PORTRAIT: Final[str] = ...
"""
Orientations of the display, used by :meth:`LCD160CR.set_orient`.
"""
LANDSCAPE: Final[str] = ...
"""
Orientations of the display, used by :meth:`LCD160CR.set_orient`.
"""
PORTRAIT_UPSIDEDOWN: Final[str] = ...
"""
Orientations of the display, used by :meth:`LCD160CR.set_orient`.
"""
LANDSCAPE_UPSIDEDOWN: Final[str] = ...
"""
Orientations of the display, used by :meth:`LCD160CR.set_orient`.
"""
STARTUP_DECO_NONE: Final[int] = ...
"""
Types of start-up decoration, can be OR'ed together, used by
:meth:`LCD160CR.set_startup_deco`.
"""
STARTUP_DECO_MLOGO: Final[int] = ...
"""
Types of start-up decoration, can be OR'ed together, used by
:meth:`LCD160CR.set_startup_deco`.
"""
STARTUP_DECO_INFO: Final[int] = ...
"""
Types of start-up decoration, can be OR'ed together, used by
:meth:`LCD160CR.set_startup_deco`.
"""
class LCD160CR:
"""
The LCD160CR class provides an interface to the display. Create an
instance of this class and use its methods to draw to the LCD and get
the status of the touch panel.
For example::
import lcd160cr
lcd = lcd160cr.LCD160CR('X')
lcd.set_orient(lcd160cr.PORTRAIT)
lcd.set_pos(0, 0)
lcd.set_text_color(lcd.rgb(255, 0, 0), lcd.rgb(0, 0, 0))
lcd.set_font(1)
lcd.write('Hello MicroPython!')
print('touch:', lcd.get_touch())
"""
w: Final[int] = ...
"""
The width and height of the display, respectively, in pixels. These
members are updated when calling :meth:`LCD160CR.set_orient` and should
be considered read-only.
"""
h: Final[int] = ...
"""
The width and height of the display, respectively, in pixels. These
members are updated when calling :meth:`LCD160CR.set_orient` and should
be considered read-only.
"""
@overload
def __init__(self, connect: str, /):
"""
Construct an LCD160CR object. The parameters are:
- *connect* is a string specifying the physical connection of the LCD
display to the board; valid values are "X", "Y", "XY", "YX".
Use "X" when the display is connected to a pyboard in the X-skin
position, and "Y" when connected in the Y-skin position. "XY"
and "YX" are used when the display is connected to the right or
left side of the pyboard, respectively.
- *pwr* is a Pin object connected to the LCD's power/enabled pin.
- *i2c* is an I2C object connected to the LCD's I2C interface.
- *spi* is an SPI object connected to the LCD's SPI interface.
- *i2c_addr* is the I2C address of the display.
One must specify either a valid *connect* or all of *pwr*, *i2c* and *spi*.
If a valid *connect* is given then any of *pwr*, *i2c* or *spi* which are
not passed as parameters (i.e. they are ``None``) will be created based on the
value of *connect*. This allows to override the default interface to the
display if needed.
The default values are:
- "X" is for the X-skin and uses:
``pwr=Pin("X4")``, ``i2c=I2C("X")``, ``spi=SPI("X")``
- "Y" is for the Y-skin and uses:
``pwr=Pin("Y4")``, ``i2c=I2C("Y")``, ``spi=SPI("Y")``
- "XY" is for the right-side and uses:
``pwr=Pin("X4")``, ``i2c=I2C("Y")``, ``spi=SPI("X")``
- "YX" is for the left-side and uses:
``pwr=Pin("Y4")``, ``i2c=I2C("X")``, ``spi=SPI("Y")``
See `this image `_
for how the display can be connected to the pyboard.
"""
@overload
def __init__(self, *, pwr: Pin, i2c: I2C, spi: SPI, i2c_addr: int = 98):
"""
Construct an LCD160CR object. The parameters are:
- *connect* is a string specifying the physical connection of the LCD
display to the board; valid values are "X", "Y", "XY", "YX".
Use "X" when the display is connected to a pyboard in the X-skin
position, and "Y" when connected in the Y-skin position. "XY"
and "YX" are used when the display is connected to the right or
left side of the pyboard, respectively.
- *pwr* is a Pin object connected to the LCD's power/enabled pin.
- *i2c* is an I2C object connected to the LCD's I2C interface.
- *spi* is an SPI object connected to the LCD's SPI interface.
- *i2c_addr* is the I2C address of the display.
One must specify either a valid *connect* or all of *pwr*, *i2c* and *spi*.
If a valid *connect* is given then any of *pwr*, *i2c* or *spi* which are
not passed as parameters (i.e. they are ``None``) will be created based on the
value of *connect*. This allows to override the default interface to the
display if needed.
The default values are:
- "X" is for the X-skin and uses:
``pwr=Pin("X4")``, ``i2c=I2C("X")``, ``spi=SPI("X")``
- "Y" is for the Y-skin and uses:
``pwr=Pin("Y4")``, ``i2c=I2C("Y")``, ``spi=SPI("Y")``
- "XY" is for the right-side and uses:
``pwr=Pin("X4")``, ``i2c=I2C("Y")``, ``spi=SPI("X")``
- "YX" is for the left-side and uses:
``pwr=Pin("Y4")``, ``i2c=I2C("X")``, ``spi=SPI("Y")``
See `this image `_
for how the display can be connected to the pyboard.
"""
@staticmethod
def rgb(r: int, g: int, b: int, /) -> int:
"""
Return a 16-bit integer representing the given rgb color values. The
16-bit value can be used to set the font color (see
:meth:`LCD160CR.set_text_color`) pen color (see :meth:`LCD160CR.set_pen`)
and draw individual pixels.
"""
@staticmethod
def clip_line(data: Any, w: int, h: int, /) -> int:
"""
Clip the given line data. This is for internal use.
"""
def set_power(self, on: bool, /) -> None:
"""
Turn the display on or off, depending on the given value of *on*: 0 or ``False``
will turn the display off, and 1 or ``True`` will turn it on.
"""
def set_orient(self, orient: str, /) -> None:
"""
Set the orientation of the display. The *orient* parameter can be one
of `PORTRAIT`, `LANDSCAPE`, `PORTRAIT_UPSIDEDOWN`, `LANDSCAPE_UPSIDEDOWN`.
"""
def set_brightness(self, value: int, /) -> None:
"""
Set the brightness of the display, between 0 and 31.
"""
def set_i2c_addr(self, addr: int, /) -> None:
"""
Set the I2C address of the display. The *addr* value must have the
lower 2 bits cleared.
"""
def set_uart_baudrate(self, baudrate: int, /) -> None:
"""
Set the baudrate of the UART interface.
"""
def set_startup_deco(self, value: bool | str, /) -> None:
"""
Set the start-up decoration of the display. The *value* parameter can be a
logical or of `STARTUP_DECO_NONE`, `STARTUP_DECO_MLOGO`, `STARTUP_DECO_INFO`.
"""
def save_to_flash(self) -> None:
"""
Save the following parameters to flash so they persist on restart and power up:
initial decoration, orientation, brightness, UART baud rate, I2C address.
"""
def set_pixel(self, x: int, y: int, c: int, /) -> None:
"""
Set the specified pixel to the given color. The color should be a 16-bit
integer and can be created by :meth:`LCD160CR.rgb`.
"""
def get_pixel(self, x: int, y: int, /) -> int:
"""
Get the 16-bit value of the specified pixel.
"""
def get_line(self, x: int, y: int, buf: AnyWritableBuf, /) -> None:
"""
Low-level method to get a line of pixels into the given buffer.
To read *n* pixels *buf* should be *2*n+1* bytes in length. The first byte
is a dummy byte and should be ignored, and subsequent bytes represent the
pixels in the line starting at coordinate *(x, y)*.
"""
def screen_dump(
self,
buf: AnyWritableBuf,
x: int = 0,
y: int = 0,
w: int | None = None,
h: int | None = None,
/,
) -> None:
"""
Dump the contents of the screen to the given buffer. The parameters *x* and *y*
specify the starting coordinate, and *w* and *h* the size of the region. If *w*
or *h* are ``None`` then they will take on their maximum values, set by the size
of the screen minus the given *x* and *y* values. *buf* should be large enough
to hold ``2*w*h`` bytes. If it's smaller then only the initial horizontal lines
will be stored.
"""
def screen_load(self, buf: AnyReadableBuf, /) -> None:
"""
Load the entire screen from the given buffer.
"""
def set_pos(self, x: int, y: int, /) -> None:
"""
Set the position for text output using :meth:`LCD160CR.write`. The position
is the upper-left corner of the text.
"""
def set_text_color(self, fg: int, bg: int, /) -> None:
"""
Set the foreground and background color of the text.
"""
def set_font(
self,
font: int,
scale: int = 0,
bold: int = 0,
trans: int = 0,
scroll: int = 0,
/,
) -> None:
"""
Set the font for the text. Subsequent calls to `write` will use the newly
configured font. The parameters are:
- *font* is the font family to use, valid values are 0, 1, 2, 3.
- *scale* is a scaling value for each character pixel, where the pixels
are drawn as a square with side length equal to *scale + 1*. The value
can be between 0 and 63.
- *bold* controls the number of pixels to overdraw each character pixel,
making a bold effect. The lower 2 bits of *bold* are the number of
pixels to overdraw in the horizontal direction, and the next 2 bits are
for the vertical direction. For example, a *bold* value of 5 will
overdraw 1 pixel in both the horizontal and vertical directions.
- *trans* can be either 0 or 1 and if set to 1 the characters will be
drawn with a transparent background.
- *scroll* can be either 0 or 1 and if set to 1 the display will do a
soft scroll if the text moves to the next line.
"""
def write(self, s: str, /) -> None:
"""
Write text to the display, using the current position, color and font.
As text is written the position is automatically incremented. The
display supports basic VT100 control codes such as newline and backspace.
"""
def set_pen(self, line: int, fill: int, /) -> None:
"""
Set the line and fill color for primitive shapes.
"""
def erase(self) -> None:
"""
Erase the entire display to the pen fill color.
"""
def dot(self, x: int, y: int, /) -> None:
"""
Draw a single pixel at the given location using the pen line color.
"""
def rect(self, x: int, y: int, w: int, h: int, /) -> None:
"""
Draw a rectangle at the given location and size using the pen line
color for the outline, and the pen fill color for the interior.
The `rect` method draws the outline and interior, while the other methods
just draw one or the other.
"""
def rect_outline(self, x: int, y: int, w: int, h: int, /) -> None:
"""
Draw a rectangle at the given location and size using the pen line
color for the outline, and the pen fill color for the interior.
The `rect` method draws the outline and interior, while the other methods
just draw one or the other.
"""
def rect_interior(self, x: int, y: int, w: int, h: int, /) -> None:
"""
Draw a rectangle at the given location and size using the pen line
color for the outline, and the pen fill color for the interior.
The `rect` method draws the outline and interior, while the other methods
just draw one or the other.
"""
def line(self, x1: int, y1: int, x2: int, y2: int, /) -> None:
"""
Draw a line between the given coordinates using the pen line color.
"""
def dot_no_clip(self, x: int, y: int, /) -> None:
"""
These methods are as above but don't do any clipping on the input
coordinates. They are faster than the clipping versions and can be
used when you know that the coordinates are within the display.
"""
def rect_no_clip(self, x: int, y: int, w: int, h: int, /) -> None:
"""
These methods are as above but don't do any clipping on the input
coordinates. They are faster than the clipping versions and can be
used when you know that the coordinates are within the display.
"""
def rect_outline_no_clip(self, x: int, y: int, w: int, h: int, /) -> None:
"""
These methods are as above but don't do any clipping on the input
coordinates. They are faster than the clipping versions and can be
used when you know that the coordinates are within the display.
"""
def rect_interior_no_clip(self, x: int, y: int, w: int, h: int, /) -> None:
"""
These methods are as above but don't do any clipping on the input
coordinates. They are faster than the clipping versions and can be
used when you know that the coordinates are within the display.
"""
def line_no_clip(self, x1: int, y1: int, x2: int, y2: int, /) -> None:
"""
These methods are as above but don't do any clipping on the input
coordinates. They are faster than the clipping versions and can be
used when you know that the coordinates are within the display.
"""
def poly_dot(self, data: AnyReadableBuf, /) -> None:
"""
Draw a sequence of dots using the pen line color.
The *data* should be a buffer of bytes, with each successive pair of
bytes corresponding to coordinate pairs (x, y).
"""
def poly_line(self, data: AnyReadableBuf, /) -> None:
"""
Similar to :meth:`LCD160CR.poly_dot` but draws lines between the dots.
"""
def touch_config(
self, calib: bool = False, save: bool = False, irq: bool | None = None, /
) -> None:
"""
Configure the touch panel:
- If *calib* is ``True`` then the call will trigger a touch calibration of
the resistive touch sensor. This requires the user to touch various
parts of the screen.
- If *save* is ``True`` then the touch parameters will be saved to NVRAM
to persist across reset/power up.
- If *irq* is ``True`` then the display will be configured to pull the IRQ
line low when a touch force is detected. If *irq* is ``False`` then this
feature is disabled. If *irq* is ``None`` (the default value) then no
change is made to this setting.
"""
def is_touched(self) -> bool:
"""
Returns a boolean: ``True`` if there is currently a touch force on the screen,
``False`` otherwise.
"""
def get_touch(self) -> tuple[int, int, int]:
"""
Returns a 3-tuple of: *(active, x, y)*. If there is currently a touch force
on the screen then *active* is 1, otherwise it is 0. The *x* and *y* values
indicate the position of the current or most recent touch.
"""
def set_spi_win(self, x: int, y: int, w: int, h: int, /) -> None:
"""
Set the window that SPI data is written to.
"""
def fast_spi(self, flush: bool = True, /) -> SPI:
"""
Ready the display to accept RGB pixel data on the SPI bus, resetting the location
of the first byte to go to the top-left corner of the window set by
:meth:`LCD160CR.set_spi_win`.
The method returns an SPI object which can be used to write the pixel data.
Pixels should be sent as 16-bit RGB values in the 5-6-5 format. The destination
counter will increase as data is sent, and data can be sent in arbitrary sized
chunks. Once the destination counter reaches the end of the window specified by
:meth:`LCD160CR.set_spi_win` it will wrap around to the top-left corner of that window.
"""
def show_framebuf(self, buf: AnyReadableBuf, /) -> None:
"""
Show the given buffer on the display. *buf* should be an array of bytes containing
the 16-bit RGB values for the pixels, and they will be written to the area
specified by :meth:`LCD160CR.set_spi_win`, starting from the top-left corner.
The `framebuf `_ module can be used to construct frame buffers
and provides drawing primitives. Using a frame buffer will improve
performance of animations when compared to drawing directly to the screen.
"""
def set_scroll(self, on: bool, /) -> None:
"""
Turn scrolling on or off. This controls globally whether any window regions will
scroll.
"""
def set_scroll_win(
self,
win: int,
x: int = -1,
y: int = 0,
w: int = 0,
h: int = 0,
vec: int = 0,
pat: int = 0,
fill: int = 0x07E0,
color: int = 0,
/,
) -> None:
"""
Configure a window region for scrolling:
- *win* is the window id to configure. There are 0..7 standard windows for
general purpose use. Window 8 is the text scroll window (the ticker).
- *x*, *y*, *w*, *h* specify the location of the window in the display.
- *vec* specifies the direction and speed of scroll: it is a 16-bit value
of the form ``0bF.ddSSSSSSSSSSSS``. *dd* is 0, 1, 2, 3 for +x, +y, -x,
-y scrolling. *F* sets the speed format, with 0 meaning that the window
is shifted *S % 256* pixel every frame, and 1 meaning that the window
is shifted 1 pixel every *S* frames.
- *pat* is a 16-bit pattern mask for the background.
- *fill* is the fill color.
- *color* is the extra color, either of the text or pattern foreground.
"""
def set_scroll_win_param(self, win: int, param: int, value: int, /) -> None:
"""
Set a single parameter of a scrolling window region:
- *win* is the window id, 0..8.
- *param* is the parameter number to configure, 0..7, and corresponds
to the parameters in the `set_scroll_win` method.
- *value* is the value to set.
"""
def set_scroll_buf(self, s: str, /) -> None:
"""
Set the string for scrolling in window 8. The parameter *s* must be a string
with length 32 or less.
"""
def jpeg(self, buf: AnyReadableBuf, /) -> None:
"""
Display a JPEG. *buf* should contain the entire JPEG data. JPEG data should
not include EXIF information. The following encodings are supported: Baseline
DCT, Huffman coding, 8 bits per sample, 3 color components, YCbCr4:2:2.
The origin of the JPEG is set by :meth:`LCD160CR.set_pos`.
"""
def jpeg_start(self, total_len: int, /) -> None:
"""
Display a JPEG with the data split across multiple buffers. There must be
a single call to `jpeg_start` to begin with, specifying the total number of
bytes in the JPEG. Then this number of bytes must be transferred to the
display using one or more calls to the `jpeg_data` command.
"""
def jpeg_data(self, buf: AnyReadableBuf, /) -> None:
"""
Display a JPEG with the data split across multiple buffers. There must be
a single call to `jpeg_start` to begin with, specifying the total number of
bytes in the JPEG. Then this number of bytes must be transferred to the
display using one or more calls to the `jpeg_data` command.
"""
def feed_wdt(self) -> None:
"""
The first call to this method will start the display's internal watchdog
timer. Subsequent calls will feed the watchdog. The timeout is roughly 30
seconds.
"""
def reset(self) -> None:
"""
Reset the display.
"""
================================================
FILE: typehints/pyboard/pyb.pyi
================================================
"""
functions related to the board.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/pyb.rst.
=============================================
Hardware Note
-------------
The accelerometer uses I2C bus 1 to communicate with the processor. Consequently
when readings are being taken pins X9 and X10 should be unused (other than for
I2C). Other devices using those pins, and which therefore cannot be used
concurrently, are UART 1 and Timer 4 channels 1 and 2.
Hardware Note
-------------
On boards with external spiflash (e.g. Pyboard D), the MicroPython firmware will
be configured to use that as the primary flash storage. On all other boards, the
internal flash inside the :term:`MCU` will be used.
Flow Control
------------
On Pyboards V1 and V1.1 ``UART(2)`` and ``UART(3)`` support RTS/CTS hardware flow control
using the following pins:
- ``UART(2)`` is on: ``(TX, RX, nRTS, nCTS) = (X3, X4, X2, X1) = (PA2, PA3, PA1, PA0)``
- ``UART(3)`` is on :``(TX, RX, nRTS, nCTS) = (Y9, Y10, Y7, Y6) = (PB10, PB11, PB14, PB13)``
On the Pyboard Lite only ``UART(2)`` supports flow control on these pins:
``(TX, RX, nRTS, nCTS) = (X1, X2, X4, X3) = (PA2, PA3, PA1, PA0)``
In the following paragraphs the term "target" refers to the device connected to
the UART.
When the UART's ``init()`` method is called with ``flow`` set to one or both of
``UART.RTS`` and ``UART.CTS`` the relevant flow control pins are configured.
``nRTS`` is an active low output, ``nCTS`` is an active low input with pullup
enabled. To achieve flow control the Pyboard's ``nCTS`` signal should be connected
to the target's ``nRTS`` and the Pyboard's ``nRTS`` to the target's ``nCTS``.
CTS: target controls Pyboard transmitter
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If CTS flow control is enabled the write behaviour is as follows:
If the Pyboard's ``UART.write(buf)`` method is called, transmission will stall for
any periods when ``nCTS`` is ``False``. This will result in a timeout if the entire
buffer was not transmitted in the timeout period. The method returns the number of
bytes written, enabling the user to write the remainder of the data if required. In
the event of a timeout, a character will remain in the UART pending ``nCTS``. The
number of bytes composing this character will be included in the return value.
If ``UART.writechar()`` is called when ``nCTS`` is ``False`` the method will time
out unless the target asserts ``nCTS`` in time. If it times out ``OSError 116``
will be raised. The character will be transmitted as soon as the target asserts ``nCTS``.
RTS: Pyboard controls target's transmitter
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If RTS flow control is enabled, behaviour is as follows:
If buffered input is used (``read_buf_len`` > 0), incoming characters are buffered.
If the buffer becomes full, the next character to arrive will cause ``nRTS`` to go
``False``: the target should cease transmission. ``nRTS`` will go ``True`` when
characters are read from the buffer.
Note that the ``any()`` method returns the number of bytes in the buffer. Assume a
buffer length of ``N`` bytes. If the buffer becomes full, and another character arrives,
``nRTS`` will be set False, and ``any()`` will return the count ``N``. When
characters are read the additional character will be placed in the buffer and will
be included in the result of a subsequent ``any()`` call.
If buffered input is not used (``read_buf_len`` == 0) the arrival of a character will
cause ``nRTS`` to go ``False`` until the character is read.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from abc import ABC, abstractmethod
from typing import NoReturn, overload, Sequence, runtime_checkable, Protocol
from typing import Callable, Dict, Any, ClassVar, Final
from uarray import array
from uio import AnyReadableBuf, AnyWritableBuf
from uos import AbstractBlockDev
@runtime_checkable
class _OldAbstractReadOnlyBlockDev(Protocol):
"""
A `Protocol` (structurally typed) with the defs needed by
`mount` argument `device` for read-only devices.
"""
__slots__ = ()
@abstractmethod
def readblocks(self, blocknum: int, buf: bytearray, /) -> None: ...
@abstractmethod
def count(self) -> int: ...
@runtime_checkable
class _OldAbstractBlockDev(_OldAbstractReadOnlyBlockDev, Protocol):
"""
A `Protocol` (structurally typed) with the defs needed by
`mount` argument `device` for read-write devices.
"""
__slots__ = ()
@abstractmethod
def writeblocks(self, blocknum: int, buf: bytes | bytearray, /) -> None: ...
@abstractmethod
def sync(self) -> None: ...
hid_mouse: Final[tuple[int, int, int, int, bytes]] = ...
"""
Mouse human interface device (hid), see `hid` argument of `usb_mode`.
"""
hid_keyboard: Final[tuple[int, int, int, int, bytes]] = ...
"""
Keyboard human interface device (hid), see `hid` argument of `usb_mode`.
"""
@overload
def country() -> str:
"""Return the current ISO 3166-1, Alpha-2, country code, eg US, GB, DE, AU."""
@overload
def country(alpha_2_code: str) -> None:
"""Set the ISO 3166-1, Alpha-2, country code, eg US, GB, DE, AU."""
def delay(ms: int, /) -> None:
"""
Delay for the given number of milliseconds.
"""
def udelay(us: int, /) -> None:
"""
Delay for the given number of microseconds.
"""
def millis() -> int:
"""
Returns the number of milliseconds since the board was last reset.
The result is always a MicroPython smallint (31-bit signed number), so
after 2^30 milliseconds (about 12.4 days) this will start to return
negative numbers.
Note that if :meth:`pyb.stop()` is issued the hardware counter supporting this
function will pause for the duration of the "sleeping" state. This
will affect the outcome of :meth:`pyb.elapsed_millis()`.
"""
def micros() -> int:
"""
Returns the number of microseconds since the board was last reset.
The result is always a MicroPython smallint (31-bit signed number), so
after 2^30 microseconds (about 17.8 minutes) this will start to return
negative numbers.
Note that if :meth:`pyb.stop()` is issued the hardware counter supporting this
function will pause for the duration of the "sleeping" state. This
will affect the outcome of :meth:`pyb.elapsed_micros()`.
"""
def elapsed_millis(start: int, /) -> int:
"""
Returns the number of milliseconds which have elapsed since ``start``.
This function takes care of counter wrap, and always returns a positive
number. This means it can be used to measure periods up to about 12.4 days.
Example::
start = pyb.millis()
while pyb.elapsed_millis(start) < 1000:
# Perform some operation
"""
def elapsed_micros(start: int, /) -> int:
"""
Returns the number of microseconds which have elapsed since ``start``.
This function takes care of counter wrap, and always returns a positive
number. This means it can be used to measure periods up to about 17.8 minutes.
Example::
start = pyb.micros()
while pyb.elapsed_micros(start) < 1000:
# Perform some operation
pass
"""
def hard_reset() -> NoReturn:
"""
Resets the pyboard in a manner similar to pushing the external RESET
button.
"""
def bootloader() -> NoReturn:
"""
Activate the bootloader without BOOT\* pins.
"""
def fault_debug(value: bool = False) -> None:
"""
Enable or disable hard-fault debugging. A hard-fault is when there is a fatal
error in the underlying system, like an invalid memory access.
If the *value* argument is ``False`` then the board will automatically reset if
there is a hard fault.
If *value* is ``True`` then, when the board has a hard fault, it will print the
registers and the stack trace, and then cycle the LEDs indefinitely.
The default value is disabled, i.e. to automatically reset.
"""
def disable_irq() -> bool:
"""
Disable interrupt requests.
Returns the previous IRQ state: ``False``/``True`` for disabled/enabled IRQs
respectively. This return value can be passed to enable_irq to restore
the IRQ to its original state.
"""
def enable_irq(state: bool = True, /) -> None:
"""
Enable interrupt requests.
If ``state`` is ``True`` (the default value) then IRQs are enabled.
If ``state`` is ``False`` then IRQs are disabled. The most common use of
this function is to pass it the value returned by ``disable_irq`` to
exit a critical section.
"""
@overload
def freq() -> tuple[int, int, int, int]:
"""
If given no arguments, returns a tuple of clock frequencies:
(sysclk, hclk, pclk1, pclk2).
These correspond to:
- sysclk: frequency of the CPU
- hclk: frequency of the AHB bus, core memory and DMA
- pclk1: frequency of the APB1 bus
- pclk2: frequency of the APB2 bus
If given any arguments then the function sets the frequency of the CPU,
and the buses if additional arguments are given. Frequencies are given in
Hz. Eg freq(120000000) sets sysclk (the CPU frequency) to 120MHz. Note that
not all values are supported and the largest supported frequency not greater
than the given value will be selected.
Supported sysclk frequencies are (in MHz): 8, 16, 24, 30, 32, 36, 40, 42, 48,
54, 56, 60, 64, 72, 84, 96, 108, 120, 144, 168.
The maximum frequency of hclk is 168MHz, of pclk1 is 42MHz, and of pclk2 is
84MHz. Be sure not to set frequencies above these values.
The hclk, pclk1 and pclk2 frequencies are derived from the sysclk frequency
using a prescaler (divider). Supported prescalers for hclk are: 1, 2, 4, 8,
16, 64, 128, 256, 512. Supported prescalers for pclk1 and pclk2 are: 1, 2,
4, 8. A prescaler will be chosen to best match the requested frequency.
A sysclk frequency of
8MHz uses the HSE (external crystal) directly and 16MHz uses the HSI
(internal oscillator) directly. The higher frequencies use the HSE to
drive the PLL (phase locked loop), and then use the output of the PLL.
Note that if you change the frequency while the USB is enabled then
the USB may become unreliable. It is best to change the frequency
in boot.py, before the USB peripheral is started. Also note that sysclk
frequencies below 36MHz do not allow the USB to function correctly.
"""
@overload
def freq(sysclk: int, /) -> None:
"""
If given no arguments, returns a tuple of clock frequencies:
(sysclk, hclk, pclk1, pclk2).
These correspond to:
- sysclk: frequency of the CPU
- hclk: frequency of the AHB bus, core memory and DMA
- pclk1: frequency of the APB1 bus
- pclk2: frequency of the APB2 bus
If given any arguments then the function sets the frequency of the CPU,
and the buses if additional arguments are given. Frequencies are given in
Hz. Eg freq(120000000) sets sysclk (the CPU frequency) to 120MHz. Note that
not all values are supported and the largest supported frequency not greater
than the given value will be selected.
Supported sysclk frequencies are (in MHz): 8, 16, 24, 30, 32, 36, 40, 42, 48,
54, 56, 60, 64, 72, 84, 96, 108, 120, 144, 168.
The maximum frequency of hclk is 168MHz, of pclk1 is 42MHz, and of pclk2 is
84MHz. Be sure not to set frequencies above these values.
The hclk, pclk1 and pclk2 frequencies are derived from the sysclk frequency
using a prescaler (divider). Supported prescalers for hclk are: 1, 2, 4, 8,
16, 64, 128, 256, 512. Supported prescalers for pclk1 and pclk2 are: 1, 2,
4, 8. A prescaler will be chosen to best match the requested frequency.
A sysclk frequency of
8MHz uses the HSE (external crystal) directly and 16MHz uses the HSI
(internal oscillator) directly. The higher frequencies use the HSE to
drive the PLL (phase locked loop), and then use the output of the PLL.
Note that if you change the frequency while the USB is enabled then
the USB may become unreliable. It is best to change the frequency
in boot.py, before the USB peripheral is started. Also note that sysclk
frequencies below 36MHz do not allow the USB to function correctly.
"""
@overload
def freq(sysclk: int, hclk: int, /) -> None:
"""
If given no arguments, returns a tuple of clock frequencies:
(sysclk, hclk, pclk1, pclk2).
These correspond to:
- sysclk: frequency of the CPU
- hclk: frequency of the AHB bus, core memory and DMA
- pclk1: frequency of the APB1 bus
- pclk2: frequency of the APB2 bus
If given any arguments then the function sets the frequency of the CPU,
and the buses if additional arguments are given. Frequencies are given in
Hz. Eg freq(120000000) sets sysclk (the CPU frequency) to 120MHz. Note that
not all values are supported and the largest supported frequency not greater
than the given value will be selected.
Supported sysclk frequencies are (in MHz): 8, 16, 24, 30, 32, 36, 40, 42, 48,
54, 56, 60, 64, 72, 84, 96, 108, 120, 144, 168.
The maximum frequency of hclk is 168MHz, of pclk1 is 42MHz, and of pclk2 is
84MHz. Be sure not to set frequencies above these values.
The hclk, pclk1 and pclk2 frequencies are derived from the sysclk frequency
using a prescaler (divider). Supported prescalers for hclk are: 1, 2, 4, 8,
16, 64, 128, 256, 512. Supported prescalers for pclk1 and pclk2 are: 1, 2,
4, 8. A prescaler will be chosen to best match the requested frequency.
A sysclk frequency of
8MHz uses the HSE (external crystal) directly and 16MHz uses the HSI
(internal oscillator) directly. The higher frequencies use the HSE to
drive the PLL (phase locked loop), and then use the output of the PLL.
Note that if you change the frequency while the USB is enabled then
the USB may become unreliable. It is best to change the frequency
in boot.py, before the USB peripheral is started. Also note that sysclk
frequencies below 36MHz do not allow the USB to function correctly.
"""
@overload
def freq(sysclk: int, hclk: int, pclk1: int, /) -> None:
"""
If given no arguments, returns a tuple of clock frequencies:
(sysclk, hclk, pclk1, pclk2).
These correspond to:
- sysclk: frequency of the CPU
- hclk: frequency of the AHB bus, core memory and DMA
- pclk1: frequency of the APB1 bus
- pclk2: frequency of the APB2 bus
If given any arguments then the function sets the frequency of the CPU,
and the buses if additional arguments are given. Frequencies are given in
Hz. Eg freq(120000000) sets sysclk (the CPU frequency) to 120MHz. Note that
not all values are supported and the largest supported frequency not greater
than the given value will be selected.
Supported sysclk frequencies are (in MHz): 8, 16, 24, 30, 32, 36, 40, 42, 48,
54, 56, 60, 64, 72, 84, 96, 108, 120, 144, 168.
The maximum frequency of hclk is 168MHz, of pclk1 is 42MHz, and of pclk2 is
84MHz. Be sure not to set frequencies above these values.
The hclk, pclk1 and pclk2 frequencies are derived from the sysclk frequency
using a prescaler (divider). Supported prescalers for hclk are: 1, 2, 4, 8,
16, 64, 128, 256, 512. Supported prescalers for pclk1 and pclk2 are: 1, 2,
4, 8. A prescaler will be chosen to best match the requested frequency.
A sysclk frequency of
8MHz uses the HSE (external crystal) directly and 16MHz uses the HSI
(internal oscillator) directly. The higher frequencies use the HSE to
drive the PLL (phase locked loop), and then use the output of the PLL.
Note that if you change the frequency while the USB is enabled then
the USB may become unreliable. It is best to change the frequency
in boot.py, before the USB peripheral is started. Also note that sysclk
frequencies below 36MHz do not allow the USB to function correctly.
"""
@overload
def freq(sysclk: int, hclk: int, pclk1: int, pclk2: int, /) -> None:
"""
If given no arguments, returns a tuple of clock frequencies:
(sysclk, hclk, pclk1, pclk2).
These correspond to:
- sysclk: frequency of the CPU
- hclk: frequency of the AHB bus, core memory and DMA
- pclk1: frequency of the APB1 bus
- pclk2: frequency of the APB2 bus
If given any arguments then the function sets the frequency of the CPU,
and the buses if additional arguments are given. Frequencies are given in
Hz. Eg freq(120000000) sets sysclk (the CPU frequency) to 120MHz. Note that
not all values are supported and the largest supported frequency not greater
than the given value will be selected.
Supported sysclk frequencies are (in MHz): 8, 16, 24, 30, 32, 36, 40, 42, 48,
54, 56, 60, 64, 72, 84, 96, 108, 120, 144, 168.
The maximum frequency of hclk is 168MHz, of pclk1 is 42MHz, and of pclk2 is
84MHz. Be sure not to set frequencies above these values.
The hclk, pclk1 and pclk2 frequencies are derived from the sysclk frequency
using a prescaler (divider). Supported prescalers for hclk are: 1, 2, 4, 8,
16, 64, 128, 256, 512. Supported prescalers for pclk1 and pclk2 are: 1, 2,
4, 8. A prescaler will be chosen to best match the requested frequency.
A sysclk frequency of
8MHz uses the HSE (external crystal) directly and 16MHz uses the HSI
(internal oscillator) directly. The higher frequencies use the HSE to
drive the PLL (phase locked loop), and then use the output of the PLL.
Note that if you change the frequency while the USB is enabled then
the USB may become unreliable. It is best to change the frequency
in boot.py, before the USB peripheral is started. Also note that sysclk
frequencies below 36MHz do not allow the USB to function correctly.
"""
def wfi() -> None:
"""
Wait for an internal or external interrupt.
This executes a ``wfi`` instruction which reduces power consumption
of the MCU until any interrupt occurs (be it internal or external),
at which point execution continues. Note that the system-tick interrupt
occurs once every millisecond (1000Hz) so this function will block for
at most 1ms.
"""
def stop() -> None:
"""
Put the pyboard in a "sleeping" state.
This reduces power consumption to less than 500 uA. To wake from this
sleep state requires an external interrupt or a real-time-clock event.
Upon waking execution continues where it left off.
See :meth:`rtc.wakeup` to configure a real-time-clock wakeup event.
"""
def standby() -> None:
"""
Put the pyboard into a "deep sleep" state.
This reduces power consumption to less than 50 uA. To wake from this
sleep state requires a real-time-clock event, or an external interrupt
on X1 (PA0=WKUP) or X18 (PC13=TAMP1).
Upon waking the system undergoes a hard reset.
See :meth:`rtc.wakeup` to configure a real-time-clock wakeup event.
"""
def have_cdc() -> bool:
"""
Return True if USB is connected as a serial device, False otherwise.
.. note:: This function is deprecated. Use pyb.USB_VCP().isconnected() instead.
"""
@overload
def hid(data: tuple[int, int, int, int], /) -> None:
"""
Takes a 4-tuple (or list) and sends it to the USB host (the PC) to
signal a HID mouse-motion event.
.. note:: This function is deprecated. Use :meth:`pyb.USB_HID.send()` instead.
"""
@overload
def hid(data: Sequence[int], /) -> None:
"""
Takes a 4-tuple (or list) and sends it to the USB host (the PC) to
signal a HID mouse-motion event.
.. note:: This function is deprecated. Use :meth:`pyb.USB_HID.send()` instead.
"""
@overload
def info() -> None:
"""
Print out lots of information about the board.
"""
@overload
def info(dump_alloc_table: bytes, /) -> None:
"""
Print out lots of information about the board.
"""
def main(filename: str, /) -> None:
"""
Set the filename of the main script to run after boot.py is finished. If
this function is not called then the default file main.py will be executed.
It only makes sense to call this function from within boot.py.
"""
@overload
def mount(
device: _OldAbstractReadOnlyBlockDev,
mountpoint: str,
/,
*,
readonly: bool = False,
mkfs: bool = False,
) -> None:
"""
.. note:: This function is deprecated. Mounting and unmounting devices should
be performed by :meth:`os.mount` and :meth:`os.umount` instead.
Mount a block device and make it available as part of the filesystem.
``device`` must be an object that provides the block protocol. (The
following is also deprecated. See :class:`os.AbstractBlockDev` for the
correct way to create a block device.)
- ``readblocks(self, blocknum, buf)``
- ``writeblocks(self, blocknum, buf)`` (optional)
- ``count(self)``
- ``sync(self)`` (optional)
``readblocks`` and ``writeblocks`` should copy data between ``buf`` and
the block device, starting from block number ``blocknum`` on the device.
``buf`` will be a bytearray with length a multiple of 512. If
``writeblocks`` is not defined then the device is mounted read-only.
The return value of these two functions is ignored.
``count`` should return the number of blocks available on the device.
``sync``, if implemented, should sync the data on the device.
The parameter ``mountpoint`` is the location in the root of the filesystem
to mount the device. It must begin with a forward-slash.
If ``readonly`` is ``True``, then the device is mounted read-only,
otherwise it is mounted read-write.
If ``mkfs`` is ``True``, then a new filesystem is created if one does not
already exist.
"""
@overload
def mount(
device: _OldAbstractBlockDev,
mountpoint: str,
/,
*,
readonly: bool = False,
mkfs: bool = False,
) -> None:
"""
.. note:: This function is deprecated. Mounting and unmounting devices should
be performed by :meth:`os.mount` and :meth:`os.umount` instead.
Mount a block device and make it available as part of the filesystem.
``device`` must be an object that provides the block protocol. (The
following is also deprecated. See :class:`os.AbstractBlockDev` for the
correct way to create a block device.)
- ``readblocks(self, blocknum, buf)``
- ``writeblocks(self, blocknum, buf)`` (optional)
- ``count(self)``
- ``sync(self)`` (optional)
``readblocks`` and ``writeblocks`` should copy data between ``buf`` and
the block device, starting from block number ``blocknum`` on the device.
``buf`` will be a bytearray with length a multiple of 512. If
``writeblocks`` is not defined then the device is mounted read-only.
The return value of these two functions is ignored.
``count`` should return the number of blocks available on the device.
``sync``, if implemented, should sync the data on the device.
The parameter ``mountpoint`` is the location in the root of the filesystem
to mount the device. It must begin with a forward-slash.
If ``readonly`` is ``True``, then the device is mounted read-only,
otherwise it is mounted read-write.
If ``mkfs`` is ``True``, then a new filesystem is created if one does not
already exist.
"""
@overload
def repl_uart() -> UART | None:
"""
Get or set the UART object where the REPL is repeated on.
"""
@overload
def repl_uart(uart: UART, /) -> None:
"""
Get or set the UART object where the REPL is repeated on.
"""
def rng() -> int:
"""
Return a 30-bit hardware generated random number.
"""
def sync() -> None:
"""
Sync all file systems.
"""
def unique_id() -> bytes:
"""
Returns a string of 12 bytes (96 bits), which is the unique ID of the MCU.
"""
# noinspection PyShadowingNames
@overload
def usb_mode() -> str:
"""
If called with no arguments, return the current USB mode as a string.
If called with *modestr* provided, attempts to configure the USB mode.
The following values of *modestr* are understood:
- ``None``: disables USB
- ``'VCP'``: enable with VCP (Virtual COM Port) interface
- ``'MSC'``: enable with MSC (mass storage device class) interface
- ``'VCP+MSC'``: enable with VCP and MSC
- ``'VCP+HID'``: enable with VCP and HID (human interface device)
- ``'VCP+MSC+HID'``: enabled with VCP, MSC and HID (only available on PYBD boards)
For backwards compatibility, ``'CDC'`` is understood to mean
``'VCP'`` (and similarly for ``'CDC+MSC'`` and ``'CDC+HID'``).
The *port* parameter should be an integer (0, 1, ...) and selects which
USB port to use if the board supports multiple ports. A value of -1 uses
the default or automatically selected port.
The *vid* and *pid* parameters allow you to specify the VID (vendor id)
and PID (product id). A *pid* value of -1 will select a PID based on the
value of *modestr*.
If enabling MSC mode, the *msc* parameter can be used to specify a list
of SCSI LUNs to expose on the mass storage interface. For example
``msc=(pyb.Flash(), pyb.SDCard())``.
If enabling HID mode, you may also specify the HID details by
passing the *hid* keyword parameter. It takes a tuple of
(subclass, protocol, max packet length, polling interval, report
descriptor). By default it will set appropriate values for a USB
mouse. There is also a ``pyb.hid_keyboard`` constant, which is an
appropriate tuple for a USB keyboard.
The *high_speed* parameter, when set to ``True``, enables USB HS mode if
it is supported by the hardware.
"""
# noinspection PyShadowingNames
@overload
def usb_mode(
modestr: str,
/,
*,
port: int = -1,
vid: int = 0xF055,
pid: int = -1,
msc: Sequence[AbstractBlockDev] = (),
hid: tuple[int, int, int, int, bytes] = hid_mouse,
high_speed: bool = False,
) -> None:
"""
If called with no arguments, return the current USB mode as a string.
If called with *modestr* provided, attempts to configure the USB mode.
The following values of *modestr* are understood:
- ``None``: disables USB
- ``'VCP'``: enable with VCP (Virtual COM Port) interface
- ``'MSC'``: enable with MSC (mass storage device class) interface
- ``'VCP+MSC'``: enable with VCP and MSC
- ``'VCP+HID'``: enable with VCP and HID (human interface device)
- ``'VCP+MSC+HID'``: enabled with VCP, MSC and HID (only available on PYBD boards)
For backwards compatibility, ``'CDC'`` is understood to mean
``'VCP'`` (and similarly for ``'CDC+MSC'`` and ``'CDC+HID'``).
The *port* parameter should be an integer (0, 1, ...) and selects which
USB port to use if the board supports multiple ports. A value of -1 uses
the default or automatically selected port.
The *vid* and *pid* parameters allow you to specify the VID (vendor id)
and PID (product id). A *pid* value of -1 will select a PID based on the
value of *modestr*.
If enabling MSC mode, the *msc* parameter can be used to specify a list
of SCSI LUNs to expose on the mass storage interface. For example
``msc=(pyb.Flash(), pyb.SDCard())``.
If enabling HID mode, you may also specify the HID details by
passing the *hid* keyword parameter. It takes a tuple of
(subclass, protocol, max packet length, polling interval, report
descriptor). By default it will set appropriate values for a USB
mouse. There is also a ``pyb.hid_keyboard`` constant, which is an
appropriate tuple for a USB keyboard.
The *high_speed* parameter, when set to ``True``, enables USB HS mode if
it is supported by the hardware.
"""
class Accel:
"""
Accel is an object that controls the accelerometer. Example usage::
accel = pyb.Accel()
for i in range(10):
print(accel.x(), accel.y(), accel.z())
Raw values are between -32 and 31.
"""
def __init__(self):
"""
Create and return an accelerometer object.
"""
def filtered_xyz(self) -> tuple[int, int, int]:
"""
Get a 3-tuple of filtered x, y and z values.
Implementation note: this method is currently implemented as taking the
sum of 4 samples, sampled from the 3 previous calls to this function along
with the sample from the current call. Returned values are therefore 4
times the size of what they would be from the raw x(), y() and z() calls.
"""
def tilt(self) -> int:
"""
Get the tilt register.
"""
def x(self) -> int:
"""
Get the x-axis value.
"""
def y(self) -> int:
"""
Get the y-axis value.
"""
def z(self) -> int:
"""
Get the z-axis value.
"""
class ADC:
"""
Usage::
import pyb
adc = pyb.ADC(pin) # create an analog object from a pin
val = adc.read() # read an analog value
adc = pyb.ADCAll(resolution) # create an ADCAll object
adc = pyb.ADCAll(resolution, mask) # create an ADCAll object for selected analog channels
val = adc.read_channel(channel) # read the given channel
val = adc.read_core_temp() # read MCU temperature
val = adc.read_core_vbat() # read MCU VBAT
val = adc.read_core_vref() # read MCU VREF
val = adc.read_vref() # read MCU supply voltage
"""
def __init__(self, pin: int | Pin, /):
"""
Create an ADC object associated with the given pin.
This allows you to then read analog values on that pin.
"""
def read(self) -> int:
"""
Read the value on the analog pin and return it. The returned value
will be between 0 and 4095.
"""
def read_timed(self, buf: AnyWritableBuf, timer: Timer | int, /) -> None:
"""
Read analog values into ``buf`` at a rate set by the ``timer`` object.
``buf`` can be bytearray or array.array for example. The ADC values have
12-bit resolution and are stored directly into ``buf`` if its element size is
16 bits or greater. If ``buf`` has only 8-bit elements (eg a bytearray) then
the sample resolution will be reduced to 8 bits.
``timer`` should be a Timer object, and a sample is read each time the timer
triggers. The timer must already be initialised and running at the desired
sampling frequency.
To support previous behaviour of this function, ``timer`` can also be an
integer which specifies the frequency (in Hz) to sample at. In this case
Timer(6) will be automatically configured to run at the given frequency.
Example using a Timer object (preferred way)::
adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19
tim = pyb.Timer(6, freq=10) # create a timer running at 10Hz
buf = bytearray(100) # creat a buffer to store the samples
adc.read_timed(buf, tim) # sample 100 values, taking 10s
Example using an integer for the frequency::
adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19
buf = bytearray(100) # create a buffer of 100 bytes
adc.read_timed(buf, 10) # read analog values into buf at 10Hz
# this will take 10 seconds to finish
for val in buf: # loop over all values
print(val) # print the value out
This function does not allocate any heap memory. It has blocking behaviour:
it does not return to the calling program until the buffer is full.
"""
@staticmethod
def read_timed_multi(
adcs: tuple[ADC, ...], bufs: tuple[AnyWritableBuf, ...], timer: Timer, /
) -> bool:
"""
This is a static method. It can be used to extract relative timing or
phase data from multiple ADC's.
It reads analog values from multiple ADC's into buffers at a rate set by
the *timer* object. Each time the timer triggers a sample is rapidly
read from each ADC in turn.
ADC and buffer instances are passed in tuples with each ADC having an
associated buffer. All buffers must be of the same type and length and
the number of buffers must equal the number of ADC's.
Buffers can be ``bytearray`` or ``array.array`` for example. The ADC values
have 12-bit resolution and are stored directly into the buffer if its element
size is 16 bits or greater. If buffers have only 8-bit elements (eg a
``bytearray``) then the sample resolution will be reduced to 8 bits.
*timer* must be a Timer object. The timer must already be initialised
and running at the desired sampling frequency.
Example reading 3 ADC's::
adc0 = pyb.ADC(pyb.Pin.board.X1) # Create ADC's
adc1 = pyb.ADC(pyb.Pin.board.X2)
adc2 = pyb.ADC(pyb.Pin.board.X3)
tim = pyb.Timer(8, freq=100) # Create timer
rx0 = array.array('H', (0 for i in range(100))) # ADC buffers of
rx1 = array.array('H', (0 for i in range(100))) # 100 16-bit words
rx2 = array.array('H', (0 for i in range(100)))
# read analog values into buffers at 100Hz (takes one second)
pyb.ADC.read_timed_multi((adc0, adc1, adc2), (rx0, rx1, rx2), tim)
for n in range(len(rx0)):
print(rx0[n], rx1[n], rx2[n])
This function does not allocate any heap memory. It has blocking behaviour:
it does not return to the calling program until the buffers are full.
The function returns ``True`` if all samples were acquired with correct
timing. At high sample rates the time taken to acquire a set of samples
can exceed the timer period. In this case the function returns ``False``,
indicating a loss of precision in the sample interval. In extreme cases
samples may be missed.
The maximum rate depends on factors including the data width and the
number of ADC's being read. In testing two ADC's were sampled at a timer
rate of 210kHz without overrun. Samples were missed at 215kHz. For three
ADC's the limit is around 140kHz, and for four it is around 110kHz.
At high sample rates disabling interrupts for the duration can reduce the
risk of sporadic data loss.
"""
class ADCAll:
"""
Instantiating this changes all masked ADC pins to analog inputs. The preprocessed MCU temperature,
VREF and VBAT data can be accessed on ADC channels 16, 17 and 18 respectively.
Appropriate scaling is handled according to reference voltage used (usually 3.3V).
The temperature sensor on the chip is factory calibrated and allows to read the die temperature
to +/- 1 degree centigrade. Although this sounds pretty accurate, don't forget that the MCU's internal
temperature is measured. Depending on processing loads and I/O subsystems active the die temperature
may easily be tens of degrees above ambient temperature. On the other hand a pyboard woken up after a
long standby period will show correct ambient temperature within limits mentioned above.
The ``ADCAll`` ``read_core_vbat()``, ``read_vref()`` and ``read_core_vref()`` methods read
the backup battery voltage, reference voltage and the (1.21V nominal) reference voltage using the
actual supply as a reference. All results are floating point numbers giving direct voltage values.
``read_core_vbat()`` returns the voltage of the backup battery. This voltage is also adjusted according
to the actual supply voltage. To avoid analog input overload the battery voltage is measured
via a voltage divider and scaled according to the divider value. To prevent excessive loads
to the backup battery, the voltage divider is only active during ADC conversion.
``read_vref()`` is evaluated by measuring the internal voltage reference and backscale it using
factory calibration value of the internal voltage reference. In most cases the reading would be close
to 3.3V. If the pyboard is operated from a battery, the supply voltage may drop to values below 3.3V.
The pyboard will still operate fine as long as the operating conditions are met. With proper settings
of MCU clock, flash access speed and programming mode it is possible to run the pyboard down to
2 V and still get useful ADC conversion.
It is very important to make sure analog input voltages never exceed actual supply voltage.
Other analog input channels (0..15) will return unscaled integer values according to the selected
precision.
To avoid unwanted activation of analog inputs (channel 0..15) a second parameter can be specified.
This parameter is a binary pattern where each requested analog input has the corresponding bit set.
The default value is 0xffffffff which means all analog inputs are active. If just the internal
channels (16..18) are required, the mask value should be 0x70000.
Example::
adcall = pyb.ADCAll(12, 0x70000) # 12 bit resolution, internal channels
temp = adcall.read_core_temp()
"""
def __init__(self, resolution: int, mask: int = 0xFFFFFFFF, /):
"""
Create a multi-channel ADC instance.
``resolution`` is the number of bits for all the ADCs (even those not enabled); one of:
14, 12, 10, or 8 bits.
To avoid unwanted activation of analog inputs (channel 0..15) a second parameter, ``mask``,
can be specified.
This parameter is a binary pattern where each requested analog input has the corresponding bit set.
The default value is 0xffffffff which means all analog inputs are active. If just the internal
channels (16..18) are required, the mask value should be 0x70000.
"""
def read_channel(self, channel: int, /) -> int:
"""
Read the given channel.
"""
def read_core_temp(self) -> float:
"""
Read MCU temperature (centigrade).
"""
def read_core_vbat(self) -> float:
"""
Read MCU VBAT (volts).
"""
def read_core_vref(self) -> float:
"""
Read MCU VREF (volts).
"""
def read_vref(self) -> float:
"""
Read MCU supply voltage (volts).
"""
class CAN:
"""
CAN implements the standard CAN communications protocol. At
the physical level it consists of 2 lines: RX and TX. Note that
to connect the pyboard to a CAN bus you must use a CAN transceiver
to convert the CAN logic signals from the pyboard to the correct
voltage levels on the bus.
Example usage (works without anything connected)::
from pyb import CAN
can = CAN(1, CAN.LOOPBACK)
can.setfilter(0, CAN.LIST16, 0, (123, 124, 125, 126)) # set a filter to receive messages with id=123, 124, 125 and 126
can.send('message!', 123) # send a message with id 123
can.recv(0) # receive message on FIFO 0
"""
NORMAL: ClassVar[int] = ...
"""
The mode of the CAN bus used in :meth:`~CAN.init()`.
"""
LOOPBACK: ClassVar[int] = ...
"""
The mode of the CAN bus used in :meth:`~CAN.init()`.
"""
SILENT: ClassVar[int] = ...
"""
The mode of the CAN bus used in :meth:`~CAN.init()`.
"""
SILENT_LOOPBACK: ClassVar[int] = ...
"""
The mode of the CAN bus used in :meth:`~CAN.init()`.
"""
STOPPED: ClassVar[int] = ...
"""
Possible states of the CAN controller returned from :meth:`~CAN.state()`.
"""
ERROR_ACTIVE: ClassVar[int] = ...
"""
Possible states of the CAN controller returned from :meth:`~CAN.state()`.
"""
ERROR_WARNING: ClassVar[int] = ...
"""
Possible states of the CAN controller returned from :meth:`~CAN.state()`.
"""
ERROR_PASSIVE: ClassVar[int] = ...
"""
Possible states of the CAN controller returned from :meth:`~CAN.state()`.
"""
BUS_OFF: ClassVar[int] = ...
"""
Possible states of the CAN controller returned from :meth:`~CAN.state()`.
"""
LIST16: ClassVar[int] = ...
"""
The operation mode of a filter used in :meth:`~CAN.setfilter()`.
"""
MASK16: ClassVar[int] = ...
"""
The operation mode of a filter used in :meth:`~CAN.setfilter()`.
"""
LIST32: ClassVar[int] = ...
"""
The operation mode of a filter used in :meth:`~CAN.setfilter()`.
"""
MASK32: ClassVar[int] = ...
"""
The operation mode of a filter used in :meth:`~CAN.setfilter()`.
"""
def __init__(
self,
bus: int | str,
mode: int,
/,
extframe: bool = False,
prescaler: int = 100,
*,
sjw: int = 1,
bs1: int = 6,
bs2: int = 8,
auto_restart: bool = False,
):
"""
Construct a CAN object on the given bus. *bus* can be 1-2, or ``'YA'`` or ``'YB'``.
With no additional parameters, the CAN object is created but not
initialised (it has the settings from the last initialisation of
the bus, if any). If extra arguments are given, the bus is initialised.
See :meth:`CAN.init` for parameters of initialisation.
The physical pins of the CAN buses are:
- ``CAN(1)`` is on ``YA``: ``(RX, TX) = (Y3, Y4) = (PB8, PB9)``
- ``CAN(2)`` is on ``YB``: ``(RX, TX) = (Y5, Y6) = (PB12, PB13)``
"""
@staticmethod
def initfilterbanks(nr: int, /) -> None:
"""
Reset and disable all filter banks and assign how many banks should be available for CAN(1).
STM32F405 has 28 filter banks that are shared between the two available CAN bus controllers.
This function configures how many filter banks should be assigned to each. *nr* is the number of banks
that will be assigned to CAN(1), the rest of the 28 are assigned to CAN(2).
At boot, 14 banks are assigned to each controller.
"""
def init(
self,
mode: int,
/,
extframe: bool = False,
prescaler: int = 100,
*,
sjw: int = 1,
bs1: int = 6,
bs2: int = 8,
auto_restart: bool = False,
baudrate: int = 0,
sample_point: int = 75,
) -> None:
"""
Initialise the CAN bus with the given parameters:
- *mode* is one of: NORMAL, LOOPBACK, SILENT, SILENT_LOOPBACK
- if *extframe* is True then the bus uses extended identifiers in the frames
(29 bits); otherwise it uses standard 11 bit identifiers
- *prescaler* is used to set the duration of 1 time quanta; the time quanta
will be the input clock (PCLK1, see :meth:`pyb.freq()`) divided by the prescaler
- *sjw* is the resynchronisation jump width in units of the time quanta;
it can be 1, 2, 3, 4
- *bs1* defines the location of the sample point in units of the time quanta;
it can be between 1 and 1024 inclusive
- *bs2* defines the location of the transmit point in units of the time quanta;
it can be between 1 and 16 inclusive
- *auto_restart* sets whether the controller will automatically try and restart
communications after entering the bus-off state; if this is disabled then
:meth:`~CAN.restart()` can be used to leave the bus-off state
- *baudrate* if a baudrate other than 0 is provided, this function will try to automatically
calculate a CAN bit-timing (overriding *prescaler*, *bs1* and *bs2*) that satisfies both
the baudrate and the desired *sample_point*.
- *sample_point* given in a percentage of the bit time, the *sample_point* specifies the position
of the last bit sample with respect to the whole bit time. The default *sample_point* is 75%.
The time quanta tq is the basic unit of time for the CAN bus. tq is the CAN
prescaler value divided by PCLK1 (the frequency of internal peripheral bus 1);
see :meth:`pyb.freq()` to determine PCLK1.
A single bit is made up of the synchronisation segment, which is always 1 tq.
Then follows bit segment 1, then bit segment 2. The sample point is after bit
segment 1 finishes. The transmit point is after bit segment 2 finishes.
The baud rate will be 1/bittime, where the bittime is 1 + BS1 + BS2 multiplied
by the time quanta tq.
For example, with PCLK1=42MHz, prescaler=100, sjw=1, bs1=6, bs2=8, the value of
tq is 2.38 microseconds. The bittime is 35.7 microseconds, and the baudrate
is 28kHz.
See page 680 of the STM32F405 datasheet for more details.
"""
def deinit(self) -> None:
"""
Turn off the CAN bus.
"""
def restart(self) -> None:
"""
Force a software restart of the CAN controller without resetting its
configuration.
If the controller enters the bus-off state then it will no longer participate
in bus activity. If the controller is not configured to automatically restart
(see :meth:`~CAN.init()`) then this method can be used to trigger a restart,
and the controller will follow the CAN protocol to leave the bus-off state and
go into the error active state.
"""
def state(self) -> int:
"""
Return the state of the controller. The return value can be one of:
- ``CAN.STOPPED`` -- the controller is completely off and reset;
- ``CAN.ERROR_ACTIVE`` -- the controller is on and in the Error Active state
(both TEC and REC are less than 96);
- ``CAN.ERROR_WARNING`` -- the controller is on and in the Error Warning state
(at least one of TEC or REC is 96 or greater);
- ``CAN.ERROR_PASSIVE`` -- the controller is on and in the Error Passive state
(at least one of TEC or REC is 128 or greater);
- ``CAN.BUS_OFF`` -- the controller is on but not participating in bus activity
(TEC overflowed beyond 255).
"""
@overload
def info(self) -> list[int]:
"""
Get information about the controller's error states and TX and RX buffers.
If *list* is provided then it should be a list object with at least 8 entries,
which will be filled in with the information. Otherwise a new list will be
created and filled in. In both cases the return value of the method is the
populated list.
The values in the list are:
- TEC value
- REC value
- number of times the controller enterted the Error Warning state (wrapped
around to 0 after 65535)
- number of times the controller enterted the Error Passive state (wrapped
around to 0 after 65535)
- number of times the controller enterted the Bus Off state (wrapped
around to 0 after 65535)
- number of pending TX messages
- number of pending RX messages on fifo 0
- number of pending RX messages on fifo 1
"""
@overload
def info(self, list: list[int], /) -> list[int]:
"""
Get information about the controller's error states and TX and RX buffers.
If *list* is provided then it should be a list object with at least 8 entries,
which will be filled in with the information. Otherwise a new list will be
created and filled in. In both cases the return value of the method is the
populated list.
The values in the list are:
- TEC value
- REC value
- number of times the controller enterted the Error Warning state (wrapped
around to 0 after 65535)
- number of times the controller enterted the Error Passive state (wrapped
around to 0 after 65535)
- number of times the controller enterted the Bus Off state (wrapped
around to 0 after 65535)
- number of pending TX messages
- number of pending RX messages on fifo 0
- number of pending RX messages on fifo 1
"""
@overload
def setfilter(
self, bank: int, mode: int, fifo: int, params: Sequence[int], /
) -> None:
"""
Configure a filter bank:
- *bank* is the filter bank that is to be configured.
- *mode* is the mode the filter should operate in.
- *fifo* is which fifo (0 or 1) a message should be stored in, if it is accepted by this filter.
- *params* is an array of values the defines the filter. The contents of the array depends on the *mode* argument.
+-----------+---------------------------------------------------------+
|*mode* |contents of *params* array |
+===========+=========================================================+
|CAN.LIST16 |Four 16 bit ids that will be accepted |
+-----------+---------------------------------------------------------+
|CAN.LIST32 |Two 32 bit ids that will be accepted |
+-----------+---------------------------------------------------------+
|CAN.MASK16 |Two 16 bit id/mask pairs. E.g. (1, 3, 4, 4) |
| | | The first pair, 1 and 3 will accept all ids |
| | | that have bit 0 = 1 and bit 1 = 0. |
| | | The second pair, 4 and 4, will accept all ids |
| | | that have bit 2 = 1. |
+-----------+---------------------------------------------------------+
|CAN.MASK32 |As with CAN.MASK16 but with only one 32 bit id/mask pair.|
+-----------+---------------------------------------------------------+
- *rtr* is an array of booleans that states if a filter should accept a
remote transmission request message. If this argument is not given
then it defaults to ``False`` for all entries. The length of the array
depends on the *mode* argument.
+-----------+----------------------+
|*mode* |length of *rtr* array |
+===========+======================+
|CAN.LIST16 |4 |
+-----------+----------------------+
|CAN.LIST32 |2 |
+-----------+----------------------+
|CAN.MASK16 |2 |
+-----------+----------------------+
|CAN.MASK32 |1 |
+-----------+----------------------+
"""
@overload
def setfilter(
self,
bank: int,
mode: int,
fifo: int,
params: Sequence[int],
/,
*,
rtr: Sequence[bool],
) -> None:
"""
Configure a filter bank:
- *bank* is the filter bank that is to be configured.
- *mode* is the mode the filter should operate in.
- *fifo* is which fifo (0 or 1) a message should be stored in, if it is accepted by this filter.
- *params* is an array of values the defines the filter. The contents of the array depends on the *mode* argument.
+-----------+---------------------------------------------------------+
|*mode* |contents of *params* array |
+===========+=========================================================+
|CAN.LIST16 |Four 16 bit ids that will be accepted |
+-----------+---------------------------------------------------------+
|CAN.LIST32 |Two 32 bit ids that will be accepted |
+-----------+---------------------------------------------------------+
|CAN.MASK16 |Two 16 bit id/mask pairs. E.g. (1, 3, 4, 4) |
| | | The first pair, 1 and 3 will accept all ids |
| | | that have bit 0 = 1 and bit 1 = 0. |
| | | The second pair, 4 and 4, will accept all ids |
| | | that have bit 2 = 1. |
+-----------+---------------------------------------------------------+
|CAN.MASK32 |As with CAN.MASK16 but with only one 32 bit id/mask pair.|
+-----------+---------------------------------------------------------+
- *rtr* is an array of booleans that states if a filter should accept a
remote transmission request message. If this argument is not given
then it defaults to ``False`` for all entries. The length of the array
depends on the *mode* argument.
+-----------+----------------------+
|*mode* |length of *rtr* array |
+===========+======================+
|CAN.LIST16 |4 |
+-----------+----------------------+
|CAN.LIST32 |2 |
+-----------+----------------------+
|CAN.MASK16 |2 |
+-----------+----------------------+
|CAN.MASK32 |1 |
+-----------+----------------------+
"""
def clearfilter(self, bank: int, /) -> None:
"""
Clear and disables a filter bank:
- *bank* is the filter bank that is to be cleared.
"""
def any(self, fifo: int, /) -> bool:
"""
Return ``True`` if any message waiting on the FIFO, else ``False``.
"""
@overload
def recv(
self, fifo: int, /, *, timeout: int = 5000
) -> tuple[int, bool, int, memoryview]:
"""
Receive data on the bus:
- *fifo* is an integer, which is the FIFO to receive on
- *list* is an optional list object to be used as the return value
- *timeout* is the timeout in milliseconds to wait for the receive.
Return value: A tuple containing four values.
- The id of the message.
- A boolean that indicates if the message is an RTR message.
- The FMI (Filter Match Index) value.
- An array containing the data.
If *list* is ``None`` then a new tuple will be allocated, as well as a new
bytes object to contain the data (as the fourth element in the tuple).
If *list* is not ``None`` then it should be a list object with a least four
elements. The fourth element should be a memoryview object which is created
from either a bytearray or an array of type 'B' or 'b', and this array must
have enough room for at least 8 bytes. The list object will then be
populated with the first three return values above, and the memoryview object
will be resized inplace to the size of the data and filled in with that data.
The same list and memoryview objects can be reused in subsequent calls to
this method, providing a way of receiving data without using the heap.
For example::
buf = bytearray(8)
lst = [0, 0, 0, memoryview(buf)]
# No heap memory is allocated in the following call
can.recv(0, lst)
"""
@overload
def recv(
self, fifo: int, list: None, /, *, timeout: int = 5000
) -> tuple[int, bool, int, memoryview]:
"""
Receive data on the bus:
- *fifo* is an integer, which is the FIFO to receive on
- *list* is an optional list object to be used as the return value
- *timeout* is the timeout in milliseconds to wait for the receive.
Return value: A tuple containing four values.
- The id of the message.
- A boolean that indicates if the message is an RTR message.
- The FMI (Filter Match Index) value.
- An array containing the data.
If *list* is ``None`` then a new tuple will be allocated, as well as a new
bytes object to contain the data (as the fourth element in the tuple).
If *list* is not ``None`` then it should be a list object with a least four
elements. The fourth element should be a memoryview object which is created
from either a bytearray or an array of type 'B' or 'b', and this array must
have enough room for at least 8 bytes. The list object will then be
populated with the first three return values above, and the memoryview object
will be resized inplace to the size of the data and filled in with that data.
The same list and memoryview objects can be reused in subsequent calls to
this method, providing a way of receiving data without using the heap.
For example::
buf = bytearray(8)
lst = [0, 0, 0, memoryview(buf)]
# No heap memory is allocated in the following call
can.recv(0, lst)
"""
@overload
def recv(
self, fifo: int, list: list[int | bool | memoryview], /, *, timeout: int = 5000
) -> None:
"""
Receive data on the bus:
- *fifo* is an integer, which is the FIFO to receive on
- *list* is an optional list object to be used as the return value
- *timeout* is the timeout in milliseconds to wait for the receive.
Return value: A tuple containing four values.
- The id of the message.
- A boolean that indicates if the message is an RTR message.
- The FMI (Filter Match Index) value.
- An array containing the data.
If *list* is ``None`` then a new tuple will be allocated, as well as a new
bytes object to contain the data (as the fourth element in the tuple).
If *list* is not ``None`` then it should be a list object with a least four
elements. The fourth element should be a memoryview object which is created
from either a bytearray or an array of type 'B' or 'b', and this array must
have enough room for at least 8 bytes. The list object will then be
populated with the first three return values above, and the memoryview object
will be resized inplace to the size of the data and filled in with that data.
The same list and memoryview objects can be reused in subsequent calls to
this method, providing a way of receiving data without using the heap.
For example::
buf = bytearray(8)
lst = [0, 0, 0, memoryview(buf)]
# No heap memory is allocated in the following call
can.recv(0, lst)
"""
def send(
self,
data: int | AnyWritableBuf,
id: int,
/,
*,
timeout: int = 0,
rtr: bool = False,
) -> None:
"""
Send a message on the bus:
- *data* is the data to send (an integer to send, or a buffer object).
- *id* is the id of the message to be sent.
- *timeout* is the timeout in milliseconds to wait for the send.
- *rtr* is a boolean that specifies if the message shall be sent as
a remote transmission request. If *rtr* is True then only the length
of *data* is used to fill in the DLC slot of the frame; the actual
bytes in *data* are unused.
If timeout is 0 the message is placed in a buffer in one of three hardware
buffers and the method returns immediately. If all three buffers are in use
an exception is thrown. If timeout is not 0, the method waits until the
message is transmitted. If the message can't be transmitted within the
specified time an exception is thrown.
Return value: ``None``.
"""
def rxcallback(self, fifo: int, fun: Callable[[CAN], None], /) -> None:
"""
Register a function to be called when a message is accepted into a empty fifo:
- *fifo* is the receiving fifo.
- *fun* is the function to be called when the fifo becomes non empty.
The callback function takes two arguments the first is the can object it self the second is
a integer that indicates the reason for the callback.
+--------+------------------------------------------------+
| Reason | |
+========+================================================+
| 0 | A message has been accepted into a empty FIFO. |
+--------+------------------------------------------------+
| 1 | The FIFO is full |
+--------+------------------------------------------------+
| 2 | A message has been lost due to a full FIFO |
+--------+------------------------------------------------+
Example use of rxcallback::
def cb0(bus, reason):
print('cb0')
if reason == 0:
print('pending')
if reason == 1:
print('full')
if reason == 2:
print('overflow')
can = CAN(1, CAN.LOOPBACK)
can.rxcallback(0, cb0)
"""
# noinspection PyShadowingNames
class DAC:
"""
The DAC is used to output analog values (a specific voltage) on pin X5 or pin X6.
The voltage will be between 0 and 3.3V.
*This module will undergo changes to the API.*
Example usage::
from pyb import DAC
dac = DAC(1) # create DAC 1 on pin X5
dac.write(128) # write a value to the DAC (makes X5 1.65V)
dac = DAC(1, bits=12) # use 12 bit resolution
dac.write(4095) # output maximum value, 3.3V
To output a continuous sine-wave::
import math
from pyb import DAC
# create a buffer containing a sine-wave
buf = bytearray(100)
for i in range(len(buf)):
buf[i] = 128 + int(127 * math.sin(2 * math.pi * i / len(buf)))
# output the sine-wave at 400Hz
dac = DAC(1)
dac.write_timed(buf, 400 * len(buf), mode=DAC.CIRCULAR)
To output a continuous sine-wave at 12-bit resolution::
import math
from array import array
from pyb import DAC
# create a buffer containing a sine-wave, using half-word samples
buf = array('H', 2048 + int(2047 * math.sin(2 * math.pi * i / 128)) for i in range(128))
# output the sine-wave at 400Hz
dac = DAC(1, bits=12)
dac.write_timed(buf, 400 * len(buf), mode=DAC.CIRCULAR)
"""
NORMAL: ClassVar[int] = ...
"""
Normal mode (output buffer once) for `mode` argument of `write_timed`.
"""
CIRCULAR: ClassVar[int] = ...
"""
Circular mode (output buffer continuously) for `mode` argument of `write_timed`.
"""
def __init__(
self, port: int | Pin, /, bits: int = 8, *, buffering: bool | None = None
):
"""
Construct a new DAC object.
``port`` can be a pin object, or an integer (1 or 2).
DAC(1) is on pin X5 and DAC(2) is on pin X6.
``bits`` is an integer specifying the resolution, and can be 8 or 12.
The maximum value for the write and write_timed methods will be
2\*\*``bits``-1.
The *buffering* parameter selects the behaviour of the DAC op-amp output
buffer, whose purpose is to reduce the output impedance. It can be
``None`` to select the default (buffering enabled for :meth:`DAC.noise`,
:meth:`DAC.triangle` and :meth:`DAC.write_timed`, and disabled for
:meth:`DAC.write`), ``False`` to disable buffering completely, or ``True``
to enable output buffering.
When buffering is enabled the DAC pin can drive loads down to 5KΩ.
Otherwise it has an output impedance of 15KΩ maximum: consequently
to achieve a 1% accuracy without buffering requires the applied load
to be less than 1.5MΩ. Using the buffer incurs a penalty in accuracy,
especially near the extremes of range.
"""
def init(self, bits: int = 8, *, buffering: bool | None = None) -> None:
"""
Reinitialise the DAC. *bits* can be 8 or 12. *buffering* can be
``None``, ``False`` or ``True``; see above constructor for the meaning
of this parameter.
"""
def deinit(self) -> None:
"""
De-initialise the DAC making its pin available for other uses.
"""
def noise(self, freq: int, /) -> None:
"""
Generate a pseudo-random noise signal. A new random sample is written
to the DAC output at the given frequency.
"""
def triangle(self, freq: int, /) -> None:
"""
Generate a triangle wave. The value on the DAC output changes at the given
frequency and ramps through the full 12-bit range (up and down). Therefore
the frequency of the repeating triangle wave itself is 8192 times smaller.
"""
def write(self, value: int, /) -> None:
"""
Direct access to the DAC output. The minimum value is 0. The maximum
value is 2\*\*``bits``-1, where ``bits`` is set when creating the DAC
object or by using the ``init`` method.
"""
def write_timed(
self, data: AnyWritableBuf, freq: int | Timer, /, *, mode: int = NORMAL
) -> None:
"""
Initiates a burst of RAM to DAC using a DMA transfer.
The input data is treated as an array of bytes in 8-bit mode, and
an array of unsigned half-words (array typecode 'H') in 12-bit mode.
``freq`` can be an integer specifying the frequency to write the DAC
samples at, using Timer(6). Or it can be an already-initialised
Timer object which is used to trigger the DAC sample. Valid timers
are 2, 4, 5, 6, 7 and 8.
``mode`` can be ``DAC.NORMAL`` or ``DAC.CIRCULAR``.
Example using both DACs at the same time::
dac1 = DAC(1)
dac2 = DAC(2)
dac1.write_timed(buf1, pyb.Timer(6, freq=100), mode=DAC.CIRCULAR)
dac2.write_timed(buf2, pyb.Timer(7, freq=200), mode=DAC.CIRCULAR)
"""
class ExtInt:
"""
There are a total of 22 interrupt lines. 16 of these can come from GPIO pins
and the remaining 6 are from internal sources.
For lines 0 through 15, a given line can map to the corresponding line from an
arbitrary port. So line 0 can map to Px0 where x is A, B, C, ... and
line 1 can map to Px1 where x is A, B, C, ... ::
def callback(line):
print("line =", line)
Note: ExtInt will automatically configure the gpio line as an input. ::
extint = pyb.ExtInt(pin, pyb.ExtInt.IRQ_FALLING, pyb.Pin.PULL_UP, callback)
Now every time a falling edge is seen on the X1 pin, the callback will be
called. Caution: mechanical pushbuttons have "bounce" and pushing or
releasing a switch will often generate multiple edges.
See: http://www.eng.utah.edu/~cs5780/debouncing.pdf for a detailed
explanation, along with various techniques for debouncing.
Trying to register 2 callbacks onto the same pin will throw an exception.
If pin is passed as an integer, then it is assumed to map to one of the
internal interrupt sources, and must be in the range 16 through 22.
All other pin objects go through the pin mapper to come up with one of the
gpio pins. ::
extint = pyb.ExtInt(pin, mode, pull, callback)
Valid modes are pyb.ExtInt.IRQ_RISING, pyb.ExtInt.IRQ_FALLING,
pyb.ExtInt.IRQ_RISING_FALLING, pyb.ExtInt.EVT_RISING,
pyb.ExtInt.EVT_FALLING, and pyb.ExtInt.EVT_RISING_FALLING.
Only the IRQ_xxx modes have been tested. The EVT_xxx modes have
something to do with sleep mode and the WFE instruction.
Valid pull values are pyb.Pin.PULL_UP, pyb.Pin.PULL_DOWN, pyb.Pin.PULL_NONE.
There is also a C API, so that drivers which require EXTI interrupt lines
can also use this code. See extint.h for the available functions and
usrsw.h for an example of using this.
"""
IRQ_FALLING: ClassVar[int] = ...
"""
interrupt on a falling edge
"""
IRQ_RISING: ClassVar[int] = ...
"""
interrupt on a rising edge
"""
IRQ_RISING_FALLING: ClassVar[int] = ...
"""
interrupt on a rising or falling edge
"""
def __init__(
self,
pin: int | str | Pin,
mode: int,
pull: int,
callback: Callable[[int], None],
):
"""
Create an ExtInt object:
- ``pin`` is the pin on which to enable the interrupt (can be a pin object or any valid pin name).
- ``mode`` can be one of:
- ``ExtInt.IRQ_RISING`` - trigger on a rising edge;
- ``ExtInt.IRQ_FALLING`` - trigger on a falling edge;
- ``ExtInt.IRQ_RISING_FALLING`` - trigger on a rising or falling edge.
- ``pull`` can be one of:
- ``pyb.Pin.PULL_NONE`` - no pull up or down resistors;
- ``pyb.Pin.PULL_UP`` - enable the pull-up resistor;
- ``pyb.Pin.PULL_DOWN`` - enable the pull-down resistor.
- ``callback`` is the function to call when the interrupt triggers. The
callback function must accept exactly 1 argument, which is the line that
triggered the interrupt.
"""
@staticmethod
def regs() -> None:
"""
Dump the values of the EXTI registers.
"""
def disable(self) -> None:
"""
Disable the interrupt associated with the ExtInt object.
This could be useful for debouncing.
"""
def enable(self) -> None:
"""
Enable a disabled interrupt.
"""
def line(self) -> int:
"""
Return the line number that the pin is mapped to.
"""
def swint(self) -> None:
"""
Trigger the callback from software.
"""
class Flash(AbstractBlockDev):
"""
The Flash class allows direct access to the primary flash device on the pyboard.
In most cases, to store persistent data on the device, you'll want to use a
higher-level abstraction, for example the filesystem via Python's standard file
API, but this interface is useful to :ref:`customise the filesystem
configuration ` or implement a low-level storage system for your
application.
"""
@overload
def __init__(self):
"""
Create and return a block device that represents the flash device presented
to the USB mass storage interface.
It includes a virtual partition table at the start, and the actual flash
starts at block ``0x100``.
This constructor is deprecated and will be removed in a future version of MicroPython.
"""
@overload
def __init__(self, *, start: int = -1, len: int = -1):
"""
Create and return a block device that accesses the flash at the specified offset. The length defaults to the remaining size of the device.
The *start* and *len* offsets are in bytes, and must be a multiple of the block size (typically 512 for internal flash).
"""
def readblocks(self, blocknum: int, buf: bytes, offset: int = 0, /) -> None:
"""
These methods implement the simple and :ref:`extended
` block protocol defined by
:class:`os.AbstractBlockDev`.
"""
def writeblocks(self, blocknum: int, buf: bytes, offset: int = 0, /) -> None:
"""
These methods implement the simple and :ref:`extended
` block protocol defined by
:class:`os.AbstractBlockDev`.
"""
def ioctl(self, op: int, arg: int) -> int | None:
"""
These methods implement the simple and :ref:`extended
` block protocol defined by
:class:`os.AbstractBlockDev`.
"""
class I2C:
"""
I2C is a two-wire protocol for communicating between devices. At the physical
level it consists of 2 wires: SCL and SDA, the clock and data lines respectively.
I2C objects are created attached to a specific bus. They can be initialised
when created, or initialised later on.
Example::
from pyb import I2C
i2c = I2C(1) # create on bus 1
i2c = I2C(1, I2C.CONTROLLER) # create and init as a controller
i2c.init(I2C.CONTROLLER, baudrate=20000) # init as a controller
i2c.init(I2C.PERIPHERAL, addr=0x42) # init as a peripheral with given address
i2c.deinit() # turn off the I2C unit
Printing the i2c object gives you information about its configuration.
The basic methods are send and recv::
i2c.send('abc') # send 3 bytes
i2c.send(0x42) # send a single byte, given by the number
data = i2c.recv(3) # receive 3 bytes
To receive inplace, first create a bytearray::
data = bytearray(3) # create a buffer
i2c.recv(data) # receive 3 bytes, writing them into data
You can specify a timeout (in ms)::
i2c.send(b'123', timeout=2000) # timeout after 2 seconds
A controller must specify the recipient's address::
i2c.init(I2C.CONTROLLER)
i2c.send('123', 0x42) # send 3 bytes to peripheral with address 0x42
i2c.send(b'456', addr=0x42) # keyword for address
Master also has other methods::
i2c.is_ready(0x42) # check if peripheral 0x42 is ready
i2c.scan() # scan for peripherals on the bus, returning
# a list of valid addresses
i2c.mem_read(3, 0x42, 2) # read 3 bytes from memory of peripheral 0x42,
# starting at address 2 in the peripheral
i2c.mem_write('abc', 0x42, 2, timeout=1000) # write 'abc' (3 bytes) to memory of peripheral 0x42
# starting at address 2 in the peripheral, timeout after 1 second
"""
CONTROLLER: ClassVar[int] = ...
"""
for initialising the bus to controller mode
"""
PERIPHERAL: ClassVar[int] = ...
"""
for initialising the bus to peripheral mode
"""
def __init__(
self,
bus: int | str,
mode: str,
/,
*,
addr: int = 0x12,
baudrate: int = 400_000,
gencall: bool = False,
dma: bool = False,
):
"""
Construct an I2C object on the given bus. ``bus`` can be 1 or 2, 'X' or
'Y'. With no additional parameters, the I2C object is created but not
initialised (it has the settings from the last initialisation of
the bus, if any). If extra arguments are given, the bus is initialised.
See ``init`` for parameters of initialisation.
The physical pins of the I2C buses on Pyboards V1.0 and V1.1 are:
- ``I2C(1)`` is on the X position: ``(SCL, SDA) = (X9, X10) = (PB6, PB7)``
- ``I2C(2)`` is on the Y position: ``(SCL, SDA) = (Y9, Y10) = (PB10, PB11)``
On the Pyboard Lite:
- ``I2C(1)`` is on the X position: ``(SCL, SDA) = (X9, X10) = (PB6, PB7)``
- ``I2C(3)`` is on the Y position: ``(SCL, SDA) = (Y9, Y10) = (PA8, PB8)``
Calling the constructor with 'X' or 'Y' enables portability between Pyboard
types.
"""
def deinit(self) -> None:
"""
Turn off the I2C bus.
"""
def init(
self,
bus: int | str,
mode: str,
/,
*,
addr: int = 0x12,
baudrate: int = 400_000,
gencall: bool = False,
dma: bool = False,
) -> None:
"""
Initialise the I2C bus with the given parameters:
- ``mode`` must be either ``I2C.CONTROLLER`` or ``I2C.PERIPHERAL``
- ``addr`` is the 7-bit address (only sensible for a peripheral)
- ``baudrate`` is the SCL clock rate (only sensible for a controller)
- ``gencall`` is whether to support general call mode
- ``dma`` is whether to allow the use of DMA for the I2C transfers (note
that DMA transfers have more precise timing but currently do not handle bus
errors properly)
"""
def is_ready(self, addr: int, /) -> bool:
"""
Check if an I2C device responds to the given address. Only valid when in controller mode.
"""
@overload
def mem_read(
self,
data: int,
addr: int,
memaddr: int,
/,
*,
timeout: int = 5000,
addr_size: int = 8,
) -> bytes:
"""
Read from the memory of an I2C device:
- ``data`` can be an integer (number of bytes to read) or a buffer to read into
- ``addr`` is the I2C device address
- ``memaddr`` is the memory location within the I2C device
- ``timeout`` is the timeout in milliseconds to wait for the read
- ``addr_size`` selects width of memaddr: 8 or 16 bits
Returns the read data.
This is only valid in controller mode.
"""
@overload
def mem_read(
self,
data: AnyWritableBuf,
addr: int,
memaddr: int,
/,
*,
timeout: int = 5000,
addr_size: int = 8,
) -> AnyWritableBuf:
"""
Read from the memory of an I2C device:
- ``data`` can be an integer (number of bytes to read) or a buffer to read into
- ``addr`` is the I2C device address
- ``memaddr`` is the memory location within the I2C device
- ``timeout`` is the timeout in milliseconds to wait for the read
- ``addr_size`` selects width of memaddr: 8 or 16 bits
Returns the read data.
This is only valid in controller mode.
"""
def mem_write(
self,
data: int | AnyWritableBuf,
addr: int,
memaddr: int,
/,
*,
timeout: int = 5000,
addr_size: int = 8,
) -> None:
"""
Write to the memory of an I2C device:
- ``data`` can be an integer or a buffer to write from
- ``addr`` is the I2C device address
- ``memaddr`` is the memory location within the I2C device
- ``timeout`` is the timeout in milliseconds to wait for the write
- ``addr_size`` selects width of memaddr: 8 or 16 bits
Returns ``None``.
This is only valid in controller mode.
"""
@overload
def recv(self, recv: int, addr: int = 0x00, /, *, timeout: int = 5000,) -> bytes:
"""
Receive data on the bus:
- ``recv`` can be an integer, which is the number of bytes to receive,
or a mutable buffer, which will be filled with received bytes
- ``addr`` is the address to receive from (only required in controller mode)
- ``timeout`` is the timeout in milliseconds to wait for the receive
Return value: if ``recv`` is an integer then a new buffer of the bytes received,
otherwise the same buffer that was passed in to ``recv``.
"""
@overload
def recv(
self, recv: AnyWritableBuf, addr: int = 0x00, /, *, timeout: int = 5000,
) -> AnyWritableBuf:
"""
Receive data on the bus:
- ``recv`` can be an integer, which is the number of bytes to receive,
or a mutable buffer, which will be filled with received bytes
- ``addr`` is the address to receive from (only required in controller mode)
- ``timeout`` is the timeout in milliseconds to wait for the receive
Return value: if ``recv`` is an integer then a new buffer of the bytes received,
otherwise the same buffer that was passed in to ``recv``.
"""
def send(self, addr: int = 0x00, /, *, timeout: int = 5000,) -> None:
"""
Send data on the bus:
- ``send`` is the data to send (an integer to send, or a buffer object)
- ``addr`` is the address to send to (only required in controller mode)
- ``timeout`` is the timeout in milliseconds to wait for the send
Return value: ``None``.
"""
def scan(self) -> list[int]:
"""
Scan all I2C addresses from 0x01 to 0x7f and return a list of those that respond.
Only valid when in controller mode.
"""
class LCD:
"""
The LCD class is used to control the LCD on the LCD touch-sensor pyskin,
LCD32MKv1.0. The LCD is a 128x32 pixel monochrome screen, part NHD-C12832A1Z.
The pyskin must be connected in either the X or Y positions, and then
an LCD object is made using::
lcd = pyb.LCD('X') # if pyskin is in the X position
lcd = pyb.LCD('Y') # if pyskin is in the Y position
Then you can use::
lcd.light(True) # turn the backlight on
lcd.write('Hello world!\n') # print text to the screen
This driver implements a double buffer for setting/getting pixels.
For example, to make a bouncing dot, try::
x = y = 0
dx = dy = 1
while True:
# update the dot's position
x += dx
y += dy
# make the dot bounce of the edges of the screen
if x <= 0 or x >= 127: dx = -dx
if y <= 0 or y >= 31: dy = -dy
lcd.fill(0) # clear the buffer
lcd.pixel(x, y, 1) # draw the dot
lcd.show() # show the buffer
pyb.delay(50) # pause for 50ms
"""
def __init__(self, skin_position: str, /):
"""
Construct an LCD object in the given skin position. ``skin_position`` can be 'X' or 'Y', and
should match the position where the LCD pyskin is plugged in.
"""
def command(self, inst_data: int, buf: bytes, /) -> None:
"""
Send an arbitrary command to the LCD. Pass 0 for ``instr_data`` to send an
instruction, otherwise pass 1 to send data. ``buf`` is a buffer with the
instructions/data to send.
"""
def contrast(self, value: int, /) -> None:
"""
Set the contrast of the LCD. Valid values are between 0 and 47.
"""
def fill(self, colour: int, /) -> None:
"""
Fill the screen with the given colour (0 or 1 for white or black).
This method writes to the hidden buffer. Use ``show()`` to show the buffer.
"""
def get(self, x: int, y: int, /) -> int:
"""
Get the pixel at the position ``(x, y)``. Returns 0 or 1.
This method reads from the visible buffer.
"""
def light(self, value: bool | int, /) -> None:
"""
Turn the backlight on/off. True or 1 turns it on, False or 0 turns it off.
"""
def pixel(self, x: int, y: int, colour: int, /) -> None:
"""
Set the pixel at ``(x, y)`` to the given colour (0 or 1).
This method writes to the hidden buffer. Use ``show()`` to show the buffer.
"""
def show(self) -> None:
"""
Show the hidden buffer on the screen.
"""
def text(self, str: str, x: int, y: int, colour: int, /) -> None:
"""
Draw the given text to the position ``(x, y)`` using the given colour (0 or 1).
This method writes to the hidden buffer. Use ``show()`` to show the buffer.
"""
def write(self, str: str, /) -> None:
"""
Write the string ``str`` to the screen. It will appear immediately.
"""
class LED:
"""
The LED object controls an individual LED (Light Emitting Diode).
"""
def __init__(self, id: int, /):
"""
Create an LED object associated with the given LED:
- ``id`` is the LED number, 1-4.
"""
@overload
def intensity(self) -> int:
"""
Get or set the LED intensity. Intensity ranges between 0 (off) and 255 (full on).
If no argument is given, return the LED intensity.
If an argument is given, set the LED intensity and return ``None``.
*Note:* Only LED(3) and LED(4) can have a smoothly varying intensity, and
they use timer PWM to implement it. LED(3) uses Timer(2) and LED(4) uses
Timer(3). These timers are only configured for PWM if the intensity of the
relevant LED is set to a value between 1 and 254. Otherwise the timers are
free for general purpose use.
"""
@overload
def intensity(self, value: int, /) -> None:
"""
Get or set the LED intensity. Intensity ranges between 0 (off) and 255 (full on).
If no argument is given, return the LED intensity.
If an argument is given, set the LED intensity and return ``None``.
*Note:* Only LED(3) and LED(4) can have a smoothly varying intensity, and
they use timer PWM to implement it. LED(3) uses Timer(2) and LED(4) uses
Timer(3). These timers are only configured for PWM if the intensity of the
relevant LED is set to a value between 1 and 254. Otherwise the timers are
free for general purpose use.
"""
def off(self) -> None:
"""
Turn the LED off.
"""
def on(self) -> None:
"""
Turn the LED on, to maximum intensity.
"""
def toggle(self) -> None:
"""
Toggle the LED between on (maximum intensity) and off. If the LED is at
non-zero intensity then it is considered "on" and toggle will turn it off.
"""
# noinspection PyNestedDecorators
class Pin:
"""
A pin is the basic object to control I/O pins. It has methods to set
the mode of the pin (input, output, etc) and methods to get and set the
digital logic level. For analog control of a pin, see the ADC class.
Usage Model:
All Board Pins are predefined as pyb.Pin.board.Name::
x1_pin = pyb.Pin.board.X1
g = pyb.Pin(pyb.Pin.board.X1, pyb.Pin.IN)
CPU pins which correspond to the board pins are available
as ``pyb.Pin.cpu.Name``. For the CPU pins, the names are the port letter
followed by the pin number. On the PYBv1.0, ``pyb.Pin.board.X1`` and
``pyb.Pin.cpu.A0`` are the same pin.
You can also use strings::
g = pyb.Pin('X1', pyb.Pin.OUT_PP)
Users can add their own names::
MyMapperDict = { 'LeftMotorDir' : pyb.Pin.cpu.C12 }
pyb.Pin.dict(MyMapperDict)
g = pyb.Pin("LeftMotorDir", pyb.Pin.OUT_OD)
and can query mappings::
pin = pyb.Pin("LeftMotorDir")
Users can also add their own mapping function::
def MyMapper(pin_name):
if pin_name == "LeftMotorDir":
return pyb.Pin.cpu.A0
pyb.Pin.mapper(MyMapper)
So, if you were to call: ``pyb.Pin("LeftMotorDir", pyb.Pin.OUT_PP)``
then ``"LeftMotorDir"`` is passed directly to the mapper function.
To summarise, the following order determines how things get mapped into
an ordinal pin number:
1. Directly specify a pin object
2. User supplied mapping function
3. User supplied mapping (object must be usable as a dictionary key)
4. Supply a string which matches a board pin
5. Supply a string which matches a CPU port/pin
You can set ``pyb.Pin.debug(True)`` to get some debug information about
how a particular object gets mapped to a pin.
When a pin has the ``Pin.PULL_UP`` or ``Pin.PULL_DOWN`` pull-mode enabled,
that pin has an effective 40k Ohm resistor pulling it to 3V3 or GND
respectively (except pin Y5 which has 11k Ohm resistors).
Now every time a falling edge is seen on the gpio pin, the callback will be
executed. Caution: mechanical push buttons have "bounce" and pushing or
releasing a switch will often generate multiple edges.
See: http://www.eng.utah.edu/~cs5780/debouncing.pdf for a detailed
explanation, along with various techniques for debouncing.
All pin objects go through the pin mapper to come up with one of the
gpio pins.
"""
AF1_TIM1: ClassVar[PinAF] = ...
"""
Alternate def_ 1, timer 1.
"""
AF1_TIM2: ClassVar[PinAF] = ...
"""
Alternate def_ 1, timer 2.
"""
AF2_TIM3: ClassVar[PinAF] = ...
"""
Alternate def_ 2, timer 3.
"""
AF2_TIM4: ClassVar[PinAF] = ...
"""
Alternate def_ 2, timer 4.
"""
AF2_TIM5: ClassVar[PinAF] = ...
"""
Alternate def_ 2, timer 5.
"""
AF3_TIM10: ClassVar[PinAF] = ...
"""
Alternate def_ 3, timer 10.
"""
AF3_TIM11: ClassVar[PinAF] = ...
"""
Alternate def_ 3, timer 11.
"""
AF3_TIM8: ClassVar[PinAF] = ...
"""
Alternate def_ 3, timer 8.
"""
AF3_TIM9: ClassVar[PinAF] = ...
"""
Alternate def_ 3, timer 9.
"""
AF4_I2C1: ClassVar[PinAF] = ...
"""
Alternate def_ 4, I2C 1.
"""
AF4_I2C2: ClassVar[PinAF] = ...
"""
Alternate def_ 4, I2C 2.
"""
AF5_SPI1: ClassVar[PinAF] = ...
"""
Alternate def_ 5, SPI 1.
"""
AF5_SPI2: ClassVar[PinAF] = ...
"""
Alternate def_ 5, SPI 2.
"""
AF7_USART1: ClassVar[PinAF] = ...
"""
Alternate def_ 7, USART 1.
"""
AF7_USART2: ClassVar[PinAF] = ...
"""
Alternate def_ 7, USART 2.
"""
AF7_USART3: ClassVar[PinAF] = ...
"""
Alternate def_ 7, USART 3.
"""
AF8_UART4: ClassVar[PinAF] = ...
"""
Alternate def_ 8, USART 4.
"""
AF8_USART6: ClassVar[PinAF] = ...
"""
Alternate def_ 8, USART 6.
"""
AF9_CAN1: ClassVar[PinAF] = ...
"""
Alternate def_ 9, CAN 1.
"""
AF9_CAN2: ClassVar[PinAF] = ...
"""
Alternate def_ 9, CAN 2.
"""
AF9_TIM12: ClassVar[PinAF] = ...
"""
Alternate def_ 9, timer 12.
"""
AF9_TIM13: ClassVar[PinAF] = ...
"""
Alternate def_ 9, timer 13.
"""
AF9_TIM14: ClassVar[PinAF] = ...
"""
Alternate def_ 9, timer 14.
"""
ALT: ClassVar[int] = ...
"""
Initialise the pin to alternate-def_ mode with a push-pull drive (same as `AF_PP`).
"""
ALT_OPEN_DRAIN: ClassVar[int] = ...
"""
Initialise the pin to alternate-def_ mode with an open-drain drive (same as `AF_OD`).
"""
IRQ_FALLING: ClassVar[int] = ...
"""
Initialise the pin to generate an interrupt on a falling edge.
"""
IRQ_RISING: ClassVar[int] = ...
"""
Initialise the pin to generate an interrupt on a rising edge.
"""
OPEN_DRAIN: ClassVar[int] = ...
"""
Initialise the pin to output mode with an open-drain drive (same as `OUT_OD`).
"""
# noinspection PyPep8Naming
class board:
"""
The board pins (board nomenclature, e.g. `X1`) that are bought out onto pads on a PyBoard.
"""
LED_BLUE: ClassVar[Pin] = ...
"""
The blue LED.
"""
LED_GREEN: ClassVar[Pin] = ...
"""
The green LED.
"""
LED_RED: ClassVar[Pin] = ...
"""
The red LED.
"""
LED_YELLOW: ClassVar[Pin] = ...
"""
The yellow LED.
"""
MMA_AVDD: ClassVar[Pin] = ...
"""
Accelerometer (MMA7660) analogue power (AVDD) pin.
"""
MMA_INT: ClassVar[Pin] = ...
"""
Accelerometer (MMA7660) interrupt (\INT) pin.
"""
SD: ClassVar[Pin] = ...
"""
SD card present switch (0 for card inserted, 1 for no card) (same as SD_SW).
"""
SD_CK: ClassVar[Pin] = ...
"""
SD card clock.
"""
SD_CMD: ClassVar[Pin] = ...
"""
SD card command.
"""
SD_D0: ClassVar[Pin] = ...
"""
SD card serial data 0.
"""
SD_D1: ClassVar[Pin] = ...
"""
SD card serial data 1.
"""
SD_D2: ClassVar[Pin] = ...
"""
SD card serial data 2.
"""
SD_D3: ClassVar[Pin] = ...
"""
SD card serial data 3.
"""
SD_SW: ClassVar[Pin] = ...
"""
SD card present switch (0 for card inserted, 1 for no card) (same as SD).
"""
SW: ClassVar[Pin] = ...
"""
Usr switch (0 = pressed, 1 = not pressed).
"""
USB_DM: ClassVar[Pin] = ...
"""
USB data -.
"""
USB_DP: ClassVar[Pin] = ...
"""
USB data +.
"""
USB_ID: ClassVar[Pin] = ...
"""
USB OTG (on-the-go) ID.
"""
USB_VBUS: ClassVar[Pin] = ...
"""
USB VBUS (power) monitoring pin.
"""
X1: ClassVar[Pin] = ...
"""
X1 pin.
"""
X10: ClassVar[Pin] = ...
"""
X10 pin.
"""
X11: ClassVar[Pin] = ...
"""
X11 pin.
"""
X12: ClassVar[Pin] = ...
"""
X12 pin.
"""
X17: ClassVar[Pin] = ...
"""
X17 pin.
"""
X18: ClassVar[Pin] = ...
"""
X18 pin.
"""
X19: ClassVar[Pin] = ...
"""
X19 pin.
"""
X2: ClassVar[Pin] = ...
"""
X2 pin.
"""
X20: ClassVar[Pin] = ...
"""
X20 pin.
"""
X21: ClassVar[Pin] = ...
"""
X21 pin.
"""
X22: ClassVar[Pin] = ...
"""
X22 pin.
"""
X3: ClassVar[Pin] = ...
"""
X3 pin.
"""
X4: ClassVar[Pin] = ...
"""
X4 pin.
"""
X5: ClassVar[Pin] = ...
"""
X5 pin.
"""
X6: ClassVar[Pin] = ...
"""
X6 pin.
"""
X7: ClassVar[Pin] = ...
"""
X7 pin.
"""
X8: ClassVar[Pin] = ...
"""
X8 pin.
"""
X9: ClassVar[Pin] = ...
"""
X9 pin.
"""
Y1: ClassVar[Pin] = ...
"""
Y1 pin.
"""
Y10: ClassVar[Pin] = ...
"""
Y10 pin.
"""
Y11: ClassVar[Pin] = ...
"""
Y11 pin.
"""
Y12: ClassVar[Pin] = ...
"""
Y12 pin.
"""
Y2: ClassVar[Pin] = ...
"""
Y2 pin.
"""
Y3: ClassVar[Pin] = ...
"""
Y3 pin.
"""
Y4: ClassVar[Pin] = ...
"""
Y4 pin.
"""
Y5: ClassVar[Pin] = ...
"""
Y5 pin.
"""
Y6: ClassVar[Pin] = ...
"""
Y6 pin.
"""
Y7: ClassVar[Pin] = ...
"""
Y7 pin.
"""
Y8: ClassVar[Pin] = ...
"""
Y8 pin.
"""
Y9: ClassVar[Pin] = ...
"""
Y9 pin.
"""
# noinspection PyPep8Naming
class cpu:
"""
The CPU pins (CPU nomenclature, e.g. `A0`) that are bought out onto pads on a PyBoard.
"""
A0: ClassVar[Pin] = ...
"""
A0 pin.
"""
A1: ClassVar[Pin] = ...
"""
A1 pin.
"""
A10: ClassVar[Pin] = ...
"""
A10 pin.
"""
A11: ClassVar[Pin] = ...
"""
A11 pin.
"""
A12: ClassVar[Pin] = ...
"""
A12 pin.
"""
A13: ClassVar[Pin] = ...
"""
A13 pin.
"""
A14: ClassVar[Pin] = ...
"""
A14 pin.
"""
A15: ClassVar[Pin] = ...
"""
A15 pin.
"""
A2: ClassVar[Pin] = ...
"""
A2 pin.
"""
A3: ClassVar[Pin] = ...
"""
A3 pin.
"""
A4: ClassVar[Pin] = ...
"""
A4 pin.
"""
A5: ClassVar[Pin] = ...
"""
A5 pin.
"""
A6: ClassVar[Pin] = ...
"""
A6 pin.
"""
A7: ClassVar[Pin] = ...
"""
A7 pin.
"""
A8: ClassVar[Pin] = ...
"""
A8 pin.
"""
A9: ClassVar[Pin] = ...
"""
A9 pin.
"""
B0: ClassVar[Pin] = ...
"""
B0 pin.
"""
B1: ClassVar[Pin] = ...
"""
B1 pin.
"""
B10: ClassVar[Pin] = ...
"""
B10 pin.
"""
B11: ClassVar[Pin] = ...
"""
B11 pin.
"""
B12: ClassVar[Pin] = ...
"""
B12 pin.
"""
B13: ClassVar[Pin] = ...
"""
B13 pin.
"""
B14: ClassVar[Pin] = ...
"""
B14 pin.
"""
B15: ClassVar[Pin] = ...
"""
B15 pin.
"""
B2: ClassVar[Pin] = ...
"""
B2 pin.
"""
B3: ClassVar[Pin] = ...
"""
B3 pin.
"""
B4: ClassVar[Pin] = ...
"""
B4 pin.
"""
B5: ClassVar[Pin] = ...
"""
B5 pin.
"""
B6: ClassVar[Pin] = ...
"""
B6 pin.
"""
B7: ClassVar[Pin] = ...
"""
B7 pin.
"""
B8: ClassVar[Pin] = ...
"""
B8 pin.
"""
B9: ClassVar[Pin] = ...
"""
B9 pin.
"""
C0: ClassVar[Pin] = ...
"""
C0 pin.
"""
C1: ClassVar[Pin] = ...
"""
C1 pin.
"""
C10: ClassVar[Pin] = ...
"""
C10 pin.
"""
C11: ClassVar[Pin] = ...
"""
C11 pin.
"""
C12: ClassVar[Pin] = ...
"""
C12 pin.
"""
C13: ClassVar[Pin] = ...
"""
C13 pin.
"""
C2: ClassVar[Pin] = ...
"""
C2 pin.
"""
C3: ClassVar[Pin] = ...
"""
C3 pin.
"""
C4: ClassVar[Pin] = ...
"""
C4 pin.
"""
C5: ClassVar[Pin] = ...
"""
C5 pin.
"""
C6: ClassVar[Pin] = ...
"""
C6 pin.
"""
C7: ClassVar[Pin] = ...
"""
C7 pin.
"""
C8: ClassVar[Pin] = ...
"""
C8 pin.
"""
C9: ClassVar[Pin] = ...
"""
C9 pin.
"""
D2: ClassVar[Pin] = ...
"""
D2 pin.
"""
AF_OD: ClassVar[int] = ...
"""
initialise the pin to alternate-function mode with an open-drain drive
"""
AF_PP: ClassVar[int] = ...
"""
initialise the pin to alternate-function mode with a push-pull drive
"""
ANALOG: ClassVar[int] = ...
"""
initialise the pin to analog mode
"""
IN: ClassVar[int] = ...
"""
initialise the pin to input mode
"""
OUT_OD: ClassVar[int] = ...
"""
initialise the pin to output mode with an open-drain drive
"""
OUT_PP: ClassVar[int] = ...
"""
initialise the pin to output mode with a push-pull drive
"""
PULL_DOWN: ClassVar[int] = ...
"""
enable the pull-down resistor on the pin
"""
PULL_NONE: ClassVar[int] = ...
"""
don't enable any pull up or down resistors on the pin
"""
PULL_UP: ClassVar[int] = ...
"""
enable the pull-up resistor on the pin
"""
def __init__(
self,
id: Pin | str,
/,
mode: int = IN,
pull: int = PULL_NONE,
*,
value: Any = None,
alt: str | int = -1,
):
"""
Create a new Pin object associated with the id. If additional arguments are given,
they are used to initialise the pin. See :meth:`pin.init`.
"""
@overload
@staticmethod
def debug() -> bool:
"""
Get or set the debugging state (``True`` or ``False`` for on or off).
"""
@overload
@staticmethod
def debug(state: bool, /) -> None:
"""
Get or set the debugging state (``True`` or ``False`` for on or off).
"""
@overload
@staticmethod
def dict() -> Dict[str, Pin]:
"""
Get or set the pin mapper dictionary.
"""
@overload
@staticmethod
def dict(dict: Dict[str, Pin], /) -> None:
"""
Get or set the pin mapper dictionary.
"""
@overload
@staticmethod
def mapper() -> Callable[[str], Pin]:
"""
Get or set the pin mapper function.
"""
@overload
@staticmethod
def mapper(fun: Callable[[str], Pin], /) -> None:
"""
Get or set the pin mapper function.
"""
def init(
self,
mode: int = IN,
pull: int = PULL_NONE,
*,
value: Any = None,
alt: str | int = -1,
) -> None:
"""
Initialise the pin:
- *mode* can be one of:
- ``Pin.IN`` - configure the pin for input;
- ``Pin.OUT_PP`` - configure the pin for output, with push-pull control;
- ``Pin.OUT_OD`` - configure the pin for output, with open-drain control;
- ``Pin.AF_PP`` - configure the pin for alternate function, pull-pull;
- ``Pin.AF_OD`` - configure the pin for alternate function, open-drain;
- ``Pin.ANALOG`` - configure the pin for analog.
- *pull* can be one of:
- ``Pin.PULL_NONE`` - no pull up or down resistors;
- ``Pin.PULL_UP`` - enable the pull-up resistor;
- ``Pin.PULL_DOWN`` - enable the pull-down resistor.
- *value* if not None will set the port output value before enabling the pin.
- *alt* can be used when mode is ``Pin.AF_PP`` or ``Pin.AF_OD`` to set the
index or name of one of the alternate functions associated with a pin.
This arg was previously called *af* which can still be used if needed.
Returns: ``None``.
"""
@overload
def value(self) -> int:
"""
Get or set the digital logic level of the pin:
- With no argument, return 0 or 1 depending on the logic level of the pin.
- With ``value`` given, set the logic level of the pin. ``value`` can be
anything that converts to a boolean. If it converts to ``True``, the pin
is set high, otherwise it is set low.
"""
@overload
def value(self, value: Any, /) -> None:
"""
Get or set the digital logic level of the pin:
- With no argument, return 0 or 1 depending on the logic level of the pin.
- With ``value`` given, set the logic level of the pin. ``value`` can be
anything that converts to a boolean. If it converts to ``True``, the pin
is set high, otherwise it is set low.
"""
def __str__(self) -> str:
"""
Return a string describing the pin object.
"""
def af(self) -> int:
"""
Returns the currently configured alternate-function of the pin. The
integer returned will match one of the allowed constants for the af
argument to the init function.
"""
def af_list(self) -> list[PinAF]:
"""
Returns an array of alternate functions available for this pin.
"""
def gpio(self) -> int:
"""
Returns the base address of the GPIO block associated with this pin.
"""
def mode(self) -> int:
"""
Returns the currently configured mode of the pin. The integer returned
will match one of the allowed constants for the mode argument to the init
function.
"""
def name(self) -> str:
"""
Get the pin name.
"""
def names(self) -> list[str]:
"""
Returns the cpu and board names for this pin.
"""
def pin(self) -> int:
"""
Get the pin number.
"""
def port(self) -> int:
"""
Get the pin port.
"""
def pull(self) -> int:
"""
Returns the currently configured pull of the pin. The integer returned
will match one of the allowed constants for the pull argument to the init
function.
"""
class PinAF(ABC):
"""
A Pin represents a physical pin on the microprocessor. Each pin
can have a variety of functions (GPIO, I2C SDA, etc). Each PinAF
object represents a particular function for a pin.
Usage Model::
x3 = pyb.Pin.board.X3
x3_af = x3.af_list()
x3_af will now contain an array of PinAF objects which are available on
pin X3.
For the pyboard, x3_af would contain:
[Pin.AF1_TIM2, Pin.AF2_TIM5, Pin.AF3_TIM9, Pin.AF7_USART2]
Normally, each peripheral would configure the af automatically, but sometimes
the same function is available on multiple pins, and having more control
is desired.
To configure X3 to expose TIM2_CH3, you could use::
pin = pyb.Pin(pyb.Pin.board.X3, mode=pyb.Pin.AF_PP, af=pyb.Pin.AF1_TIM2)
or::
pin = pyb.Pin(pyb.Pin.board.X3, mode=pyb.Pin.AF_PP, af=1)
"""
__slots__ = ()
@abstractmethod
def __str__(self) -> str:
"""
Return a string describing the alternate function.
"""
@abstractmethod
def index(self) -> int:
"""
Return the alternate function index.
"""
@abstractmethod
def name(self) -> str:
"""
Return the name of the alternate function.
"""
@abstractmethod
def reg(self) -> int:
"""
Return the base register associated with the peripheral assigned to this
alternate function. For example, if the alternate function were TIM2_CH3
this would return stm.TIM2
"""
class RTC:
"""
The RTC is an independent clock that keeps track of the date
and time.
Example usage::
rtc = pyb.RTC()
rtc.datetime((2014, 5, 1, 4, 13, 0, 0, 0))
print(rtc.datetime())
"""
def __init__(self):
"""
Create an RTC object.
"""
def datetime(
self, datetimetuple: tuple[int, int, int, int, int, int, int, int], /
) -> None:
"""
Get or set the date and time of the RTC.
With no arguments, this method returns an 8-tuple with the current
date and time. With 1 argument (being an 8-tuple) it sets the date
and time (and ``subseconds`` is reset to 255).
The 8-tuple has the following format:
(year, month, day, weekday, hours, minutes, seconds, subseconds)
``weekday`` is 1-7 for Monday through Sunday.
``subseconds`` counts down from 255 to 0
"""
def wakeup(
self, timeout: int, callback: Callable[[RTC], None] | None = None, /
) -> None:
"""
Set the RTC wakeup timer to trigger repeatedly at every ``timeout``
milliseconds. This trigger can wake the pyboard from both the sleep
states: :meth:`pyb.stop` and :meth:`pyb.standby`.
If ``timeout`` is ``None`` then the wakeup timer is disabled.
If ``callback`` is given then it is executed at every trigger of the
wakeup timer. ``callback`` must take exactly one argument.
"""
def info(self) -> int:
"""
Get information about the startup time and reset source.
- The lower 0xffff are the number of milliseconds the RTC took to
start up.
- Bit 0x10000 is set if a power-on reset occurred.
- Bit 0x20000 is set if an external reset occurred
"""
@overload
def calibration(self) -> int:
"""
Get or set RTC calibration.
With no arguments, ``calibration()`` returns the current calibration
value, which is an integer in the range [-511 : 512]. With one
argument it sets the RTC calibration.
The RTC Smooth Calibration mechanism adjusts the RTC clock rate by
adding or subtracting the given number of ticks from the 32768 Hz
clock over a 32 second period (corresponding to 2^20 clock ticks.)
Each tick added will speed up the clock by 1 part in 2^20, or 0.954
ppm; likewise the RTC clock it slowed by negative values. The
usable calibration range is:
(-511 * 0.954) ~= -487.5 ppm up to (512 * 0.954) ~= 488.5 ppm
"""
@overload
def calibration(self, cal: int, /) -> None:
"""
Get or set RTC calibration.
With no arguments, ``calibration()`` returns the current calibration
value, which is an integer in the range [-511 : 512]. With one
argument it sets the RTC calibration.
The RTC Smooth Calibration mechanism adjusts the RTC clock rate by
adding or subtracting the given number of ticks from the 32768 Hz
clock over a 32 second period (corresponding to 2^20 clock ticks.)
Each tick added will speed up the clock by 1 part in 2^20, or 0.954
ppm; likewise the RTC clock it slowed by negative values. The
usable calibration range is:
(-511 * 0.954) ~= -487.5 ppm up to (512 * 0.954) ~= 488.5 ppm
"""
class Servo:
"""
Servo objects control standard hobby servo motors with 3-wires (ground, power,
signal). There are 4 positions on the pyboard where these motors can be plugged
in: pins X1 through X4 are the signal pins, and next to them are 4 sets of power
and ground pins.
Example usage::
import pyb
s1 = pyb.Servo(1) # create a servo object on position X1
s2 = pyb.Servo(2) # create a servo object on position X2
s1.angle(45) # move servo 1 to 45 degrees
s2.angle(0) # move servo 2 to 0 degrees
# move servo1 and servo2 synchronously, taking 1500ms
s1.angle(-60, 1500)
s2.angle(30, 1500)
.. note:: The Servo objects use Timer(5) to produce the PWM output. You can
use Timer(5) for Servo control, or your own purposes, but not both at the
same time.
"""
def __init__(self, id: int, /):
"""
Create a servo object. ``id`` is 1-4, and corresponds to pins X1 through X4.
"""
@overload
def angle(self) -> int:
"""
If no arguments are given, this function returns the current angle.
If arguments are given, this function sets the angle of the servo:
- ``angle`` is the angle to move to in degrees.
- ``time`` is the number of milliseconds to take to get to the specified
angle. If omitted, then the servo moves as quickly as possible to its
new position.
"""
@overload
def angle(self, angle: int, time: int = 0, /) -> None:
"""
If no arguments are given, this function returns the current angle.
If arguments are given, this function sets the angle of the servo:
- ``angle`` is the angle to move to in degrees.
- ``time`` is the number of milliseconds to take to get to the specified
angle. If omitted, then the servo moves as quickly as possible to its
new position.
"""
@overload
def speed(self) -> int:
"""
If no arguments are given, this function returns the current speed.
If arguments are given, this function sets the speed of the servo:
- ``speed`` is the speed to change to, between -100 and 100.
- ``time`` is the number of milliseconds to take to get to the specified
speed. If omitted, then the servo accelerates as quickly as possible.
"""
@overload
def speed(self, speed: int, time: int = 0, /) -> None:
"""
If no arguments are given, this function returns the current speed.
If arguments are given, this function sets the speed of the servo:
- ``speed`` is the speed to change to, between -100 and 100.
- ``time`` is the number of milliseconds to take to get to the specified
speed. If omitted, then the servo accelerates as quickly as possible.
"""
@overload
def speed(self) -> int:
"""
If no arguments are given, this function returns the current raw pulse-width
value.
If an argument is given, this function sets the raw pulse-width value.
"""
@overload
def speed(self, value: int, /) -> None:
"""
If no arguments are given, this function returns the current raw pulse-width
value.
If an argument is given, this function sets the raw pulse-width value.
"""
@overload
def calibration(self) -> tuple[int, int, int, int, int]:
"""
If no arguments are given, this function returns the current calibration
data, as a 5-tuple.
If arguments are given, this function sets the timing calibration:
- ``pulse_min`` is the minimum allowed pulse width.
- ``pulse_max`` is the maximum allowed pulse width.
- ``pulse_centre`` is the pulse width corresponding to the centre/zero position.
- ``pulse_angle_90`` is the pulse width corresponding to 90 degrees.
- ``pulse_speed_100`` is the pulse width corresponding to a speed of 100.
"""
@overload
def calibration(self, pulse_min: int, pulse_max: int, pulse_centre: int, /) -> None:
"""
If no arguments are given, this function returns the current calibration
data, as a 5-tuple.
If arguments are given, this function sets the timing calibration:
- ``pulse_min`` is the minimum allowed pulse width.
- ``pulse_max`` is the maximum allowed pulse width.
- ``pulse_centre`` is the pulse width corresponding to the centre/zero position.
- ``pulse_angle_90`` is the pulse width corresponding to 90 degrees.
- ``pulse_speed_100`` is the pulse width corresponding to a speed of 100.
"""
@overload
def calibration(
self,
pulse_min: int,
pulse_max: int,
pulse_centre: int,
pulse_angle_90: int,
pulse_speed_100: int,
/,
) -> None:
"""
If no arguments are given, this function returns the current calibration
data, as a 5-tuple.
If arguments are given, this function sets the timing calibration:
- ``pulse_min`` is the minimum allowed pulse width.
- ``pulse_max`` is the maximum allowed pulse width.
- ``pulse_centre`` is the pulse width corresponding to the centre/zero position.
- ``pulse_angle_90`` is the pulse width corresponding to 90 degrees.
- ``pulse_speed_100`` is the pulse width corresponding to a speed of 100.
"""
class SPI:
"""
SPI is a serial protocol that is driven by a controller. At the physical level
there are 3 lines: SCK, MOSI, MISO.
See usage model of I2C; SPI is very similar. Main difference is
parameters to init the SPI bus::
from pyb import SPI
spi = SPI(1, SPI.CONTROLLER, baudrate=600000, polarity=1, phase=0, crc=0x7)
Only required parameter is mode, SPI.CONTROLLER or SPI.PERIPHERAL. Polarity can be
0 or 1, and is the level the idle clock line sits at. Phase can be 0 or 1
to sample data on the first or second clock edge respectively. Crc can be
None for no CRC, or a polynomial specifier.
Additional methods for SPI::
data = spi.send_recv(b'1234') # send 4 bytes and receive 4 bytes
buf = bytearray(4)
spi.send_recv(b'1234', buf) # send 4 bytes and receive 4 into buf
spi.send_recv(buf, buf) # send/recv 4 bytes from/to buf
"""
CONTROLLER: ClassVar[int] = ...
"""
for initialising the SPI bus to controller or peripheral mode
"""
PERIPHERAL: ClassVar[int] = ...
"""
for initialising the SPI bus to controller or peripheral mode
"""
LSB: ClassVar[int] = ...
"""
set the first bit to be the least or most significant bit
"""
MSB: ClassVar[int] = ...
"""
set the first bit to be the least or most significant bit
"""
@overload
def __init__(self, bus: int, /):
"""
Construct an SPI object on the given bus. ``bus`` can be 1 or 2, or
'X' or 'Y'. With no additional parameters, the SPI object is created but
not initialised (it has the settings from the last initialisation of
the bus, if any). If extra arguments are given, the bus is initialised.
See ``init`` for parameters of initialisation.
The physical pins of the SPI buses are:
- ``SPI(1)`` is on the X position: ``(NSS, SCK, MISO, MOSI) = (X5, X6, X7, X8) = (PA4, PA5, PA6, PA7)``
- ``SPI(2)`` is on the Y position: ``(NSS, SCK, MISO, MOSI) = (Y5, Y6, Y7, Y8) = (PB12, PB13, PB14, PB15)``
At the moment, the NSS pin is not used by the SPI driver and is free
for other use.
"""
@overload
def __init__(
self,
bus: int,
/,
mode: int = CONTROLLER,
baudrate: int = 328125,
*,
polarity: int = 1,
phase: int = 0,
bits: int = 8,
firstbit: int = MSB,
ti: bool = False,
crc: int | None = None,
):
"""
Construct an SPI object on the given bus. ``bus`` can be 1 or 2, or
'X' or 'Y'. With no additional parameters, the SPI object is created but
not initialised (it has the settings from the last initialisation of
the bus, if any). If extra arguments are given, the bus is initialised.
See ``init`` for parameters of initialisation.
The physical pins of the SPI buses are:
- ``SPI(1)`` is on the X position: ``(NSS, SCK, MISO, MOSI) = (X5, X6, X7, X8) = (PA4, PA5, PA6, PA7)``
- ``SPI(2)`` is on the Y position: ``(NSS, SCK, MISO, MOSI) = (Y5, Y6, Y7, Y8) = (PB12, PB13, PB14, PB15)``
At the moment, the NSS pin is not used by the SPI driver and is free
for other use.
"""
@overload
def __init__(
self,
bus: int,
/,
mode: int = CONTROLLER,
*,
prescaler: int = 256,
polarity: int = 1,
phase: int = 0,
bits: int = 8,
firstbit: int = MSB,
ti: bool = False,
crc: int | None = None,
):
"""
Construct an SPI object on the given bus. ``bus`` can be 1 or 2, or
'X' or 'Y'. With no additional parameters, the SPI object is created but
not initialised (it has the settings from the last initialisation of
the bus, if any). If extra arguments are given, the bus is initialised.
See ``init`` for parameters of initialisation.
The physical pins of the SPI buses are:
- ``SPI(1)`` is on the X position: ``(NSS, SCK, MISO, MOSI) = (X5, X6, X7, X8) = (PA4, PA5, PA6, PA7)``
- ``SPI(2)`` is on the Y position: ``(NSS, SCK, MISO, MOSI) = (Y5, Y6, Y7, Y8) = (PB12, PB13, PB14, PB15)``
At the moment, the NSS pin is not used by the SPI driver and is free
for other use.
"""
def deinit(self) -> None:
"""
Turn off the SPI bus.
"""
@overload
def init(
self,
mode: int = CONTROLLER,
baudrate: int = 328125,
*,
polarity: int = 1,
phase: int = 0,
bits: int = 8,
firstbit: int = MSB,
ti: bool = False,
crc: int | None = None,
):
"""
Initialise the SPI bus with the given parameters:
- ``mode`` must be either ``SPI.CONTROLLER`` or ``SPI.PERIPHERAL``.
- ``baudrate`` is the SCK clock rate (only sensible for a controller).
- ``prescaler`` is the prescaler to use to derive SCK from the APB bus frequency;
use of ``prescaler`` overrides ``baudrate``.
- ``polarity`` can be 0 or 1, and is the level the idle clock line sits at.
- ``phase`` can be 0 or 1 to sample data on the first or second clock edge
respectively.
- ``bits`` can be 8 or 16, and is the number of bits in each transferred word.
- ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``.
- ``ti`` True indicates Texas Instruments, as opposed to Motorola, signal conventions.
- ``crc`` can be None for no CRC, or a polynomial specifier.
Note that the SPI clock frequency will not always be the requested baudrate.
The hardware only supports baudrates that are the APB bus frequency
(see :meth:`pyb.freq`) divided by a prescaler, which can be 2, 4, 8, 16, 32,
64, 128 or 256. SPI(1) is on AHB2, and SPI(2) is on AHB1. For precise
control over the SPI clock frequency, specify ``prescaler`` instead of
``baudrate``.
Printing the SPI object will show you the computed baudrate and the chosen
prescaler.
"""
@overload
def init(
self,
mode: int = CONTROLLER,
*,
prescaler: int = 256,
polarity: int = 1,
phase: int = 0,
bits: int = 8,
firstbit: int = MSB,
ti: bool = False,
crc: int | None = None,
):
"""
Initialise the SPI bus with the given parameters:
- ``mode`` must be either ``SPI.CONTROLLER`` or ``SPI.PERIPHERAL``.
- ``baudrate`` is the SCK clock rate (only sensible for a controller).
- ``prescaler`` is the prescaler to use to derive SCK from the APB bus frequency;
use of ``prescaler`` overrides ``baudrate``.
- ``polarity`` can be 0 or 1, and is the level the idle clock line sits at.
- ``phase`` can be 0 or 1 to sample data on the first or second clock edge
respectively.
- ``bits`` can be 8 or 16, and is the number of bits in each transferred word.
- ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``.
- ``ti`` True indicates Texas Instruments, as opposed to Motorola, signal conventions.
- ``crc`` can be None for no CRC, or a polynomial specifier.
Note that the SPI clock frequency will not always be the requested baudrate.
The hardware only supports baudrates that are the APB bus frequency
(see :meth:`pyb.freq`) divided by a prescaler, which can be 2, 4, 8, 16, 32,
64, 128 or 256. SPI(1) is on AHB2, and SPI(2) is on AHB1. For precise
control over the SPI clock frequency, specify ``prescaler`` instead of
``baudrate``.
Printing the SPI object will show you the computed baudrate and the chosen
prescaler.
"""
def recv(
self, recv: int | AnyWritableBuf, /, *, timeout: int = 5000
) -> AnyWritableBuf:
"""
Receive data on the bus:
- ``recv`` can be an integer, which is the number of bytes to receive,
or a mutable buffer, which will be filled with received bytes.
- ``timeout`` is the timeout in milliseconds to wait for the receive.
Return value: if ``recv`` is an integer then a new buffer of the bytes received,
otherwise the same buffer that was passed in to ``recv``.
"""
def send(
self, send: int | AnyWritableBuf | bytes, /, *, timeout: int = 5000
) -> None:
"""
Send data on the bus:
- ``send`` is the data to send (an integer to send, or a buffer object).
- ``timeout`` is the timeout in milliseconds to wait for the send.
Return value: ``None``.
"""
def send_recv(
self,
send: int | bytearray | array | bytes,
recv: AnyWritableBuf | None = None,
/,
*,
timeout: int = 5000,
) -> AnyWritableBuf:
"""
Send and receive data on the bus at the same time:
- ``send`` is the data to send (an integer to send, or a buffer object).
- ``recv`` is a mutable buffer which will be filled with received bytes.
It can be the same as ``send``, or omitted. If omitted, a new buffer will
be created.
- ``timeout`` is the timeout in milliseconds to wait for the receive.
Return value: the buffer with the received bytes.
"""
class Switch:
"""
A Switch object is used to control a push-button switch.
Usage::
sw = pyb.Switch() # create a switch object
sw.value() # get state (True if pressed, False otherwise)
sw() # shorthand notation to get the switch state
sw.callback(f) # register a callback to be called when the
# switch is pressed down
sw.callback(None) # remove the callback
Example::
pyb.Switch().callback(lambda: pyb.LED(1).toggle())
"""
def __init__(self):
"""
Create and return a switch object.
"""
def __call__(self) -> bool:
"""
Call switch object directly to get its state: ``True`` if pressed down,
``False`` otherwise.
"""
def value(self) -> bool:
"""
Get the switch state. Returns ``True`` if pressed down, otherwise ``False``.
"""
def callback(self, fun: Callable[[], None] | None) -> None:
"""
Register the given function to be called when the switch is pressed down.
If ``fun`` is ``None``, then it disables the callback.
"""
# noinspection PyShadowingNames,PyUnresolvedReferences
class Timer:
"""
Timers can be used for a great variety of tasks. At the moment, only
the simplest case is implemented: that of calling a function periodically.
Each timer consists of a counter that counts up at a certain rate. The rate
at which it counts is the peripheral clock frequency (in Hz) divided by the
timer prescaler. When the counter reaches the timer period it triggers an
event, and the counter resets back to zero. By using the callback method,
the timer event can call a Python function.
Example usage to toggle an LED at a fixed frequency::
tim = pyb.Timer(4) # create a timer object using timer 4
tim.init(freq=2) # trigger at 2Hz
tim.callback(lambda t:pyb.LED(1).toggle())
Example using named function for the callback::
def tick(timer): # we will receive the timer object when being called
print(timer.counter()) # show current timer's counter value
tim = pyb.Timer(4, freq=1) # create a timer object using timer 4 - trigger at 1Hz
tim.callback(tick) # set the callback to our tick function
Further examples::
tim = pyb.Timer(4, freq=100) # freq in Hz
tim = pyb.Timer(4, prescaler=0, period=99)
tim.counter() # get counter (can also set)
tim.prescaler(2) # set prescaler (can also get)
tim.period(199) # set period (can also get)
tim.callback(lambda t: ...) # set callback for update interrupt (t=tim instance)
tim.callback(None) # clear callback
*Note:* Timer(2) and Timer(3) are used for PWM to set the intensity of LED(3)
and LED(4) respectively. But these timers are only configured for PWM if
the intensity of the relevant LED is set to a value between 1 and 254. If
the intensity feature of the LEDs is not used then these timers are free for
general purpose use. Similarly, Timer(5) controls the servo driver, and
Timer(6) is used for timed ADC/DAC reading/writing. It is recommended to
use the other timers in your programs.
*Note:* Memory can't be allocated during a callback (an interrupt) and so
exceptions raised within a callback don't give much information. See
:func:`micropython.alloc_emergency_exception_buf` for how to get around this
limitation.
"""
UP: ClassVar[int] = ...
"""
configures the timer to count from 0 to ARR (default).
"""
DOWN: ClassVar[int] = ...
"""
configures the timer to count from ARR down to 0.
"""
CENTER: ClassVar[int] = ...
"""
configures the timer to count from 0 to ARR and then back down to 0.
"""
PWM: ClassVar[int] = ...
"""
configure the timer in PWM mode (active high).
"""
PWM_INVERTED: ClassVar[int] = ...
"""
configure the timer in PWM mode (active low).
"""
OC_TIMING: ClassVar[int] = ...
"""
indicates that no pin is driven.
"""
OC_ACTIVE: ClassVar[int] = ...
"""
the pin will be made active when a compare match occurs (active is determined by polarity).
"""
OC_INACTIVE: ClassVar[int] = ...
"""
the pin will be made inactive when a compare match occurs.
"""
OC_TOGGLE: ClassVar[int] = ...
"""
the pin will be toggled when an compare match occurs.
"""
OC_FORCED_ACTIVE: ClassVar[int] = ...
"""
the pin is forced active (compare match is ignored).
"""
OC_FORCED_INACTIVE: ClassVar[int] = ...
"""
the pin is forced inactive (compare match is ignored).
"""
IC: ClassVar[int] = ...
"""
configure the timer in Input Capture mode.
"""
ENC_A: ClassVar[int] = ...
"""
configure the timer in Encoder mode. The counter only changes when CH1 changes.
"""
ENC_B: ClassVar[int] = ...
"""
configure the timer in Encoder mode. The counter only changes when CH2 changes.
"""
ENC_AB: ClassVar[int] = ...
"""
configure the timer in Encoder mode. The counter changes when CH1 or CH2 changes.
"""
HIGH: ClassVar[int] = ...
"""
output is active high.
"""
LOW: ClassVar[int] = ...
"""
output is active low.
"""
RISING: ClassVar[int] = ...
"""
captures on rising edge.
"""
FALLING: ClassVar[int] = ...
"""
captures on falling edge.
"""
BOTH: ClassVar[int] = ...
"""
captures on both edges.
"""
@overload
def __init__(self, id: int, /):
"""
Construct a new timer object of the given id. If additional
arguments are given, then the timer is initialised by ``init(...)``.
``id`` can be 1 to 14.
"""
@overload
def __init__(
self,
id: int,
/,
*,
freq: int,
mode: int = UP,
div: int = 1,
callback: Callable[[Timer], None] | None = None,
deadtime: int = 0,
):
"""
Construct a new timer object of the given id. If additional
arguments are given, then the timer is initialised by ``init(...)``.
``id`` can be 1 to 14.
"""
@overload
def __init__(
self,
id: int,
/,
*,
prescaler: int,
period: int,
mode: int = UP,
div: int = 1,
callback: Callable[[Timer], None] | None = None,
deadtime: int = 0,
):
"""
Construct a new timer object of the given id. If additional
arguments are given, then the timer is initialised by ``init(...)``.
``id`` can be 1 to 14.
"""
@overload
def init(
self,
*,
freq: int,
mode: int = UP,
div: int = 1,
callback: Callable[[Timer], None] | None = None,
deadtime: int = 0,
) -> None:
"""
Initialise the timer. Initialisation must be either by frequency (in Hz)
or by prescaler and period::
tim.init(freq=100) # set the timer to trigger at 100Hz
tim.init(prescaler=83, period=999) # set the prescaler and period directly
Keyword arguments:
- ``freq`` --- specifies the periodic frequency of the timer. You might also
view this as the frequency with which the timer goes through one complete cycle.
- ``prescaler`` [0-0xffff] - specifies the value to be loaded into the
timer's Prescaler Register (PSC). The timer clock source is divided by
(``prescaler + 1``) to arrive at the timer clock. Timers 2-7 and 12-14
have a clock source of 84 MHz (pyb.freq()[2] \* 2), and Timers 1, and 8-11
have a clock source of 168 MHz (pyb.freq()[3] \* 2).
- ``period`` [0-0xffff] for timers 1, 3, 4, and 6-15. [0-0x3fffffff] for timers 2 & 5.
Specifies the value to be loaded into the timer's AutoReload
Register (ARR). This determines the period of the timer (i.e. when the
counter cycles). The timer counter will roll-over after ``period + 1``
timer clock cycles.
- ``mode`` can be one of:
- ``Timer.UP`` - configures the timer to count from 0 to ARR (default)
- ``Timer.DOWN`` - configures the timer to count from ARR down to 0.
- ``Timer.CENTER`` - configures the timer to count from 0 to ARR and
then back down to 0.
- ``div`` can be one of 1, 2, or 4. Divides the timer clock to determine
the sampling clock used by the digital filters.
- ``callback`` - as per Timer.callback()
- ``deadtime`` - specifies the amount of "dead" or inactive time between
transitions on complimentary channels (both channels will be inactive)
for this time). ``deadtime`` may be an integer between 0 and 1008, with
the following restrictions: 0-128 in steps of 1. 128-256 in steps of
2, 256-512 in steps of 8, and 512-1008 in steps of 16. ``deadtime``
measures ticks of ``source_freq`` divided by ``div`` clock ticks.
``deadtime`` is only available on timers 1 and 8.
You must either specify freq or both of period and prescaler.
"""
@overload
def init(
self,
*,
prescaler: int,
period: int,
mode: int = UP,
div: int = 1,
callback: Callable[[Timer], None] | None = None,
deadtime: int = 0,
) -> None:
"""
Initialise the timer. Initialisation must be either by frequency (in Hz)
or by prescaler and period::
tim.init(freq=100) # set the timer to trigger at 100Hz
tim.init(prescaler=83, period=999) # set the prescaler and period directly
Keyword arguments:
- ``freq`` --- specifies the periodic frequency of the timer. You might also
view this as the frequency with which the timer goes through one complete cycle.
- ``prescaler`` [0-0xffff] - specifies the value to be loaded into the
timer's Prescaler Register (PSC). The timer clock source is divided by
(``prescaler + 1``) to arrive at the timer clock. Timers 2-7 and 12-14
have a clock source of 84 MHz (pyb.freq()[2] \* 2), and Timers 1, and 8-11
have a clock source of 168 MHz (pyb.freq()[3] \* 2).
- ``period`` [0-0xffff] for timers 1, 3, 4, and 6-15. [0-0x3fffffff] for timers 2 & 5.
Specifies the value to be loaded into the timer's AutoReload
Register (ARR). This determines the period of the timer (i.e. when the
counter cycles). The timer counter will roll-over after ``period + 1``
timer clock cycles.
- ``mode`` can be one of:
- ``Timer.UP`` - configures the timer to count from 0 to ARR (default)
- ``Timer.DOWN`` - configures the timer to count from ARR down to 0.
- ``Timer.CENTER`` - configures the timer to count from 0 to ARR and
then back down to 0.
- ``div`` can be one of 1, 2, or 4. Divides the timer clock to determine
the sampling clock used by the digital filters.
- ``callback`` - as per Timer.callback()
- ``deadtime`` - specifies the amount of "dead" or inactive time between
transitions on complimentary channels (both channels will be inactive)
for this time). ``deadtime`` may be an integer between 0 and 1008, with
the following restrictions: 0-128 in steps of 1. 128-256 in steps of
2, 256-512 in steps of 8, and 512-1008 in steps of 16. ``deadtime``
measures ticks of ``source_freq`` divided by ``div`` clock ticks.
``deadtime`` is only available on timers 1 and 8.
You must either specify freq or both of period and prescaler.
"""
def deinit(self) -> None:
"""
Deinitialises the timer.
Disables the callback (and the associated irq).
Disables any channel callbacks (and the associated irq).
Stops the timer, and disables the timer peripheral.
"""
def callback(self, fun: Callable[[Timer], None] | None, /) -> None:
"""
Set the function to be called when the timer triggers.
``fun`` is passed 1 argument, the timer object.
If ``fun`` is ``None`` then the callback will be disabled.
"""
@overload
def channel(self, channel: int, /) -> "TimerChannel" | None:
"""
If only a channel number is passed, then a previously initialized channel
object is returned (or ``None`` if there is no previous channel).
Otherwise, a TimerChannel object is initialized and returned.
Each channel can be configured to perform pwm, output compare, or
input capture. All channels share the same underlying timer, which means
that they share the same timer clock.
Keyword arguments:
- ``mode`` can be one of:
- ``Timer.PWM`` --- configure the timer in PWM mode (active high).
- ``Timer.PWM_INVERTED`` --- configure the timer in PWM mode (active low).
- ``Timer.OC_TIMING`` --- indicates that no pin is driven.
- ``Timer.OC_ACTIVE`` --- the pin will be made active when a compare match occurs (active is determined by polarity)
- ``Timer.OC_INACTIVE`` --- the pin will be made inactive when a compare match occurs.
- ``Timer.OC_TOGGLE`` --- the pin will be toggled when an compare match occurs.
- ``Timer.OC_FORCED_ACTIVE`` --- the pin is forced active (compare match is ignored).
- ``Timer.OC_FORCED_INACTIVE`` --- the pin is forced inactive (compare match is ignored).
- ``Timer.IC`` --- configure the timer in Input Capture mode.
- ``Timer.ENC_A`` --- configure the timer in Encoder mode. The counter only changes when CH1 changes.
- ``Timer.ENC_B`` --- configure the timer in Encoder mode. The counter only changes when CH2 changes.
- ``Timer.ENC_AB`` --- configure the timer in Encoder mode. The counter changes when CH1 or CH2 changes.
- ``callback`` - as per TimerChannel.callback()
- ``pin`` None (the default) or a Pin object. If specified (and not None)
this will cause the alternate function of the the indicated pin
to be configured for this timer channel. An error will be raised if
the pin doesn't support any alternate functions for this timer channel.
Keyword arguments for Timer.PWM modes:
- ``pulse_width`` - determines the initial pulse width value to use.
- ``pulse_width_percent`` - determines the initial pulse width percentage to use.
Keyword arguments for Timer.OC modes:
- ``compare`` - determines the initial value of the compare register.
- ``polarity`` can be one of:
- ``Timer.HIGH`` - output is active high
- ``Timer.LOW`` - output is active low
Optional keyword arguments for Timer.IC modes:
- ``polarity`` can be one of:
- ``Timer.RISING`` - captures on rising edge.
- ``Timer.FALLING`` - captures on falling edge.
- ``Timer.BOTH`` - captures on both edges.
Note that capture only works on the primary channel, and not on the
complimentary channels.
Notes for Timer.ENC modes:
- Requires 2 pins, so one or both pins will need to be configured to use
the appropriate timer AF using the Pin API.
- Read the encoder value using the timer.counter() method.
- Only works on CH1 and CH2 (and not on CH1N or CH2N)
- The channel number is ignored when setting the encoder mode.
PWM Example::
timer = pyb.Timer(2, freq=1000)
ch2 = timer.channel(2, pyb.Timer.PWM, pin=pyb.Pin.board.X2, pulse_width=8000)
ch3 = timer.channel(3, pyb.Timer.PWM, pin=pyb.Pin.board.X3, pulse_width=16000)
"""
@overload
def channel(
self,
channel: int,
/,
mode: int,
*,
callback: Callable[[Timer], None] | None = None,
pin: Pin | None = None,
pulse_width: int,
) -> "TimerChannel":
"""
If only a channel number is passed, then a previously initialized channel
object is returned (or ``None`` if there is no previous channel).
Otherwise, a TimerChannel object is initialized and returned.
Each channel can be configured to perform pwm, output compare, or
input capture. All channels share the same underlying timer, which means
that they share the same timer clock.
Keyword arguments:
- ``mode`` can be one of:
- ``Timer.PWM`` --- configure the timer in PWM mode (active high).
- ``Timer.PWM_INVERTED`` --- configure the timer in PWM mode (active low).
- ``Timer.OC_TIMING`` --- indicates that no pin is driven.
- ``Timer.OC_ACTIVE`` --- the pin will be made active when a compare match occurs (active is determined by polarity)
- ``Timer.OC_INACTIVE`` --- the pin will be made inactive when a compare match occurs.
- ``Timer.OC_TOGGLE`` --- the pin will be toggled when an compare match occurs.
- ``Timer.OC_FORCED_ACTIVE`` --- the pin is forced active (compare match is ignored).
- ``Timer.OC_FORCED_INACTIVE`` --- the pin is forced inactive (compare match is ignored).
- ``Timer.IC`` --- configure the timer in Input Capture mode.
- ``Timer.ENC_A`` --- configure the timer in Encoder mode. The counter only changes when CH1 changes.
- ``Timer.ENC_B`` --- configure the timer in Encoder mode. The counter only changes when CH2 changes.
- ``Timer.ENC_AB`` --- configure the timer in Encoder mode. The counter changes when CH1 or CH2 changes.
- ``callback`` - as per TimerChannel.callback()
- ``pin`` None (the default) or a Pin object. If specified (and not None)
this will cause the alternate function of the the indicated pin
to be configured for this timer channel. An error will be raised if
the pin doesn't support any alternate functions for this timer channel.
Keyword arguments for Timer.PWM modes:
- ``pulse_width`` - determines the initial pulse width value to use.
- ``pulse_width_percent`` - determines the initial pulse width percentage to use.
Keyword arguments for Timer.OC modes:
- ``compare`` - determines the initial value of the compare register.
- ``polarity`` can be one of:
- ``Timer.HIGH`` - output is active high
- ``Timer.LOW`` - output is active low
Optional keyword arguments for Timer.IC modes:
- ``polarity`` can be one of:
- ``Timer.RISING`` - captures on rising edge.
- ``Timer.FALLING`` - captures on falling edge.
- ``Timer.BOTH`` - captures on both edges.
Note that capture only works on the primary channel, and not on the
complimentary channels.
Notes for Timer.ENC modes:
- Requires 2 pins, so one or both pins will need to be configured to use
the appropriate timer AF using the Pin API.
- Read the encoder value using the timer.counter() method.
- Only works on CH1 and CH2 (and not on CH1N or CH2N)
- The channel number is ignored when setting the encoder mode.
PWM Example::
timer = pyb.Timer(2, freq=1000)
ch2 = timer.channel(2, pyb.Timer.PWM, pin=pyb.Pin.board.X2, pulse_width=8000)
ch3 = timer.channel(3, pyb.Timer.PWM, pin=pyb.Pin.board.X3, pulse_width=16000)
"""
@overload
def channel(
self,
channel: int,
/,
mode: int,
*,
callback: Callable[[Timer], None] | None = None,
pin: Pin | None = None,
pulse_width_percent: int | float,
) -> "TimerChannel":
"""
If only a channel number is passed, then a previously initialized channel
object is returned (or ``None`` if there is no previous channel).
Otherwise, a TimerChannel object is initialized and returned.
Each channel can be configured to perform pwm, output compare, or
input capture. All channels share the same underlying timer, which means
that they share the same timer clock.
Keyword arguments:
- ``mode`` can be one of:
- ``Timer.PWM`` --- configure the timer in PWM mode (active high).
- ``Timer.PWM_INVERTED`` --- configure the timer in PWM mode (active low).
- ``Timer.OC_TIMING`` --- indicates that no pin is driven.
- ``Timer.OC_ACTIVE`` --- the pin will be made active when a compare match occurs (active is determined by polarity)
- ``Timer.OC_INACTIVE`` --- the pin will be made inactive when a compare match occurs.
- ``Timer.OC_TOGGLE`` --- the pin will be toggled when an compare match occurs.
- ``Timer.OC_FORCED_ACTIVE`` --- the pin is forced active (compare match is ignored).
- ``Timer.OC_FORCED_INACTIVE`` --- the pin is forced inactive (compare match is ignored).
- ``Timer.IC`` --- configure the timer in Input Capture mode.
- ``Timer.ENC_A`` --- configure the timer in Encoder mode. The counter only changes when CH1 changes.
- ``Timer.ENC_B`` --- configure the timer in Encoder mode. The counter only changes when CH2 changes.
- ``Timer.ENC_AB`` --- configure the timer in Encoder mode. The counter changes when CH1 or CH2 changes.
- ``callback`` - as per TimerChannel.callback()
- ``pin`` None (the default) or a Pin object. If specified (and not None)
this will cause the alternate function of the the indicated pin
to be configured for this timer channel. An error will be raised if
the pin doesn't support any alternate functions for this timer channel.
Keyword arguments for Timer.PWM modes:
- ``pulse_width`` - determines the initial pulse width value to use.
- ``pulse_width_percent`` - determines the initial pulse width percentage to use.
Keyword arguments for Timer.OC modes:
- ``compare`` - determines the initial value of the compare register.
- ``polarity`` can be one of:
- ``Timer.HIGH`` - output is active high
- ``Timer.LOW`` - output is active low
Optional keyword arguments for Timer.IC modes:
- ``polarity`` can be one of:
- ``Timer.RISING`` - captures on rising edge.
- ``Timer.FALLING`` - captures on falling edge.
- ``Timer.BOTH`` - captures on both edges.
Note that capture only works on the primary channel, and not on the
complimentary channels.
Notes for Timer.ENC modes:
- Requires 2 pins, so one or both pins will need to be configured to use
the appropriate timer AF using the Pin API.
- Read the encoder value using the timer.counter() method.
- Only works on CH1 and CH2 (and not on CH1N or CH2N)
- The channel number is ignored when setting the encoder mode.
PWM Example::
timer = pyb.Timer(2, freq=1000)
ch2 = timer.channel(2, pyb.Timer.PWM, pin=pyb.Pin.board.X2, pulse_width=8000)
ch3 = timer.channel(3, pyb.Timer.PWM, pin=pyb.Pin.board.X3, pulse_width=16000)
"""
@overload
def channel(
self,
channel: int,
/,
mode: int,
*,
callback: Callable[[Timer], None] | None = None,
pin: Pin | None = None,
compare: int,
polarity: int,
) -> "TimerChannel":
"""
If only a channel number is passed, then a previously initialized channel
object is returned (or ``None`` if there is no previous channel).
Otherwise, a TimerChannel object is initialized and returned.
Each channel can be configured to perform pwm, output compare, or
input capture. All channels share the same underlying timer, which means
that they share the same timer clock.
Keyword arguments:
- ``mode`` can be one of:
- ``Timer.PWM`` --- configure the timer in PWM mode (active high).
- ``Timer.PWM_INVERTED`` --- configure the timer in PWM mode (active low).
- ``Timer.OC_TIMING`` --- indicates that no pin is driven.
- ``Timer.OC_ACTIVE`` --- the pin will be made active when a compare match occurs (active is determined by polarity)
- ``Timer.OC_INACTIVE`` --- the pin will be made inactive when a compare match occurs.
- ``Timer.OC_TOGGLE`` --- the pin will be toggled when an compare match occurs.
- ``Timer.OC_FORCED_ACTIVE`` --- the pin is forced active (compare match is ignored).
- ``Timer.OC_FORCED_INACTIVE`` --- the pin is forced inactive (compare match is ignored).
- ``Timer.IC`` --- configure the timer in Input Capture mode.
- ``Timer.ENC_A`` --- configure the timer in Encoder mode. The counter only changes when CH1 changes.
- ``Timer.ENC_B`` --- configure the timer in Encoder mode. The counter only changes when CH2 changes.
- ``Timer.ENC_AB`` --- configure the timer in Encoder mode. The counter changes when CH1 or CH2 changes.
- ``callback`` - as per TimerChannel.callback()
- ``pin`` None (the default) or a Pin object. If specified (and not None)
this will cause the alternate function of the the indicated pin
to be configured for this timer channel. An error will be raised if
the pin doesn't support any alternate functions for this timer channel.
Keyword arguments for Timer.PWM modes:
- ``pulse_width`` - determines the initial pulse width value to use.
- ``pulse_width_percent`` - determines the initial pulse width percentage to use.
Keyword arguments for Timer.OC modes:
- ``compare`` - determines the initial value of the compare register.
- ``polarity`` can be one of:
- ``Timer.HIGH`` - output is active high
- ``Timer.LOW`` - output is active low
Optional keyword arguments for Timer.IC modes:
- ``polarity`` can be one of:
- ``Timer.RISING`` - captures on rising edge.
- ``Timer.FALLING`` - captures on falling edge.
- ``Timer.BOTH`` - captures on both edges.
Note that capture only works on the primary channel, and not on the
complimentary channels.
Notes for Timer.ENC modes:
- Requires 2 pins, so one or both pins will need to be configured to use
the appropriate timer AF using the Pin API.
- Read the encoder value using the timer.counter() method.
- Only works on CH1 and CH2 (and not on CH1N or CH2N)
- The channel number is ignored when setting the encoder mode.
PWM Example::
timer = pyb.Timer(2, freq=1000)
ch2 = timer.channel(2, pyb.Timer.PWM, pin=pyb.Pin.board.X2, pulse_width=8000)
ch3 = timer.channel(3, pyb.Timer.PWM, pin=pyb.Pin.board.X3, pulse_width=16000)
"""
@overload
def channel(
self,
channel: int,
/,
mode: int,
*,
callback: Callable[[Timer], None] | None = None,
pin: Pin | None = None,
polarity: int,
) -> "TimerChannel":
"""
If only a channel number is passed, then a previously initialized channel
object is returned (or ``None`` if there is no previous channel).
Otherwise, a TimerChannel object is initialized and returned.
Each channel can be configured to perform pwm, output compare, or
input capture. All channels share the same underlying timer, which means
that they share the same timer clock.
Keyword arguments:
- ``mode`` can be one of:
- ``Timer.PWM`` --- configure the timer in PWM mode (active high).
- ``Timer.PWM_INVERTED`` --- configure the timer in PWM mode (active low).
- ``Timer.OC_TIMING`` --- indicates that no pin is driven.
- ``Timer.OC_ACTIVE`` --- the pin will be made active when a compare match occurs (active is determined by polarity)
- ``Timer.OC_INACTIVE`` --- the pin will be made inactive when a compare match occurs.
- ``Timer.OC_TOGGLE`` --- the pin will be toggled when an compare match occurs.
- ``Timer.OC_FORCED_ACTIVE`` --- the pin is forced active (compare match is ignored).
- ``Timer.OC_FORCED_INACTIVE`` --- the pin is forced inactive (compare match is ignored).
- ``Timer.IC`` --- configure the timer in Input Capture mode.
- ``Timer.ENC_A`` --- configure the timer in Encoder mode. The counter only changes when CH1 changes.
- ``Timer.ENC_B`` --- configure the timer in Encoder mode. The counter only changes when CH2 changes.
- ``Timer.ENC_AB`` --- configure the timer in Encoder mode. The counter changes when CH1 or CH2 changes.
- ``callback`` - as per TimerChannel.callback()
- ``pin`` None (the default) or a Pin object. If specified (and not None)
this will cause the alternate function of the the indicated pin
to be configured for this timer channel. An error will be raised if
the pin doesn't support any alternate functions for this timer channel.
Keyword arguments for Timer.PWM modes:
- ``pulse_width`` - determines the initial pulse width value to use.
- ``pulse_width_percent`` - determines the initial pulse width percentage to use.
Keyword arguments for Timer.OC modes:
- ``compare`` - determines the initial value of the compare register.
- ``polarity`` can be one of:
- ``Timer.HIGH`` - output is active high
- ``Timer.LOW`` - output is active low
Optional keyword arguments for Timer.IC modes:
- ``polarity`` can be one of:
- ``Timer.RISING`` - captures on rising edge.
- ``Timer.FALLING`` - captures on falling edge.
- ``Timer.BOTH`` - captures on both edges.
Note that capture only works on the primary channel, and not on the
complimentary channels.
Notes for Timer.ENC modes:
- Requires 2 pins, so one or both pins will need to be configured to use
the appropriate timer AF using the Pin API.
- Read the encoder value using the timer.counter() method.
- Only works on CH1 and CH2 (and not on CH1N or CH2N)
- The channel number is ignored when setting the encoder mode.
PWM Example::
timer = pyb.Timer(2, freq=1000)
ch2 = timer.channel(2, pyb.Timer.PWM, pin=pyb.Pin.board.X2, pulse_width=8000)
ch3 = timer.channel(3, pyb.Timer.PWM, pin=pyb.Pin.board.X3, pulse_width=16000)
"""
@overload
def channel(
self,
channel: int,
/,
mode: int,
*,
callback: Callable[[Timer], None] | None = None,
pin: Pin | None = None,
) -> "TimerChannel":
"""
If only a channel number is passed, then a previously initialized channel
object is returned (or ``None`` if there is no previous channel).
Otherwise, a TimerChannel object is initialized and returned.
Each channel can be configured to perform pwm, output compare, or
input capture. All channels share the same underlying timer, which means
that they share the same timer clock.
Keyword arguments:
- ``mode`` can be one of:
- ``Timer.PWM`` --- configure the timer in PWM mode (active high).
- ``Timer.PWM_INVERTED`` --- configure the timer in PWM mode (active low).
- ``Timer.OC_TIMING`` --- indicates that no pin is driven.
- ``Timer.OC_ACTIVE`` --- the pin will be made active when a compare match occurs (active is determined by polarity)
- ``Timer.OC_INACTIVE`` --- the pin will be made inactive when a compare match occurs.
- ``Timer.OC_TOGGLE`` --- the pin will be toggled when an compare match occurs.
- ``Timer.OC_FORCED_ACTIVE`` --- the pin is forced active (compare match is ignored).
- ``Timer.OC_FORCED_INACTIVE`` --- the pin is forced inactive (compare match is ignored).
- ``Timer.IC`` --- configure the timer in Input Capture mode.
- ``Timer.ENC_A`` --- configure the timer in Encoder mode. The counter only changes when CH1 changes.
- ``Timer.ENC_B`` --- configure the timer in Encoder mode. The counter only changes when CH2 changes.
- ``Timer.ENC_AB`` --- configure the timer in Encoder mode. The counter changes when CH1 or CH2 changes.
- ``callback`` - as per TimerChannel.callback()
- ``pin`` None (the default) or a Pin object. If specified (and not None)
this will cause the alternate function of the the indicated pin
to be configured for this timer channel. An error will be raised if
the pin doesn't support any alternate functions for this timer channel.
Keyword arguments for Timer.PWM modes:
- ``pulse_width`` - determines the initial pulse width value to use.
- ``pulse_width_percent`` - determines the initial pulse width percentage to use.
Keyword arguments for Timer.OC modes:
- ``compare`` - determines the initial value of the compare register.
- ``polarity`` can be one of:
- ``Timer.HIGH`` - output is active high
- ``Timer.LOW`` - output is active low
Optional keyword arguments for Timer.IC modes:
- ``polarity`` can be one of:
- ``Timer.RISING`` - captures on rising edge.
- ``Timer.FALLING`` - captures on falling edge.
- ``Timer.BOTH`` - captures on both edges.
Note that capture only works on the primary channel, and not on the
complimentary channels.
Notes for Timer.ENC modes:
- Requires 2 pins, so one or both pins will need to be configured to use
the appropriate timer AF using the Pin API.
- Read the encoder value using the timer.counter() method.
- Only works on CH1 and CH2 (and not on CH1N or CH2N)
- The channel number is ignored when setting the encoder mode.
PWM Example::
timer = pyb.Timer(2, freq=1000)
ch2 = timer.channel(2, pyb.Timer.PWM, pin=pyb.Pin.board.X2, pulse_width=8000)
ch3 = timer.channel(3, pyb.Timer.PWM, pin=pyb.Pin.board.X3, pulse_width=16000)
"""
@overload
def counter(self) -> int:
"""
Get or set the timer counter.
"""
@overload
def counter(self, value: int, /) -> None:
"""
Get or set the timer counter.
"""
@overload
def freq(self) -> int:
"""
Get or set the frequency for the timer (changes prescaler and period if set).
"""
@overload
def freq(self, value: int, /) -> None:
"""
Get or set the frequency for the timer (changes prescaler and period if set).
"""
@overload
def period(self) -> int:
"""
Get or set the period of the timer.
"""
@overload
def period(self, value: int, /) -> None:
"""
Get or set the period of the timer.
"""
@overload
def prescaler(self) -> int:
"""
Get or set the prescaler for the timer.
"""
@overload
def prescaler(self, value: int, /) -> None:
"""
Get or set the prescaler for the timer.
"""
def source_freq(self) -> int:
"""
Get the frequency of the source of the timer.
"""
class TimerChannel(ABC):
"""
Timer channels are used to generate/capture a signal using a timer.
TimerChannel objects are created using the Timer.channel() method.
"""
@abstractmethod
def callback(self, fun: Callable[[Timer], None] | None, /) -> None:
"""
Set the function to be called when the timer channel triggers.
``fun`` is passed 1 argument, the timer object.
If ``fun`` is ``None`` then the callback will be disabled.
"""
@overload
@abstractmethod
def capture(self) -> int:
"""
Get or set the capture value associated with a channel.
capture, compare, and pulse_width are all aliases for the same function.
capture is the logical name to use when the channel is in input capture mode.
"""
@overload
@abstractmethod
def capture(self, value: int, /) -> None:
"""
Get or set the capture value associated with a channel.
capture, compare, and pulse_width are all aliases for the same function.
capture is the logical name to use when the channel is in input capture mode.
"""
@overload
@abstractmethod
def compare(self) -> int:
"""
Get or set the compare value associated with a channel.
capture, compare, and pulse_width are all aliases for the same function.
compare is the logical name to use when the channel is in output compare mode.
"""
@overload
@abstractmethod
def compare(self, value: int, /) -> None:
"""
Get or set the compare value associated with a channel.
capture, compare, and pulse_width are all aliases for the same function.
compare is the logical name to use when the channel is in output compare mode.
"""
@overload
@abstractmethod
def pulse_width(self) -> int:
"""
Get or set the pulse width value associated with a channel.
capture, compare, and pulse_width are all aliases for the same function.
pulse_width is the logical name to use when the channel is in PWM mode.
In edge aligned mode, a pulse_width of ``period + 1`` corresponds to a duty cycle of 100%
In center aligned mode, a pulse width of ``period`` corresponds to a duty cycle of 100%
"""
@overload
@abstractmethod
def pulse_width(self, value: int, /) -> None:
"""
Get or set the pulse width value associated with a channel.
capture, compare, and pulse_width are all aliases for the same function.
pulse_width is the logical name to use when the channel is in PWM mode.
In edge aligned mode, a pulse_width of ``period + 1`` corresponds to a duty cycle of 100%
In center aligned mode, a pulse width of ``period`` corresponds to a duty cycle of 100%
"""
@overload
@abstractmethod
def pulse_width_percent(self) -> float:
"""
Get or set the pulse width percentage associated with a channel. The value
is a number between 0 and 100 and sets the percentage of the timer period
for which the pulse is active. The value can be an integer or
floating-point number for more accuracy. For example, a value of 25 gives
a duty cycle of 25%.
"""
@overload
@abstractmethod
def pulse_width_percent(self, value: int | float, /) -> None:
"""
Get or set the pulse width percentage associated with a channel. The value
is a number between 0 and 100 and sets the percentage of the timer period
for which the pulse is active. The value can be an integer or
floating-point number for more accuracy. For example, a value of 25 gives
a duty cycle of 25%.
"""
# noinspection PyShadowingNames
class UART:
"""
UART implements the standard UART/USART duplex serial communications protocol. At
the physical level it consists of 2 lines: RX and TX. The unit of communication
is a character (not to be confused with a string character) which can be 8 or 9
bits wide.
UART objects can be created and initialised using::
from pyb import UART
uart = UART(1, 9600) # init with given baudrate
uart.init(9600, bits=8, parity=None, stop=1) # init with given parameters
Bits can be 7, 8 or 9. Parity can be None, 0 (even) or 1 (odd). Stop can be 1 or 2.
*Note:* with parity=None, only 8 and 9 bits are supported. With parity enabled,
only 7 and 8 bits are supported.
A UART object acts like a `stream` object and reading and writing is done
using the standard stream methods::
uart.read(10) # read 10 characters, returns a bytes object
uart.read() # read all available characters
uart.readline() # read a line
uart.readinto(buf) # read and store into the given buffer
uart.write('abc') # write the 3 characters
Individual characters can be read/written using::
uart.readchar() # read 1 character and returns it as an integer
uart.writechar(42) # write 1 character
To check if there is anything to be read, use::
uart.any() # returns the number of characters waiting
*Note:* The stream functions ``read``, ``write``, etc. are new in MicroPython v1.3.4.
Earlier versions use ``uart.send`` and ``uart.recv``.
"""
RTS: ClassVar[int] = ...
"""
to select the flow control type.
"""
CTS: ClassVar[int] = ...
"""
to select the flow control type.
"""
@overload
def __init__(self, bus: int | str, /):
"""
Construct a UART object on the given bus.
For Pyboard ``bus`` can be 1-4, 6, 'XA', 'XB', 'YA', or 'YB'.
For Pyboard Lite ``bus`` can be 1, 2, 6, 'XB', or 'YA'.
For Pyboard D ``bus`` can be 1-4, 'XA', 'YA' or 'YB'.
With no additional parameters, the UART object is created but not
initialised (it has the settings from the last initialisation of
the bus, if any). If extra arguments are given, the bus is initialised.
See ``init`` for parameters of initialisation.
The physical pins of the UART buses on Pyboard are:
- ``UART(4)`` is on ``XA``: ``(TX, RX) = (X1, X2) = (PA0, PA1)``
- ``UART(1)`` is on ``XB``: ``(TX, RX) = (X9, X10) = (PB6, PB7)``
- ``UART(6)`` is on ``YA``: ``(TX, RX) = (Y1, Y2) = (PC6, PC7)``
- ``UART(3)`` is on ``YB``: ``(TX, RX) = (Y9, Y10) = (PB10, PB11)``
- ``UART(2)`` is on: ``(TX, RX) = (X3, X4) = (PA2, PA3)``
The Pyboard Lite supports UART(1), UART(2) and UART(6) only, pins are:
- ``UART(1)`` is on ``XB``: ``(TX, RX) = (X9, X10) = (PB6, PB7)``
- ``UART(6)`` is on ``YA``: ``(TX, RX) = (Y1, Y2) = (PC6, PC7)``
- ``UART(2)`` is on: ``(TX, RX) = (X1, X2) = (PA2, PA3)``
The Pyboard D supports UART(1), UART(2), UART(3) and UART(4) only, pins are:
- ``UART(4)`` is on ``XA``: ``(TX, RX) = (X1, X2) = (PA0, PA1)``
- ``UART(1)`` is on ``YA``: ``(TX, RX) = (Y1, Y2) = (PA9, PA10)``
- ``UART(3)`` is on ``YB``: ``(TX, RX) = (Y9, Y10) = (PB10, PB11)``
- ``UART(2)`` is on: ``(TX, RX) = (X3, X4) = (PA2, PA3)``
*Note:* Pyboard D has ``UART(1)`` on ``YA``, unlike Pyboard and Pyboard Lite that both
have ``UART(1)`` on ``XB`` and ``UART(6)`` on ``YA``.
"""
@overload
def __init__(
self,
bus: int | str,
baudrate: int,
/,
bits: int = 8,
parity: int | None = None,
stop: int = 1,
*,
timeout: int = 0,
flow: int = 0,
timeout_char: int = 0,
read_buf_len: int = 64,
):
"""
Construct a UART object on the given bus.
For Pyboard ``bus`` can be 1-4, 6, 'XA', 'XB', 'YA', or 'YB'.
For Pyboard Lite ``bus`` can be 1, 2, 6, 'XB', or 'YA'.
For Pyboard D ``bus`` can be 1-4, 'XA', 'YA' or 'YB'.
With no additional parameters, the UART object is created but not
initialised (it has the settings from the last initialisation of
the bus, if any). If extra arguments are given, the bus is initialised.
See ``init`` for parameters of initialisation.
The physical pins of the UART buses on Pyboard are:
- ``UART(4)`` is on ``XA``: ``(TX, RX) = (X1, X2) = (PA0, PA1)``
- ``UART(1)`` is on ``XB``: ``(TX, RX) = (X9, X10) = (PB6, PB7)``
- ``UART(6)`` is on ``YA``: ``(TX, RX) = (Y1, Y2) = (PC6, PC7)``
- ``UART(3)`` is on ``YB``: ``(TX, RX) = (Y9, Y10) = (PB10, PB11)``
- ``UART(2)`` is on: ``(TX, RX) = (X3, X4) = (PA2, PA3)``
The Pyboard Lite supports UART(1), UART(2) and UART(6) only, pins are:
- ``UART(1)`` is on ``XB``: ``(TX, RX) = (X9, X10) = (PB6, PB7)``
- ``UART(6)`` is on ``YA``: ``(TX, RX) = (Y1, Y2) = (PC6, PC7)``
- ``UART(2)`` is on: ``(TX, RX) = (X1, X2) = (PA2, PA3)``
The Pyboard D supports UART(1), UART(2), UART(3) and UART(4) only, pins are:
- ``UART(4)`` is on ``XA``: ``(TX, RX) = (X1, X2) = (PA0, PA1)``
- ``UART(1)`` is on ``YA``: ``(TX, RX) = (Y1, Y2) = (PA9, PA10)``
- ``UART(3)`` is on ``YB``: ``(TX, RX) = (Y9, Y10) = (PB10, PB11)``
- ``UART(2)`` is on: ``(TX, RX) = (X3, X4) = (PA2, PA3)``
*Note:* Pyboard D has ``UART(1)`` on ``YA``, unlike Pyboard and Pyboard Lite that both
have ``UART(1)`` on ``XB`` and ``UART(6)`` on ``YA``.
"""
def init(
self,
baudrate: int,
/,
bits: int = 8,
parity: int | None = None,
stop: int = 1,
*,
timeout: int = 0,
flow: int = 0,
timeout_char: int = 0,
read_buf_len: int = 64,
):
"""
Initialise the UART bus with the given parameters:
- ``baudrate`` is the clock rate.
- ``bits`` is the number of bits per character, 7, 8 or 9.
- ``parity`` is the parity, ``None``, 0 (even) or 1 (odd).
- ``stop`` is the number of stop bits, 1 or 2.
- ``flow`` sets the flow control type. Can be 0, ``UART.RTS``, ``UART.CTS``
or ``UART.RTS | UART.CTS``.
- ``timeout`` is the timeout in milliseconds to wait for writing/reading the first character.
- ``timeout_char`` is the timeout in milliseconds to wait between characters while writing or reading.
- ``read_buf_len`` is the character length of the read buffer (0 to disable).
This method will raise an exception if the baudrate could not be set within
5% of the desired value. The minimum baudrate is dictated by the frequency
of the bus that the UART is on; UART(1) and UART(6) are APB2, the rest are on
APB1. The default bus frequencies give a minimum baudrate of 1300 for
UART(1) and UART(6) and 650 for the others. Use :func:`pyb.freq `
to reduce the bus frequencies to get lower baudrates.
*Note:* with parity=None, only 8 and 9 bits are supported. With parity enabled,
only 7 and 8 bits are supported.
"""
def deinit(self) -> None:
"""
Turn off the UART bus.
"""
def any(self) -> int:
"""
Returns the number of bytes waiting (may be 0).
"""
@overload
def read(self) -> bytes | None:
"""
Read characters. If ``nbytes`` is specified then read at most that many bytes.
If ``nbytes`` are available in the buffer, returns immediately, otherwise returns
when sufficient characters arrive or the timeout elapses.
If ``nbytes`` is not given then the method reads as much data as possible. It
returns after the timeout has elapsed.
*Note:* for 9 bit characters each character takes two bytes, ``nbytes`` must
be even, and the number of characters is ``nbytes/2``.
Return value: a bytes object containing the bytes read in. Returns ``None``
on timeout.
"""
@overload
def read(self, nbytes: int, /) -> bytes | None:
"""
Read characters. If ``nbytes`` is specified then read at most that many bytes.
If ``nbytes`` are available in the buffer, returns immediately, otherwise returns
when sufficient characters arrive or the timeout elapses.
If ``nbytes`` is not given then the method reads as much data as possible. It
returns after the timeout has elapsed.
*Note:* for 9 bit characters each character takes two bytes, ``nbytes`` must
be even, and the number of characters is ``nbytes/2``.
Return value: a bytes object containing the bytes read in. Returns ``None``
on timeout.
"""
def readchar(self) -> int:
"""
Receive a single character on the bus.
Return value: The character read, as an integer. Returns -1 on timeout.
"""
@overload
def readinto(self, buf: AnyWritableBuf, /) -> int | None:
"""
Read bytes into the ``buf``. If ``nbytes`` is specified then read at most
that many bytes. Otherwise, read at most ``len(buf)`` bytes.
Return value: number of bytes read and stored into ``buf`` or ``None`` on
timeout.
"""
@overload
def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None:
"""
Read bytes into the ``buf``. If ``nbytes`` is specified then read at most
that many bytes. Otherwise, read at most ``len(buf)`` bytes.
Return value: number of bytes read and stored into ``buf`` or ``None`` on
timeout.
"""
def readline(self) -> str | None:
"""
Read a line, ending in a newline character. If such a line exists, return is
immediate. If the timeout elapses, all available data is returned regardless
of whether a newline exists.
Return value: the line read or ``None`` on timeout if no data is available.
"""
def write(self, buf: AnyWritableBuf, /) -> int | None:
"""
Write the buffer of bytes to the bus. If characters are 7 or 8 bits wide
then each byte is one character. If characters are 9 bits wide then two
bytes are used for each character (little endian), and ``buf`` must contain
an even number of bytes.
Return value: number of bytes written. If a timeout occurs and no bytes
were written returns ``None``.
"""
def writechar(self, char: int, /) -> None:
"""
Write a single character on the bus. ``char`` is an integer to write.
Return value: ``None``. See note below if CTS flow control is used.
"""
def sendbreak(self) -> None:
"""
Send a break condition on the bus. This drives the bus low for a duration
of 13 bits.
Return value: ``None``.
"""
# noinspection PyPep8Naming
class USB_HID:
"""
The USB_HID class allows creation of an object representing the USB
Human Interface Device (HID) interface. It can be used to emulate
a peripheral such as a mouse or keyboard.
Before you can use this class, you need to use :meth:`pyb.usb_mode()` to set the USB mode to include the HID interface.
"""
def __init__(self):
"""
Create a new USB_HID object.
"""
@overload
def recv(self, data: int, /, *, timeout: int = 5000) -> bytes:
"""
Receive data on the bus:
- ``data`` can be an integer, which is the number of bytes to receive,
or a mutable buffer, which will be filled with received bytes.
- ``timeout`` is the timeout in milliseconds to wait for the receive.
Return value: if ``data`` is an integer then a new buffer of the bytes received,
otherwise the number of bytes read into ``data`` is returned.
"""
@overload
def recv(self, data: AnyWritableBuf, /, *, timeout: int = 5000) -> int:
"""
Receive data on the bus:
- ``data`` can be an integer, which is the number of bytes to receive,
or a mutable buffer, which will be filled with received bytes.
- ``timeout`` is the timeout in milliseconds to wait for the receive.
Return value: if ``data`` is an integer then a new buffer of the bytes received,
otherwise the number of bytes read into ``data`` is returned.
"""
def send(self, data: Sequence[int]) -> None:
"""
Send data over the USB HID interface:
- ``data`` is the data to send (a tuple/list of integers, or a
bytearray).
"""
# noinspection PyPep8Naming
class USB_VCP:
"""
The USB_VCP class allows creation of a `stream`-like object representing the USB
virtual comm port. It can be used to read and write data over USB to
the connected host.
"""
RTS: ClassVar[int] = ...
"""
to select the flow control type.
.. data:: USB_VCP.IRQ_RX
IRQ trigger values for :meth:`USB_VCP.irq`.
"""
CTS: ClassVar[int] = ...
"""
to select the flow control type.
.. data:: USB_VCP.IRQ_RX
IRQ trigger values for :meth:`USB_VCP.irq`.
"""
def __init__(self, id: int = 0, /):
"""
Create a new USB_VCP object. The *id* argument specifies which USB VCP port to
use.
"""
def init(self, *, flow: int = -1) -> int:
"""
Configure the USB VCP port. If the *flow* argument is not -1 then the value sets
the flow control, which can be a bitwise-or of ``USB_VCP.RTS`` and ``USB_VCP.CTS``.
RTS is used to control read behaviour and CTS, to control write behaviour.
"""
def setinterrupt(self, chr: int, /) -> None:
"""
Set the character which interrupts running Python code. This is set
to 3 (CTRL-C) by default, and when a CTRL-C character is received over
the USB VCP port, a KeyboardInterrupt exception is raised.
Set to -1 to disable this interrupt feature. This is useful when you
want to send raw bytes over the USB VCP port.
"""
def isconnected(self) -> bool:
"""
Return ``True`` if USB is connected as a serial device, else ``False``.
"""
def any(self) -> bool:
"""
Return ``True`` if any characters waiting, else ``False``.
"""
def close(self) -> None:
"""
This method does nothing. It exists so the USB_VCP object can act as
a file.
"""
@overload
def read(self) -> bytes | None:
"""
Read at most ``nbytes`` from the serial device and return them as a
bytes object. If ``nbytes`` is not specified then the method reads
all available bytes from the serial device.
USB_VCP `stream` implicitly works in non-blocking mode,
so if no pending data available, this method will return immediately
with ``None`` value.
"""
@overload
def read(self, nbytes, /) -> bytes | None:
"""
Read at most ``nbytes`` from the serial device and return them as a
bytes object. If ``nbytes`` is not specified then the method reads
all available bytes from the serial device.
USB_VCP `stream` implicitly works in non-blocking mode,
so if no pending data available, this method will return immediately
with ``None`` value.
"""
@overload
def readinto(self, buf: AnyWritableBuf, /) -> int | None:
"""
Read bytes from the serial device and store them into ``buf``, which
should be a buffer-like object. At most ``len(buf)`` bytes are read.
If ``maxlen`` is given and then at most ``min(maxlen, len(buf))`` bytes
are read.
Returns the number of bytes read and stored into ``buf`` or ``None``
if no pending data available.
"""
@overload
def readinto(self, buf: AnyWritableBuf, maxlen: int, /) -> int | None:
"""
Read bytes from the serial device and store them into ``buf``, which
should be a buffer-like object. At most ``len(buf)`` bytes are read.
If ``maxlen`` is given and then at most ``min(maxlen, len(buf))`` bytes
are read.
Returns the number of bytes read and stored into ``buf`` or ``None``
if no pending data available.
"""
def readline(self) -> bytes | None:
"""
Read a whole line from the serial device.
Returns a bytes object containing the data, including the trailing
newline character or ``None`` if no pending data available.
"""
def readlines(self) -> list[bytes] | None:
"""
Read as much data as possible from the serial device, breaking it into
lines.
Returns a list of bytes objects, each object being one of the lines.
Each line will include the newline character.
"""
def write(self, buf: AnyReadableBuf, /) -> int:
"""
Write the bytes from ``buf`` to the serial device.
Returns the number of bytes written.
"""
@overload
def recv(self, data: int, /, *, timeout: int = 5000) -> bytes | None:
"""
Receive data on the bus:
- ``data`` can be an integer, which is the number of bytes to receive,
or a mutable buffer, which will be filled with received bytes.
- ``timeout`` is the timeout in milliseconds to wait for the receive.
Return value: if ``data`` is an integer then a new buffer of the bytes received,
otherwise the number of bytes read into ``data`` is returned.
"""
@overload
def recv(self, data: AnyWritableBuf, /, *, timeout: int = 5000) -> int | None:
"""
Receive data on the bus:
- ``data`` can be an integer, which is the number of bytes to receive,
or a mutable buffer, which will be filled with received bytes.
- ``timeout`` is the timeout in milliseconds to wait for the receive.
Return value: if ``data`` is an integer then a new buffer of the bytes received,
otherwise the number of bytes read into ``data`` is returned.
"""
def send(self, buf: AnyWritableBuf | bytes | int, /, *, timeout: int = 5000) -> int:
"""
Send data over the USB VCP:
- ``data`` is the data to send (an integer to send, or a buffer object).
- ``timeout`` is the timeout in milliseconds to wait for the send.
Return value: number of bytes sent.
"""
================================================
FILE: typehints/pyboard/stm.pyi
================================================
"""
functionality specific to STM32 MCUs.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/stm.rst.
===================================================
.. module:: stm
:synopsis: functionality specific to STM32 MCUs
This module provides functionality specific to STM32 microcontrollers, including
direct access to peripheral registers.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import Final
# noinspection PyPep8Naming
class mem:
"""
Memory objects that can be used in combination with the peripheral register
constants to read and write registers of the MCU hardware peripherals, as well
as all other areas of address space.
Cannot make an instance of this class,
but pre-made instances: `mem8`, `mem16`, and `mem32` are available for 8, 16, and 32 bit access respectively.
"""
def __getitem__(self, loc: int, /) -> int:
"""
Get the contents of the given memory location using subscript notation e.g., `mem8[0]`.
Returns 8 bits for mem8`, 16 bits for `mem16`, and 32 bits for `mem32`, in all cases as a single `int`.
Location doesn't overflow, it is truncated.
Can be used in combination with the peripheral register
constants to read registers of the MCU hardware peripherals, as well
as all other areas of address space.
"""
def __setitem__(self, loc: int, value: int, /) -> None:
"""
Set the contents of the given memory location to the given value using subscript notation e.g., `mem8[0] = 195`.
Sets 8 bits for `mem8`, 16 bits for `mem16`, and 32 bits for `mem32`, from the given `int` value.
Location doesn't overflow, it is truncated.
Can be used in combination with the peripheral register
constants to write registers of the MCU hardware peripherals, as well
as all other areas of address space.
"""
mem8: Final[mem] = ...
"""
Read/write 8 bits of memory.
"""
mem16: Final[mem] = ...
"""
Read/write 16 bits of memory.
"""
mem32: Final[mem] = ...
"""
Read/write 32 bits of memory.
"""
GPIOA: Final[int] = ...
"""
Base address of the GPIOA peripheral.
The module defines constants for registers which are generated from CMSIS header
files, and the constants available depend on the microcontroller series that is
being compiled for. Examples of some constants include:
address of that peripheral. Constants that have a prefix which is the name of a
peripheral, like ``GPIO_BSRR``, are relative offsets of the register. Accessing
peripheral registers requires adding the absolute base address of the peripheral
and the relative register offset. For example ``GPIOA + GPIO_BSRR`` is the
full, absolute address of the ``GPIOA->BSRR`` register.
Example use:
.. code-block:: python3
# set PA2 high
stm.mem32[stm.GPIOA + stm.GPIO_BSRR] = 1 << 2
# read PA3
value = (stm.mem32[stm.GPIOA + stm.GPIO_IDR] >> 3) & 1
"""
GPIOB: Final[int] = ...
"""
Base address of the GPIOB peripheral.
The module defines constants for registers which are generated from CMSIS header
files, and the constants available depend on the microcontroller series that is
being compiled for. Examples of some constants include:
address of that peripheral. Constants that have a prefix which is the name of a
peripheral, like ``GPIO_BSRR``, are relative offsets of the register. Accessing
peripheral registers requires adding the absolute base address of the peripheral
and the relative register offset. For example ``GPIOA + GPIO_BSRR`` is the
full, absolute address of the ``GPIOA->BSRR`` register.
Example use:
.. code-block:: python3
# set PA2 high
stm.mem32[stm.GPIOA + stm.GPIO_BSRR] = 1 << 2
# read PA3
value = (stm.mem32[stm.GPIOA + stm.GPIO_IDR] >> 3) & 1
"""
GPIO_BSRR: Final[int] = ...
"""
Offset of the GPIO bit set/reset register.
The module defines constants for registers which are generated from CMSIS header
files, and the constants available depend on the microcontroller series that is
being compiled for. Examples of some constants include:
address of that peripheral. Constants that have a prefix which is the name of a
peripheral, like ``GPIO_BSRR``, are relative offsets of the register. Accessing
peripheral registers requires adding the absolute base address of the peripheral
and the relative register offset. For example ``GPIOA + GPIO_BSRR`` is the
full, absolute address of the ``GPIOA->BSRR`` register.
Example use:
.. code-block:: python3
# set PA2 high
stm.mem32[stm.GPIOA + stm.GPIO_BSRR] = 1 << 2
# read PA3
value = (stm.mem32[stm.GPIOA + stm.GPIO_IDR] >> 3) & 1
"""
GPIO_IDR: Final[int] = ...
"""
Offset of the GPIO input data register.
The module defines constants for registers which are generated from CMSIS header
files, and the constants available depend on the microcontroller series that is
being compiled for. Examples of some constants include:
address of that peripheral. Constants that have a prefix which is the name of a
peripheral, like ``GPIO_BSRR``, are relative offsets of the register. Accessing
peripheral registers requires adding the absolute base address of the peripheral
and the relative register offset. For example ``GPIOA + GPIO_BSRR`` is the
full, absolute address of the ``GPIOA->BSRR`` register.
Example use:
.. code-block:: python3
# set PA2 high
stm.mem32[stm.GPIOA + stm.GPIO_BSRR] = 1 << 2
# read PA3
value = (stm.mem32[stm.GPIOA + stm.GPIO_IDR] >> 3) & 1
"""
GPIO_ODR: Final[int] = ...
"""
Offset of the GPIO output data register.
Constants that are named after a peripheral, like ``GPIOA``, are the absolute
The module defines constants for registers which are generated from CMSIS header
files, and the constants available depend on the microcontroller series that is
being compiled for. Examples of some constants include:
address of that peripheral. Constants that have a prefix which is the name of a
peripheral, like ``GPIO_BSRR``, are relative offsets of the register. Accessing
peripheral registers requires adding the absolute base address of the peripheral
and the relative register offset. For example ``GPIOA + GPIO_BSRR`` is the
full, absolute address of the ``GPIOA->BSRR`` register.
Example use:
.. code-block:: python3
# set PA2 high
stm.mem32[stm.GPIOA + stm.GPIO_BSRR] = 1 << 2
# read PA3
value = (stm.mem32[stm.GPIOA + stm.GPIO_IDR] >> 3) & 1
"""
def rfcore_status() -> int:
"""
Returns the status of the second CPU as an integer (the first word of device
info table).
These functions are available on STM32WBxx microcontrollers, and interact with
the second CPU, the RF core.
"""
def rfcore_fw_version(id: int, /) -> tuple[int, int, int, int, int]:
"""
Get the version of the firmware running on the second CPU. Pass in 0 for
*id* to get the FUS version, and 1 to get the WS version.
Returns a 5-tuple with the full version number.
These functions are available on STM32WBxx microcontrollers, and interact with
the second CPU, the RF core.
"""
def rfcore_sys_hci(ogf: int, ocf: int, data: int, timeout_ms: int = 0, /) -> bytes:
"""
Execute a HCI command on the SYS channel. The execution is synchronous.
Returns a bytes object with the result of the SYS command.
These functions are available on STM32WBxx microcontrollers, and interact with
the second CPU, the RF core.
"""
================================================
FILE: typehints/rpi_pico/rp2.pyi
================================================
"""
Raspberry Pi Pico specific micropython support.
These methods are not fully documented and this is a best effort to produce the interface
"""
from typing import Optional, Callable
from machine import Pin
class Flash:
"""
Low level access to flash device
"""
def ioctl(self):
pass
def readblocks(self):
pass
def writeblocks(self):
pass
class irq:
"""
IRQ definition
"""
def flags(self) -> int:
"""
IRQ flags
"""
def trigger(self):
"""
Trigger IRQ
"""
class PIO:
IN_LOW: int = 0
IN_HIGH: int = 1
OUT_LOW: int = 2
OUT_HIGH: int = 3
SHIFT_LEFT: int = 0
SHIFT_RIGHT: int = 1
IRQ_SM0: int = 256
IRQ_SM1: int = 512
IRQ_SM2: int = 1024
IRQ_SM3: int = 2048
def __init__(self, num: int):
pass
def irq(self, callback: Optional[Callable[["PIO"], None]]) -> irq:
pass
class StateMachine:
"""
Instantiate a state machine with a program.
"""
def __init__(self, num: int, prog: list, freq: int = None, set_base: Pin = None) -> None:
pass
def active(self) -> bool:
"""
This state machine is active
"""
def init(self, prog: list):
"""
Initialise and start a PIO program
"""
def irq(self) -> PIO.irq:
pass
def put(self, data: bytes):
"""
Send data to PIO program
"""
class PIOASMError(Exception):
pass
def asm_pio(**kwargs) -> list:
"""
Assemble a PIO program
"""
================================================
FILE: typehints/stdlib/_thread.pyi
================================================
"""
multithreading support.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/_thread.rst.
========================================
.. module:: _thread
:synopsis: multithreading support
|see_cpython_module| :mod:`python:_thread`.
This module implements multithreading support.
This module is highly experimental and its API is not yet fully settled
and not yet described in this documentation.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
================================================
FILE: typehints/stdlib/array.pyi
================================================
"""
efficient arrays of numeric data.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/array.rst.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import (
overload,
Sequence,
Any,
MutableSequence,
Generic,
Text,
TypeVar,
Final,
)
_T: Final = TypeVar("_T", int, float, Text)
# noinspection PyPep8Naming
class array(MutableSequence[_T], Generic[_T]):
"""
|see_cpython_module| :mod:`python:array`.
Supported format codes: ``b``, ``B``, ``h``, ``H``, ``i``, ``I``, ``l``,
``L``, ``q``, ``Q``, ``f``, ``d`` (the latter 2 depending on the
floating-point support).
+-----------+--------------------+-------------------+-----------------------+
| Type code | C Type | Python Type | Minimum size in bytes |
+===========+====================+===================+=======================+
| ``'b'`` | signed char | int | 1 |
+-----------+--------------------+-------------------+-----------------------+
| ``'B'`` | unsigned char | int | 1 |
+-----------+--------------------+-------------------+-----------------------+
| ``'h'`` | signed short | int | 2 |
+-----------+--------------------+-------------------+-----------------------+
| ``'H'`` | unsigned short | int | 2 |
+-----------+--------------------+-------------------+-----------------------+
| ``'i'`` | signed int | int | 2 |
+-----------+--------------------+-------------------+-----------------------+
| ``'I'`` | unsigned int | int | 2 |
+-----------+--------------------+-------------------+-----------------------+
| ``'l'`` | signed long | int | 4 |
+-----------+--------------------+-------------------+-----------------------+
| ``'L'`` | unsigned long | int | 4 |
+-----------+--------------------+-------------------+-----------------------+
| ``'q'`` | signed long long | int | 8 |
+-----------+--------------------+-------------------+-----------------------+
| ``'Q'`` | unsigned long long | int | 8 |
+-----------+--------------------+-------------------+-----------------------+
| ``'f'`` | float | float | 4 |
+-----------+--------------------+-------------------+-----------------------+
| ``'d'`` | double | float | 8 |
+-----------+--------------------+-------------------+-----------------------+
"""
def __init__(self, typecode: str, iterable: Sequence[Any] = ..., /):
"""
Create array with elements of given type. Initial contents of the
array are given by *iterable*. If it is not provided, an empty
array is created.
"""
def append(self, val: Any, /) -> None:
"""
Append new element *val* to the end of array, growing it.
"""
def extend(self, iterable: Sequence[Any], /) -> None:
"""
Append new elements as contained in *iterable* to the end of
array, growing it.
"""
def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str:
"""
Deprecated *do not use*, likely to be removed in future!
Note: ``decode`` is only meant to be present for ``bytearray``,
but for efficiency of code-size reasons ``bytearray`` is implemented with the same code as the
other array type-codes and hence ``decode`` is on all ``array``s at present.
"""
@overload
def __delitem__(self, i: int) -> None:
"""``array`` object does **not** support item deletion."""
@overload
def __delitem__(self, sl: slice) -> None:
"""``array`` object does **not** support item deletion."""
def insert(self, index: int, value: _T) -> None:
"""``array`` object does **not** support item insertion."""
@overload
def __getitem__(self, index: int) -> _T:
"""
Indexed read of ``self``; called as ``a[index]``, where ``a`` is an ``array``.
Returns the value at the given ``index``.
Negative indices count from end and ``IndexError``is thrown if the index out of range.
**Note:** ``__getitem__`` cannot be called directly (``a.__getitem__(index)`` fails) and
is not present in ``__dict__``, however ``a[index]`` does work.
"""
@overload
def __getitem__(self, sl: slice) -> array[_T]:
"""
Slice read of ``self``; called as ``a[sl]``, where ``a`` is an ``array``.
Returns an ``array`` of values for the given slice.
Negative slice indices count from end and ``IndexError``is thrown if any of the slice indices are out of range.
**Note:** ``__getitem__`` cannot be called directly (``a.__getitem__(sl)`` fails) and
is not present in ``__dict__``, however ``a[sl]`` does work.
"""
@overload
def __setitem__(self, index: int, value: _T) -> None:
"""
Indexed write into ``self``; called as ``a[index] = value`` where ``a`` is an ``array``,
``index`` is an ``int``, and ``value`` is the same type as ``a``'s content.
Negative indices count from end and ``IndexError``is thrown if the index out of range.
**Note:** ``__setitem__`` cannot be called directly (``a.__setitem__(index, value)`` fails) and
is not present in ``__dict__``, however ``a[index] = value`` does work.
"""
@overload
def __setitem__(self, sl: slice, values: array[_T]) -> None:
"""
Indexed write into ``self``; called as ``a[sl] = values``, where ``a`` is an ``array``,
``sl`` is an ``slice``, and ``values`` is the same type as ``a``.
Negative indices count from end and ``IndexError``is thrown if any of the slice indices are out of range.
**Note:** ``__setitem__`` cannot be called directly (``a.__setitem__(index, value)`` fails) and
is not present in ``__dict__``, however ``a[index] = value`` does work.
"""
def __len__(self) -> int:
"""
Returns the number of items in ``self``; called as ``len(a)``, where ``a`` is an ``array``.
**Note:** ``__len__`` cannot be called directly (``a.__len__()`` fails) and the
method is not present in ``__dict__``, however ``len(a)`` does work.
"""
def __add__(self, other: array[_T]) -> array[_T]:
"""
Return a new ``array`` that is the concatenation of ``self`` with ``other``;
called as ``a + other`` (where ``a`` and ``other`` are both ``array``s).
**Note:** ``__add__`` cannot be called directly (``a.__add__(other)`` fails) and
is not present in ``__dict__``, however ``a + other`` does work.
"""
def __iadd__(self, other: array[_T]) -> None:
"""
Concatenates ``self`` with ``other`` in-place;
called as ``a += other``, where ``a`` and ``other`` are both ``array``s.
Equivalent to ``extend(other)``.
**Note:** ``__iadd__`` cannot be called directly (``a.__iadd__(other)`` fails) and
is not present in ``__dict__``, however ``a += other`` does work.
"""
def __repr__(self) -> str:
"""
Returns the string representation of ``self``; called as ``str(a)`` or ``repr(a)```,
where ``a`` is an ``array``.
Returns the string 'array(, [])',
where ```` is the type code letter for ``self`` and ```` is a
comma separated list of the elements of ``self``.
**Note:** ``__repr__`` cannot be called directly (``a.__repr__()`` fails) and
is not present in ``__dict__``, however ``str(a)`` and ``repr(a)`` both work.
"""
================================================
FILE: typehints/stdlib/binascii.pyi
================================================
"""
binary/ASCII conversions.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/binascii.rst.
===========================================
.. module:: binascii
:synopsis: binary/ASCII conversions
|see_cpython_module| :mod:`python:binascii`.
This module implements conversions between binary data and various
encodings of it in ASCII form (in both directions).
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
def hexlify(data: bytes, sep: str | bytes = ..., /) -> bytes:
"""
Convert the bytes in the *data* object to a hexadecimal representation.
Returns a bytes object.
If the additional argument *sep* is supplied it is used as a separator
between hexadecimal values.
"""
def unhexlify(data: str | bytes, /) -> bytes:
"""
Convert hexadecimal data to binary representation. Returns bytes string.
(i.e. inverse of hexlify)
"""
def a2b_base64(data: str | bytes, /) -> bytes:
"""
Decode base64-encoded data, ignoring invalid characters in the input.
Conforms to `RFC 2045 s.6.8 `_.
Returns a bytes object.
"""
def b2a_base64(data: bytes, /) -> bytes:
"""
Encode binary data in base64 format, as in `RFC 3548
`_. Returns the encoded data
followed by a newline character, as a bytes object.
"""
================================================
FILE: typehints/stdlib/cmath.pyi
================================================
"""
mathematical functions for complex numbers.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/cmath.rst.
==========================================================
.. module:: cmath
:synopsis: mathematical functions for complex numbers
|see_cpython_module| :mod:`python:cmath`.
The ``cmath`` module provides some basic mathematical functions for
working with complex numbers.
Availability: not available on WiPy and ESP8266. Floating point support
required for this module.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import SupportsComplex, SupportsFloat, Final
_C: Final = SupportsFloat | SupportsComplex
def cos(z: _C, /) -> complex:
"""
Return the cosine of ``z``.
"""
def exp(z: _C, /) -> complex:
"""
Return the exponential of ``z``.
"""
def log(z: _C, /) -> complex:
"""
Return the natural logarithm of ``z``. The branch cut is along the negative real axis.
"""
def log10(z: _C, /) -> complex:
"""
Return the base-10 logarithm of ``z``. The branch cut is along the negative real axis.
"""
def phase(z: _C, /) -> float:
"""
Returns the phase of the number ``z``, in the range (-pi, +pi].
"""
def polar(z: _C, /) -> tuple[float, float]:
"""
Returns, as a tuple, the polar form of ``z``.
"""
def rect(r: float, phi: float, /) -> complex:
"""
Returns the complex number with modulus ``r`` and phase ``phi``.
"""
def sin(z: _C, /) -> complex:
"""
Return the sine of ``z``.
"""
def sqrt(z: _C, /) -> complex:
"""
Return the square-root of ``z``.
"""
e: Final[float] = ...
"""
base of the natural logarithm
"""
pi: Final[float] = ...
"""
the ratio of a circle's circumference to its diameter
"""
================================================
FILE: typehints/stdlib/collections.pyi
================================================
"""
collection and container types.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/collections.rst.
====================================================
.. module:: collections
:synopsis: collection and container types
|see_cpython_module| :mod:`python:collections`.
This module implements advanced collection and container types to
hold/accumulate various objects.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import overload, Any, Type, Iterable, TypeVar, Generic, Mapping, Dict, Final
_KT: Final = TypeVar("_KT")
_VT: Final = TypeVar("_VT")
def namedtuple(name: str, fields: str | Iterable[str]) -> Type[tuple[Any, ...]]:
"""
This is factory function to create a new namedtuple type with a specific
name and set of fields. A namedtuple is a subclass of tuple which allows
to access its fields not just by numeric index, but also with an attribute
access syntax using symbolic field names. Fields is a sequence of strings
specifying field names. For compatibility with CPython it can also be a
a string with space-separated field named (but this is less efficient).
Example of use::
from collections import namedtuple
MyTuple = namedtuple("MyTuple", ("id", "name"))
t1 = MyTuple(1, "foo")
t2 = MyTuple(2, "bar")
print(t1.name)
assert t2.name == t2[1]
"""
# noinspection PyPep8Naming
class deque:
"""
Minimal implementation of a deque that implements a FIFO buffer.
"""
def __init__(self, iterable: tuple[Any], maxlen: int, flags: int = 0, /):
"""
Deques (double-ended queues) are a list-like container that support O(1)
appends and pops from either side of the deque. New deques are created
using the following arguments:
- *iterable* must be the empty tuple, and the new deque is created empty.
- *maxlen* must be specified and the deque will be bounded to this
maximum length. Once the deque is full, any new items added will
discard items from the opposite end.
- The optional *flags* can be 1 to check for overflow when adding items.
"""
def __bool__(self) -> bool:
"""
Returns true if the `deque` isn't empty.
**Note:** The method isn't listed by ``dir(deque)`` and can't be called directly,
however ``bool(deque)`` and automatic conversion work!
"""
def __len__(self) -> int:
"""
Returns the number of items in the `deque`.
**Note:** The method isn't listed by ``dir(deque)`` and can't be called directly,
however ``len(deque)`` works!
"""
def append(self, x: Any, /) -> None:
"""
Add *x* to the right side of the deque.
Raises IndexError if overflow checking is enabled and there is no more room left.
"""
def popleft(self) -> Any:
"""
Remove and return an item from the left side of the deque.
Raises IndexError if no items are present.
"""
class OrderedDict(Dict[_KT, _VT], Generic[_KT, _VT]):
"""
W
h
e
n
o
r
d
e
r
e
d
d
i
c
t
i
s
i
t
e
r
a
t
e
d
o
v
e
r
,
k
e
y
s
/
i
t
e
m
s
a
r
e
r
e
t
u
r
n
e
d
i
n
t
h
e
o
r
d
e
r
t
h
e
y
w
e
r
e
a
d
d
e
d
.
"""
@overload
def __init__(self):
"""
``dict`` type subclass which remembers and preserves the order of keys
added. When ordered dict is iterated over, keys/items are returned in
the order they were added::
from collections import OrderedDict
# To make benefit of ordered keys, OrderedDict should be initialized
# from sequence of (key, value) pairs.
d = OrderedDict([("z", 1), ("a", 2)])
# More items can be added as usual
d["w"] = 5
d["b"] = 3
for k, v in d.items():
print(k, v)
Output::
z 1
a 2
w 5
b 3
"""
@overload
def __init__(self, **kwargs: _VT):
"""
``dict`` type subclass which remembers and preserves the order of keys
added. When ordered dict is iterated over, keys/items are returned in
the order they were added::
from collections import OrderedDict
# To make benefit of ordered keys, OrderedDict should be initialized
# from sequence of (key, value) pairs.
d = OrderedDict([("z", 1), ("a", 2)])
# More items can be added as usual
d["w"] = 5
d["b"] = 3
for k, v in d.items():
print(k, v)
Output::
z 1
a 2
w 5
b 3
"""
@overload
def __init__(self, map: Mapping[_KT, _VT], **kwargs: _VT):
"""
``dict`` type subclass which remembers and preserves the order of keys
added. When ordered dict is iterated over, keys/items are returned in
the order they were added::
from collections import OrderedDict
# To make benefit of ordered keys, OrderedDict should be initialized
# from sequence of (key, value) pairs.
d = OrderedDict([("z", 1), ("a", 2)])
# More items can be added as usual
d["w"] = 5
d["b"] = 3
for k, v in d.items():
print(k, v)
Output::
z 1
a 2
w 5
b 3
"""
================================================
FILE: typehints/stdlib/errno.pyi
================================================
"""
system error codes.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/errno.rst.
==================================
.. module:: errno
:synopsis: system error codes
|see_cpython_module| :mod:`python:errno`.
This module provides access to symbolic error codes for `OSError` exception.
A particular inventory of codes depends on :term:`MicroPython port`.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import Final, Dict
EEXIST: Final[int] = ...
"""
Error codes, based on ANSI C/POSIX standard. All error codes start with
"E". As mentioned above, inventory of the codes depends on
:term:`MicroPython port`. Errors are usually accessible as ``exc.errno``
where ``exc`` is an instance of `OSError`. Usage example::
try:
os.mkdir("my_dir")
except OSError as exc:
if exc.errno == errno.EEXIST:
print("Directory already exists")
"""
EAGAIN: Final[int] = ...
"""
Error codes, based on ANSI C/POSIX standard. All error codes start with
"E". As mentioned above, inventory of the codes depends on
:term:`MicroPython port`. Errors are usually accessible as ``exc.errno``
where ``exc`` is an instance of `OSError`. Usage example::
try:
os.mkdir("my_dir")
except OSError as exc:
if exc.errno == errno.EEXIST:
print("Directory already exists")
"""
errorcode: Final[Dict[int, str]] = ...
"""
Dictionary mapping numeric error codes to strings with symbolic error
code (see above)::
>>> print(errno.errorcode[errno.EEXIST])
EEXIST
"""
================================================
FILE: typehints/stdlib/gc.pyi
================================================
"""
control the garbage collector.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/gc.rst.
==========================================
.. module:: gc
:synopsis: control the garbage collector
|see_cpython_module| :mod:`python:gc`.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import overload
def enable() -> None:
"""
Enable automatic garbage collection.
"""
def disable() -> None:
"""
Disable automatic garbage collection. Heap memory can still be allocated,
and garbage collection can still be initiated manually using :meth:`gc.collect`.
"""
def collect() -> None:
"""
Run a garbage collection.
"""
def mem_alloc() -> int:
"""
Return the number of bytes of heap RAM that are allocated.
.. admonition:: Difference to CPython
:class: attention
This function is MicroPython extension.
"""
def mem_free() -> int:
"""
Return the number of bytes of available heap RAM, or -1 if this amount
is not known.
.. admonition:: Difference to CPython
:class: attention
This function is MicroPython extension.
"""
@overload
def threshold() -> int:
"""
Set or query the additional GC allocation threshold. Normally, a collection
is triggered only when a new allocation cannot be satisfied, i.e. on an
out-of-memory (OOM) condition. If this function is called, in addition to
OOM, a collection will be triggered each time after *amount* bytes have been
allocated (in total, since the previous time such an amount of bytes
have been allocated). *amount* is usually specified as less than the
full heap size, with the intention to trigger a collection earlier than when the
heap becomes exhausted, and in the hope that an early collection will prevent
excessive memory fragmentation. This is a heuristic measure, the effect
of which will vary from application to application, as well as
the optimal value of the *amount* parameter.
Calling the function without argument will return the current value of
the threshold. A value of -1 means a disabled allocation threshold.
.. admonition:: Difference to CPython
:class: attention
This function is a MicroPython extension. CPython has a similar
function - ``set_threshold()``, but due to different GC
implementations, its signature and semantics are different.
"""
@overload
def threshold(amount: int) -> None:
"""
Set or query the additional GC allocation threshold. Normally, a collection
is triggered only when a new allocation cannot be satisfied, i.e. on an
out-of-memory (OOM) condition. If this function is called, in addition to
OOM, a collection will be triggered each time after *amount* bytes have been
allocated (in total, since the previous time such an amount of bytes
have been allocated). *amount* is usually specified as less than the
full heap size, with the intention to trigger a collection earlier than when the
heap becomes exhausted, and in the hope that an early collection will prevent
excessive memory fragmentation. This is a heuristic measure, the effect
of which will vary from application to application, as well as
the optimal value of the *amount* parameter.
Calling the function without argument will return the current value of
the threshold. A value of -1 means a disabled allocation threshold.
.. admonition:: Difference to CPython
:class: attention
This function is a MicroPython extension. CPython has a similar
function - ``set_threshold()``, but due to different GC
implementations, its signature and semantics are different.
"""
================================================
FILE: typehints/stdlib/hashlib.pyi
================================================
"""
hashing algorithms.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/hashlib.rst.
====================================
.. module:: hashlib
:synopsis: hashing algorithms
|see_cpython_module| :mod:`python:hashlib`.
This module implements binary data hashing algorithms. The exact inventory
of available algorithms depends on a board. Among the algorithms which may
be implemented:
* SHA256 - The current generation, modern hashing algorithm (of SHA2 series).
It is suitable for cryptographically-secure purposes. Included in the
MicroPython core and any board is recommended to provide this, unless
it has particular code size constraints.
* SHA1 - A previous generation algorithm. Not recommended for new usages,
but SHA1 is a part of number of Internet standards and existing
applications, so boards targeting network connectivity and
interoperability will try to provide this.
* MD5 - A legacy algorithm, not considered cryptographically secure. Only
selected boards, targeting interoperability with legacy applications,
will offer this.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from abc import ABC
from typing import overload
from uio import AnyReadableBuf
# noinspection PyPep8Naming
class sha256("_Hash"):
"""
The current generation, modern hashing algorithm (of SHA2 series).
It is suitable for cryptographically-secure purposes. Included in the
MicroPython core and any board is recommended to provide this, unless
it has particular code size constraints.
"""
@overload
def __init__(self):
"""
Create an SHA256 hasher object and optionally feed ``data`` into it.
"""
@overload
def __init__(self, data: AnyReadableBuf):
"""
Create an SHA256 hasher object and optionally feed ``data`` into it.
"""
# noinspection PyPep8Naming
class sha1("_Hash"):
"""
A previous generation algorithm. Not recommended for new usages,
but SHA1 is a part of number of Internet standards and existing
applications, so boards targeting network connectivity and
interoperability will try to provide this.
"""
@overload
def __init__(self):
"""
Create an SHA1 hasher object and optionally feed ``data`` into it.
"""
@overload
def __init__(self, data: AnyReadableBuf):
"""
Create an SHA1 hasher object and optionally feed ``data`` into it.
"""
# noinspection PyPep8Naming
class md5("_Hash"):
"""
A legacy algorithm, not considered cryptographically secure. Only
selected boards, targeting interoperability with legacy applications,
will offer this.
"""
def __init__(self, data: AnyReadableBuf = ..., /):
"""
Create an MD5 hasher object and optionally feed ``data`` into it.
"""
class _Hash(ABC):
"""
Abstract base class for hashing algorithms that defines methods available in all algorithms.
"""
def update(self, data: AnyReadableBuf, /) -> None:
"""
Feed more binary data into hash.
"""
def digest(self) -> bytes:
"""
Return hash for all data passed through hash, as a bytes object. After this
method is called, more data cannot be fed into the hash any longer.
"""
def hexdigest(self) -> str:
"""
This method is NOT implemented. Use ``binascii.hexlify(hash.digest())``
to achieve a similar effect.
"""
================================================
FILE: typehints/stdlib/heapq.pyi
================================================
"""
heap queue algorithm.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/heapq.rst.
====================================
.. module:: heapq
:synopsis: heap queue algorithm
|see_cpython_module| :mod:`python:heapq`.
This module implements the
`min heap queue algorithm `_.
A heap queue is essentially a list that has its elements stored in such a way
that the first item of the list is always the smallest.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import TypeVar, Any, Final
_T: Final = TypeVar("_T")
def heappush(heap: list[_T], item: _T, /) -> None:
"""
Push the ``item`` onto the ``heap``.
"""
def heappop(heap: list[_T], /) -> _T:
"""
Pop the first item from the ``heap``, and return it. Raise ``IndexError`` if
``heap`` is empty.
The returned item will be the smallest item in the ``heap``.
"""
def heapify(x: list[Any], /) -> None:
"""
Convert the list ``x`` into a heap. This is an in-place operation.
"""
================================================
FILE: typehints/stdlib/io.pyi
================================================
"""
input/output streams.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/io.rst.
=================================
.. module:: io
:synopsis: input/output streams
|see_cpython_module| :mod:`python:io`.
This module contains additional types of `stream` (file-like) objects
and helper functions.
Conceptual hierarchy
--------------------
.. admonition:: Difference to CPython
:class: attention
Conceptual hierarchy of stream base classes is simplified in MicroPython,
as described in this section.
(Abstract) base stream classes, which serve as a foundation for behaviour
of all the concrete classes, adhere to few dichotomies (pair-wise
classifications) in CPython. In MicroPython, they are somewhat simplified
and made implicit to achieve higher efficiencies and save resources.
An important dichotomy in CPython is unbuffered vs buffered streams. In
MicroPython, all streams are currently unbuffered. This is because all
modern OSes, and even many RTOSes and filesystem drivers already perform
buffering on their side. Adding another layer of buffering is counter-
productive (an issue known as "bufferbloat") and takes precious memory.
Note that there still cases where buffering may be useful, so we may
introduce optional buffering support at a later time.
But in CPython, another important dichotomy is tied with "bufferedness" -
it's whether a stream may incur short read/writes or not. A short read
is when a user asks e.g. 10 bytes from a stream, but gets less, similarly
for writes. In CPython, unbuffered streams are automatically short
operation susceptible, while buffered are guarantee against them. The
no short read/writes is an important trait, as it allows to develop
more concise and efficient programs - something which is highly desirable
for MicroPython. So, while MicroPython doesn't support buffered streams,
it still provides for no-short-operations streams. Whether there will
be short operations or not depends on each particular class' needs, but
developers are strongly advised to favour no-short-operations behaviour
for the reasons stated above. For example, MicroPython sockets are
guaranteed to avoid short read/writes. Actually, at this time, there is
no example of a short-operations stream class in the core, and one would
be a port-specific class, where such a need is governed by hardware
peculiarities.
The no-short-operations behaviour gets tricky in case of non-blocking
streams, blocking vs non-blocking behaviour being another CPython dichotomy,
fully supported by MicroPython. Non-blocking streams never wait for
data either to arrive or be written - they read/write whatever possible,
or signal lack of data (or ability to write data). Clearly, this conflicts
with "no-short-operations" policy, and indeed, a case of non-blocking
buffered (and this no-short-ops) streams is convoluted in CPython - in
some places, such combination is prohibited, in some it's undefined or
just not documented, in some cases it raises verbose exceptions. The
matter is much simpler in MicroPython: non-blocking stream are important
for efficient asynchronous operations, so this property prevails on
the "no-short-ops" one. So, while blocking streams will avoid short
reads/writes whenever possible (the only case to get a short read is
if end of file is reached, or in case of error (but errors don't
return short data, but raise exceptions)), non-blocking streams may
produce short data to avoid blocking the operation.
The final dichotomy is binary vs text streams. MicroPython of course
supports these, but while in CPython text streams are inherently
buffered, they aren't in MicroPython. (Indeed, that's one of the cases
for which we may introduce buffering support.)
Note that for efficiency, MicroPython doesn't provide abstract base
classes corresponding to the hierarchy above, and it's not possible
to implement, or subclass, a stream class in pure Python.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from types import TracebackType
from typing import TypeVar, Final, Protocol, runtime_checkable, Literal
from typing import AnyStr, overload, Type
from uarray import array
_T: Final = TypeVar("_T")
_OpenTextModeUpdating: Final = Literal[
"r+",
"+r",
"rt+",
"r+t",
"+rt",
"tr+",
"t+r",
"+tr",
"w+",
"+w",
"wt+",
"w+t",
"+wt",
"tw+",
"t+w",
"+tw",
"a+",
"+a",
"at+",
"a+t",
"+at",
"ta+",
"t+a",
"+ta",
"x+",
"+x",
"xt+",
"x+t",
"+xt",
"tx+",
"t+x",
"+tx",
]
_OpenTextModeWriting: Final = Literal["w", "wt", "tw", "a", "at", "ta", "x", "xt", "tx"]
_OpenTextModeReading: Final = Literal[
"r", "rt", "tr", "U", "rU", "Ur", "rtU", "rUt", "Urt", "trU", "tUr", "Utr"
]
_OpenTextMode: Final = _OpenTextModeUpdating | _OpenTextModeWriting | _OpenTextModeReading
_OpenBinaryModeUpdating: Final = Literal[
"rb+",
"r+b",
"+rb",
"br+",
"b+r",
"+br",
"wb+",
"w+b",
"+wb",
"bw+",
"b+w",
"+bw",
"ab+",
"a+b",
"+ab",
"ba+",
"b+a",
"+ba",
"xb+",
"x+b",
"+xb",
"bx+",
"b+x",
"+bx",
]
_OpenBinaryModeWriting: Final = Literal["wb", "bw", "ab", "ba", "xb", "bx"]
_OpenBinaryModeReading: Final = Literal[
"rb", "br", "rbU", "rUb", "Urb", "brU", "bUr", "Ubr"
]
_OpenBinaryMode: Final = _OpenBinaryModeUpdating | _OpenBinaryModeReading | _OpenBinaryModeWriting
AnyStr_co: Final = TypeVar("AnyStr_co", str, bytes, covariant=True)
@runtime_checkable
class PathLike(Protocol[AnyStr_co]):
def __fspath__(self) -> AnyStr_co: ...
StrOrBytesPath: Final = str | bytes | PathLike[str] | PathLike[bytes]
_OpenFile: Final = StrOrBytesPath | int
AnyReadableBuf: Final = TypeVar("AnyReadableBuf", bytearray, array, memoryview, bytes)
"""
Type that allows bytearray, array, memoryview, or bytes,
but only one of these and not a mixture in a single declaration.
"""
AnyWritableBuf: Final = TypeVar("AnyWritableBuf", bytearray, array, memoryview)
"""
Type that allows bytearray, array, or memoryview, but only one of these and not a mixture in a single declaration.
"""
_Self: Final = TypeVar("_Self") # The type that extends `IOBase`.
@runtime_checkable
class IOBase(Protocol[AnyStr, _Self]):
"""A `Protocol` (structurally typed) for an IOStream."""
__slots__ = ()
def __enter__(self) -> _Self:
"""
Called on entry to a `with` block.
The `with` statement will bind this method’s return value to the target(s) specified in the `as` clause
of the statement, if any.
"""
def __exit__(
self,
exc_type: Type[BaseException] | None,
exc_value: BaseException | None,
traceback: TracebackType | None,
) -> bool | None:
"""
Called on exit of a `with` block.
The parameters describe the exception that caused the context to be exited.
If the context was exited without an exception, all three arguments will be `None`.
If an exception is supplied, and the method wishes to suppress the exception
(i.e., prevent it from being propagated), it should return a true value.
Otherwise, the exception will be processed normally upon exit from this method.
*Note* that `__exit__()` methods should not re-raise the passed-in exception;
this is the caller’s responsibility.
"""
def __next__(self) -> AnyStr:
"""
Next string.
"""
def __iter__(self) -> _Self:
"""
Start new iteration.
"""
def close(self) -> None:
"""
Flushes the write buffers and closes the IO stream; best not called directly, use a `with` block instead.
Calling `f.close()` without using a `with` block might result in content not being completely written to the
disk, even if the program exits successfully.
A closed file cannot be read or written any more.
Any operation which requires that the file be open will raise a `ValueError` after the file has been closed.
Calling `f.close()` more than once is allowed.
"""
def flush(self) -> None:
"""
Flushes the write buffers of the IO stream.
`flush()` does not necessarily write the file’s data to disk.
Use `f.flush()` followed by `os.sync()` to ensure this behavior.
This method does nothing for read-only and non-blocking streams.
"""
def read(self, size: int | None = -1) -> AnyStr | None:
"""
Read up to `size` bytes from the object and return them as a `str` (text file) or `bytes` (binary file).
As a convenience, if `size` is unspecified or -1, all bytes until EOF are returned.
Otherwise, only one system call is ever made.
Fewer than `size` bytes may be returned if the operating system call returns fewer than `size` bytes.
If 0 bytes are returned, and `size` was not 0, this indicates end of file.
If `self` is in non-blocking mode and no bytes are available, `None` is returned.
"""
def readinto(self, b: AnyWritableBuf) -> int | None:
"""
Read bytes into a pre-allocated, writable bytes-like object b, and return the number of bytes read.
For example, b might be a bytearray.
If `self` is in non-blocking mode and no bytes are available, `None` is returned.
"""
def readline(self, size: int = -1) -> AnyStr:
"""
Read and return, as a `str` (text file) or `bytes` (binary file), one line from the stream.
If size is specified, at most size bytes will be read.
The line terminator is always `b'
'` for binary files;
for text files, the newline argument to `open()` can be used to select the line terminator(s) recognized.
"""
def readlines(self, hint: int | None = -1) -> list[AnyStr]:
"""
Read and return a list of lines, as a `list[str]` (text file) or `list[bytes]` (binary file), from the stream.
`hint` can be specified to control the number of lines read:
no more lines will be read if the total size (in bytes/characters) of all lines so far exceeds `hint`.
`hint` values of 0 or less, as well as `None`, are treated as no hint.
The line terminator is always `b'
'` for binary files;
for text files, the newline argument to `open()` can be used to select the line terminator(s) recognized.
*Note* that it’s already possible to iterate on file objects using `for line in file: ...`
without calling `file.readlines()`.
"""
def write(self, b: AnyReadableBuf) -> int | None:
"""
Write the given bytes-like object, `b`, to the underlying raw stream, and return the number of bytes written.
This can be less than the length of `b` in bytes, depending on specifics of the underlying raw stream,
and especially if it is in non-blocking mode.
`None` is returned if the raw stream is set not to block and no single byte could be readily written to it.
The caller may release or mutate `b` after this method returns,
so the implementation only access `b` during the method call.
"""
def seek(self, offset: int, whence: int = 0) -> int:
"""
Change the stream position to the given byte `offset`.
`offset` is interpreted relative to the position indicated by `whence`.
The default value for whence is 0.
Values for whence are:
* 0 – start of the stream (the default); offset should be zero or positive.
* 1 – current stream position; offset may be negative.
* 2 – end of the stream; offset is usually negative.
Returns the new absolute position.
"""
def tell(self) -> int:
"""
Return the current stream position.
"""
@overload
def open(name: _OpenFile, /, **kwargs) -> "TextIOWrapper":
"""
Open a file. Builtin ``open()`` function is aliased to this function.
All ports (which provide access to file system) are required to support
*mode* parameter, but support for other arguments vary by port.
"""
@overload
def open(name: _OpenFile, mode: _OpenTextMode = ..., /, **kwargs) -> "TextIOWrapper":
"""
Open a file. Builtin ``open()`` function is aliased to this function.
All ports (which provide access to file system) are required to support
*mode* parameter, but support for other arguments vary by port.
"""
@overload
def open(name: _OpenFile, mode: _OpenBinaryMode = ..., /, **kwargs) -> "FileIO":
"""
Open a file. Builtin ``open()`` function is aliased to this function.
All ports (which provide access to file system) are required to support
*mode* parameter, but support for other arguments vary by port.
"""
class FileIO(IOBase[bytes, "FileIO"]):
"""
Bytes stream from a file.
"""
def __init__(self, name: _OpenFile, mode: str = ..., /, **kwargs):
"""
This is type of a file open in binary mode, e.g. using ``open(name, "rb")``.
You should not instantiate this class directly.
"""
class TextIOWrapper(IOBase[str, "TextIOWrapper"]):
"""
Str stream from a file.
"""
def __init__(self, name: _OpenFile, mode: str = ..., /, **kwargs):
"""
This is type of a file open in text mode, e.g. using ``open(name, "rt")``.
You should not instantiate this class directly.
"""
class StringIO(IOBase[str, "StringIO"]):
"""
Str stream from a str (wrapper).
"""
@overload
def __init__(self, string: str = "", /):
"""
In-memory file-like object for input/output.
`StringIO` is used for text-mode I/O (similar to a normal file opened with "t" modifier).
Initial contents can be specified with `string` parameter.
`alloc_size` constructor creates an empty `StringIO` object,
pre-allocated to hold up to `alloc_size` number of bytes.
That means that writing that amount of bytes won't lead to reallocation of the buffer,
and thus won't hit out-of-memory situation or lead to memory fragmentation.
This constructor is a MicroPython extension and is recommended for usage only in special
cases and in system-level libraries, not for end-user applications.
.. admonition:: Difference to CPython
:class: attention
This constructor is a MicroPython extension.
"""
@overload
def __init__(self, alloc_size: int, /):
"""
In-memory file-like object for input/output.
`StringIO` is used for text-mode I/O (similar to a normal file opened with "t" modifier).
Initial contents can be specified with `string` parameter.
`alloc_size` constructor creates an empty `StringIO` object,
pre-allocated to hold up to `alloc_size` number of bytes.
That means that writing that amount of bytes won't lead to reallocation of the buffer,
and thus won't hit out-of-memory situation or lead to memory fragmentation.
This constructor is a MicroPython extension and is recommended for usage only in special
cases and in system-level libraries, not for end-user applications.
.. admonition:: Difference to CPython
:class: attention
This constructor is a MicroPython extension.
"""
def getvalue(self) -> str:
"""Get the current contents of the underlying buffer which holds data."""
class BytesIO(IOBase[bytes, "BytesIO"]):
"""
Bytes stream from a bytes array (wrapper).
"""
@overload
def __init__(self, string: bytes = "", /):
"""
In-memory file-like objects for input/output. `StringIO` is used for
text-mode I/O (similar to a normal file opened with "t" modifier).
`BytesIO` is used for binary-mode I/O (similar to a normal file
opened with "b" modifier). Initial contents of file-like objects
can be specified with *string* parameter (should be normal string
for `StringIO` or bytes object for `BytesIO`). All the usual file
methods like ``read()``, ``write()``, ``seek()``, ``flush()``,
``close()`` are available on these objects, and additionally, a
following method:
`alloc_size` constructor creates an empty `BytesIO` object,
pre-allocated to hold up to `alloc_size` number of bytes.
That means that writing that amount of bytes won't lead to reallocation of the buffer,
and thus won't hit out-of-memory situation or lead to memory fragmentation.
This constructor is a MicroPython extension and is recommended for usage only in special
cases and in system-level libraries, not for end-user applications.
.. admonition:: Difference to CPython
:class: attention
This constructor is a MicroPython extension.
"""
@overload
def __init__(self, alloc_size: int, /):
"""
In-memory file-like objects for input/output. `StringIO` is used for
text-mode I/O (similar to a normal file opened with "t" modifier).
`BytesIO` is used for binary-mode I/O (similar to a normal file
opened with "b" modifier). Initial contents of file-like objects
can be specified with *string* parameter (should be normal string
for `StringIO` or bytes object for `BytesIO`). All the usual file
methods like ``read()``, ``write()``, ``seek()``, ``flush()``,
``close()`` are available on these objects, and additionally, a
following method:
`alloc_size` constructor creates an empty `BytesIO` object,
pre-allocated to hold up to `alloc_size` number of bytes.
That means that writing that amount of bytes won't lead to reallocation of the buffer,
and thus won't hit out-of-memory situation or lead to memory fragmentation.
This constructor is a MicroPython extension and is recommended for usage only in special
cases and in system-level libraries, not for end-user applications.
.. admonition:: Difference to CPython
:class: attention
This constructor is a MicroPython extension.
"""
def getvalue(self) -> bytes:
"""
Get the current contents of the underlying buffer which holds data.
"""
================================================
FILE: typehints/stdlib/json.pyi
================================================
"""
JSON encoding and decoding.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/json.rst.
=========================================
.. module:: json
:synopsis: JSON encoding and decoding
|see_cpython_module| :mod:`python:json`.
This modules allows to convert between Python objects and the JSON
data format.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import Any, AnyStr
from uio import IOBase
def dump(
obj: Any, stream: IOBase[str, Any], separators: tuple[str, str] | None = None, /
) -> None:
"""
Serialise *obj* to a JSON string, writing it to the given *stream*.
If specified, separators should be an ``(item_separator, key_separator)``
tuple. The default is ``(', ', ': ')``. To get the most compact JSON
representation, you should specify ``(',', ':')`` to eliminate whitespace.
"""
def dumps(obj: Any, separators: tuple[str, str] | None = None) -> str:
"""
Return *obj* represented as a JSON string.
The arguments have the same meaning as in `dump`.
"""
def load(stream: IOBase[str, Any]) -> Any:
"""
Parse the given *stream*, interpreting it as a JSON string and
deserialising the data to a Python object. The resulting object is
returned.
Parsing continues until end-of-file is encountered.
A :exc:`ValueError` is raised if the data in *stream* is not correctly formed.
"""
def loads(str: AnyStr) -> Any:
"""
Parse the JSON *str* and return an object. Raises :exc:`ValueError` if the
string is not correctly formed.
"""
================================================
FILE: typehints/stdlib/math.pyi
================================================
"""
mathematical functions.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/math.rst.
=====================================
.. module:: math
:synopsis: mathematical functions
|see_cpython_module| :mod:`python:math`.
The ``math`` module provides some basic mathematical functions for
working with floating-point numbers.
*Note:* On the pyboard, floating-point numbers have 32-bit precision.
Availability: not available on WiPy. Floating point support required
for this module.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import SupportsFloat, Final
def acos(x: SupportsFloat, /) -> float:
"""
Return the inverse cosine of ``x``.
"""
def acosh(x: SupportsFloat, /) -> float:
"""
Return the inverse hyperbolic cosine of ``x``.
"""
def asin(x: SupportsFloat, /) -> float:
"""
Return the inverse sine of ``x``.
"""
def asinh(x: SupportsFloat, /) -> float:
"""
Return the inverse hyperbolic sine of ``x``.
"""
def atan(x: SupportsFloat, /) -> float:
"""
Return the inverse tangent of ``x``.
"""
def atan2(y: SupportsFloat, x: SupportsFloat, /) -> float:
"""
Return the principal value of the inverse tangent of ``y/x``.
"""
def atanh(x: SupportsFloat, /) -> float:
"""
Return the inverse hyperbolic tangent of ``x``.
"""
def ceil(x: SupportsFloat, /) -> int:
"""
Return an integer, being ``x`` rounded towards positive infinity.
"""
def copysign(x: SupportsFloat, y: SupportsFloat, /) -> float:
"""
Return ``x`` with the sign of ``y``.
"""
def cos(x: SupportsFloat, /) -> float:
"""
Return the cosine of ``x``.
"""
def cosh(x: SupportsFloat, /) -> float:
"""
Return the hyperbolic cosine of ``x``.
"""
def degrees(x: SupportsFloat, /) -> float:
"""
Return radians ``x`` converted to degrees.
"""
def erf(x: SupportsFloat, /) -> float:
"""
Return the error function of ``x``.
"""
def erfc(x: SupportsFloat, /) -> float:
"""
Return the complementary error function of ``x``.
"""
def exp(x: SupportsFloat, /) -> float:
"""
Return the exponential of ``x``.
"""
def expm1(x: SupportsFloat, /) -> float:
"""
Return ``exp(x) - 1``.
"""
def fabs(x: SupportsFloat, /) -> float:
"""
Return the absolute value of ``x``.
"""
def floor(x: SupportsFloat, /) -> int:
"""
Return an integer, being ``x`` rounded towards negative infinity.
"""
def fmod(x: SupportsFloat, y: SupportsFloat, /) -> float:
"""
Return the remainder of ``x/y``.
"""
def frexp(x: SupportsFloat, /) -> tuple[float, int]:
"""
Decomposes a floating-point number into its mantissa and exponent.
The returned value is the tuple ``(m, e)`` such that ``x == m * 2**e``
exactly. If ``x == 0`` then the function returns ``(0.0, 0)``, otherwise
the relation ``0.5 <= abs(m) < 1`` holds.
"""
def gamma(x: SupportsFloat, /) -> float:
"""
Return the gamma function of ``x``.
"""
def isfinite(x: SupportsFloat, /) -> bool:
"""
Return ``True`` if ``x`` is finite.
"""
def isinf(x: SupportsFloat, /) -> bool:
"""
Return ``True`` if ``x`` is infinite.
"""
def isnan(x: SupportsFloat, /) -> bool:
"""
Return ``True`` if ``x`` is not-a-number
"""
# noinspection PyShadowingNames
def ldexp(x: SupportsFloat, exp: int, /) -> float:
"""
Return ``x * (2**exp)``.
"""
def lgamma(x: SupportsFloat, /) -> float:
"""
Return the natural logarithm of the gamma function of ``x``.
"""
def log(x: SupportsFloat, /) -> float:
"""
Return the natural logarithm of ``x``.
"""
def log10(x: SupportsFloat, /) -> float:
"""
Return the base-10 logarithm of ``x``.
"""
def log2(x: SupportsFloat, /) -> float:
"""
Return the base-2 logarithm of ``x``.
"""
def modf(x: SupportsFloat, /) -> tuple[float, float]:
"""
Return a tuple of two floats, being the fractional and integral parts of
``x``. Both return values have the same sign as ``x``.
"""
def pow(x: SupportsFloat, y: SupportsFloat, /) -> float:
"""
Returns ``x`` to the power of ``y``.
"""
def radians(x: SupportsFloat, /) -> float:
"""
Return degrees ``x`` converted to radians.
"""
def sin(x: SupportsFloat, /) -> float:
"""
Return the sine of ``x``.
"""
def sinh(x: SupportsFloat, /) -> float:
"""
Return the hyperbolic sine of ``x``.
"""
def sqrt(x: SupportsFloat, /) -> float:
"""
Return the square root of ``x``.
"""
def tan(x: SupportsFloat, /) -> float:
"""
Return the tangent of ``x``.
"""
def tanh(x: SupportsFloat, /) -> float:
"""
Return the hyperbolic tangent of ``x``.
"""
def trunc(x: SupportsFloat, /) -> float:
"""
Return an integer, being ``x`` rounded towards 0.
"""
e: Final[float] = ...
"""
base of the natural logarithm
"""
pi: Final[float] = ...
"""
the ratio of a circle's circumference to its diameter
"""
================================================
FILE: typehints/stdlib/os.pyi
================================================
"""
basic "operating system" services.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/os.rst.
==============================================
.. module:: os
:synopsis: basic "operating system" services
|see_cpython_module| :mod:`python:os`.
The ``os`` module contains functions for filesystem access and mounting,
terminal redirection and duplication, and the ``uname`` and ``urandom``
functions.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from abc import abstractmethod
from typing import Final, TypeVar, runtime_checkable, Protocol, overload, Literal
from uio import IOBase
_StrOrBytesT: Final = TypeVar("_StrOrBytesT", str, bytes)
class _PathLike(Protocol[_StrOrBytesT]):
@abstractmethod
def __fspath__(self) -> _StrOrBytesT:
"""Return the file system path representation of the object, preferably as a `str`."""
_AnyPath: Final = str | bytes | _PathLike[str] | _PathLike[bytes]
_FdOrAnyPath: Final = int | _AnyPath
def uname() -> tuple[str, str, str, str, str]:
"""
Return a tuple (possibly a named tuple) containing information about the
underlying machine and/or its operating system. The tuple has five fields
in the following order, each of them being a string:
* ``sysname`` -- the name of the underlying system
* ``nodename`` -- the network name (can be the same as ``sysname``)
* ``release`` -- the version of the underlying system
* ``version`` -- the MicroPython version and build date
* ``machine`` -- an identifier for the underlying hardware (eg board, CPU)
"""
def urandom(n: int, /) -> bytes:
"""
Return a bytes object with *n* random bytes. Whenever possible, it is
generated by the hardware random number generator.
"""
def chdir(path: _FdOrAnyPath, /) -> None:
"""
Change current directory.
"""
def getcwd() -> str:
"""
Get the current directory.
"""
@overload
def ilistdir() -> list[tuple[str, int, int] | tuple[str, int, int, int]]:
"""
This function returns an iterator which then yields tuples corresponding to
the entries in the directory that it is listing. With no argument it lists the
current directory, otherwise it lists the directory given by *dir*.
The tuples have the form *(name, type, inode[, size])*:
- *name* is a string (or bytes if *dir* is a bytes object) and is the name of
the entry;
- *type* is an integer that specifies the type of the entry, with 0x4000 for
directories and 0x8000 for regular files;
- *inode* is an integer corresponding to the inode of the file, and may be 0
for filesystems that don't have such a notion.
- Some platforms may return a 4-tuple that includes the entry's *size*. For
file entries, *size* is an integer representing the size of the file
or -1 if unknown. Its meaning is currently undefined for directory
entries.
"""
@overload
def ilistdir(dir: int, /) -> list[tuple[str, int, int] | tuple[str, int, int, int]]:
"""
This function returns an iterator which then yields tuples corresponding to
the entries in the directory that it is listing. With no argument it lists the
current directory, otherwise it lists the directory given by *dir*.
The tuples have the form *(name, type, inode[, size])*:
- *name* is a string (or bytes if *dir* is a bytes object) and is the name of
the entry;
- *type* is an integer that specifies the type of the entry, with 0x4000 for
directories and 0x8000 for regular files;
- *inode* is an integer corresponding to the inode of the file, and may be 0
for filesystems that don't have such a notion.
- Some platforms may return a 4-tuple that includes the entry's *size*. For
file entries, *size* is an integer representing the size of the file
or -1 if unknown. Its meaning is currently undefined for directory
entries.
"""
@overload
def ilistdir(dir: str, /) -> list[tuple[str, int, int] | tuple[str, int, int, int]]:
"""
This function returns an iterator which then yields tuples corresponding to
the entries in the directory that it is listing. With no argument it lists the
current directory, otherwise it lists the directory given by *dir*.
The tuples have the form *(name, type, inode[, size])*:
- *name* is a string (or bytes if *dir* is a bytes object) and is the name of
the entry;
- *type* is an integer that specifies the type of the entry, with 0x4000 for
directories and 0x8000 for regular files;
- *inode* is an integer corresponding to the inode of the file, and may be 0
for filesystems that don't have such a notion.
- Some platforms may return a 4-tuple that includes the entry's *size*. For
file entries, *size* is an integer representing the size of the file
or -1 if unknown. Its meaning is currently undefined for directory
entries.
"""
@overload
def ilistdir(
dir: bytes, /
) -> list[tuple[bytes, int, int] | tuple[bytes, int, int, int]]:
"""
This function returns an iterator which then yields tuples corresponding to
the entries in the directory that it is listing. With no argument it lists the
current directory, otherwise it lists the directory given by *dir*.
The tuples have the form *(name, type, inode[, size])*:
- *name* is a string (or bytes if *dir* is a bytes object) and is the name of
the entry;
- *type* is an integer that specifies the type of the entry, with 0x4000 for
directories and 0x8000 for regular files;
- *inode* is an integer corresponding to the inode of the file, and may be 0
for filesystems that don't have such a notion.
- Some platforms may return a 4-tuple that includes the entry's *size*. For
file entries, *size* is an integer representing the size of the file
or -1 if unknown. Its meaning is currently undefined for directory
entries.
"""
@overload
def ilistdir(
dir: _PathLike[str], /
) -> list[tuple[str, int, int] | tuple[str, int, int, int]]:
"""
This function returns an iterator which then yields tuples corresponding to
the entries in the directory that it is listing. With no argument it lists the
current directory, otherwise it lists the directory given by *dir*.
The tuples have the form *(name, type, inode[, size])*:
- *name* is a string (or bytes if *dir* is a bytes object) and is the name of
the entry;
- *type* is an integer that specifies the type of the entry, with 0x4000 for
directories and 0x8000 for regular files;
- *inode* is an integer corresponding to the inode of the file, and may be 0
for filesystems that don't have such a notion.
- Some platforms may return a 4-tuple that includes the entry's *size*. For
file entries, *size* is an integer representing the size of the file
or -1 if unknown. Its meaning is currently undefined for directory
entries.
"""
@overload
def ilistdir(
dir: _PathLike[bytes], /
) -> list[tuple[bytes, int, int] | tuple[bytes, int, int, int]]:
"""
This function returns an iterator which then yields tuples corresponding to
the entries in the directory that it is listing. With no argument it lists the
current directory, otherwise it lists the directory given by *dir*.
The tuples have the form *(name, type, inode[, size])*:
- *name* is a string (or bytes if *dir* is a bytes object) and is the name of
the entry;
- *type* is an integer that specifies the type of the entry, with 0x4000 for
directories and 0x8000 for regular files;
- *inode* is an integer corresponding to the inode of the file, and may be 0
for filesystems that don't have such a notion.
- Some platforms may return a 4-tuple that includes the entry's *size*. For
file entries, *size* is an integer representing the size of the file
or -1 if unknown. Its meaning is currently undefined for directory
entries.
"""
@overload
def listdir() -> list[str]:
"""
With no argument, list the current directory. Otherwise list the given directory.
"""
@overload
def listdir(dir: int, /) -> list[str]:
"""
With no argument, list the current directory. Otherwise list the given directory.
"""
@overload
def listdir(dir: str, /) -> list[str]:
"""
With no argument, list the current directory. Otherwise list the given directory.
"""
@overload
def listdir(dir: bytes, /) -> list[bytes]:
"""
With no argument, list the current directory. Otherwise list the given directory.
"""
@overload
def listdir(dir: _PathLike[str], /) -> list[str]:
"""
With no argument, list the current directory. Otherwise list the given directory.
"""
@overload
def listdir(dir: _PathLike[bytes], /) -> list[bytes]:
"""
With no argument, list the current directory. Otherwise list the given directory.
"""
def mkdir(path: _AnyPath, /) -> None:
"""
Create a new directory.
"""
def remove(path: _AnyPath, /) -> None:
"""
Remove a file.
"""
def rmdir(path: _AnyPath, /) -> None:
"""
Remove a directory.
"""
def rename(old_path: _AnyPath, new_path: _AnyPath, /) -> None:
"""
Rename a file.
"""
def stat(
path: _FdOrAnyPath, /
) -> tuple[int, int, int, int, int, int, int, int, int, int]:
"""
Get the status of a file or directory.
"""
def statvfs(
path: _FdOrAnyPath, /
) -> tuple[int, int, int, int, int, int, int, int, int, int]:
"""
Get the status of a fileystem.
Returns a tuple with the filesystem information in the following order:
* ``f_bsize`` -- file system block size
* ``f_frsize`` -- fragment size
* ``f_blocks`` -- size of fs in f_frsize units
* ``f_bfree`` -- number of free blocks
* ``f_bavail`` -- number of free blocks for unprivileged users
* ``f_files`` -- number of inodes
* ``f_ffree`` -- number of free inodes
* ``f_favail`` -- number of free inodes for unprivileged users
* ``f_flag`` -- mount flags
* ``f_namemax`` -- maximum filename length
Parameters related to inodes: ``f_files``, ``f_ffree``, ``f_avail``
and the ``f_flags`` parameter may return ``0`` as they can be unavailable
in a port-specific implementation.
"""
def sync() -> None:
"""
Sync all filesystems.
"""
def dupterm(stream_object: IOBase | None, index: int = 0, /) -> IOBase | None:
"""
Duplicate or switch the MicroPython terminal (the REPL) on the given `stream`-like
object. The *stream_object* argument must be a native stream object, or derive
from ``io.IOBase`` and implement the ``readinto()`` and
``write()`` methods. The stream should be in non-blocking mode and
``readinto()`` should return ``None`` if there is no data available for reading.
After calling this function all terminal output is repeated on this stream,
and any input that is available on the stream is passed on to the terminal input.
The *index* parameter should be a non-negative integer and specifies which
duplication slot is set. A given port may implement more than one slot (slot 0
will always be available) and in that case terminal input and output is
duplicated on all the slots that are set.
If ``None`` is passed as the *stream_object* then duplication is cancelled on
the slot given by *index*.
The function returns the previous stream-like object in the given slot.
"""
def mount(
fsobj: "AbstractBlockDev", mount_point: str, /, *, readonly: bool = False
) -> IOBase | None:
"""
Mount the filesystem object *fsobj* at the location in the VFS given by the
*mount_point* string. *fsobj* can be a a VFS object that has a ``mount()``
method, or a block device. If it's a block device then the filesystem type
is automatically detected (an exception is raised if no filesystem was
recognised). *mount_point* may be ``'/'`` to mount *fsobj* at the root,
or ``'/'`` to mount it at a subdirectory under the root.
If *readonly* is ``True`` then the filesystem is mounted read-only.
During the mount process the method ``mount()`` is called on the filesystem
object.
Will raise ``OSError(EPERM)`` if *mount_point* is already mounted.
Filesystem mounting
-------------------
Some ports provide a Virtual Filesystem (VFS) and the ability to mount multiple
"real" filesystems within this VFS. Filesystem objects can be mounted at either
the root of the VFS, or at a subdirectory that lives in the root. This allows
dynamic and flexible configuration of the filesystem that is seen by Python
programs. Ports that have this functionality provide the :func:`mount` and
:func:`umount` functions, and possibly various filesystem implementations
represented by VFS classes.
"""
def umount(mount_point: str, /) -> None:
"""
Unmount a filesystem. *mount_point* can be a string naming the mount location,
or a previously-mounted filesystem object. During the unmount process the
method ``umount()`` is called on the filesystem object.
Will raise ``OSError(EINVAL)`` if *mount_point* is not found.
"""
class VfsFat("AbstractBlockDev"):
"""
"""
def __init__(self, block_dev: "AbstractBlockDev", /):
"""
Create a filesystem object that uses the FAT filesystem format. Storage of
the FAT filesystem is provided by *block_dev*.
Objects created by this constructor can be mounted using :func:`mount`.
"""
@staticmethod
def mkfs(block_dev: "AbstractBlockDev", /) -> None:
"""
Build a FAT filesystem on *block_dev*.
"""
class VfsLfs1("AbstractBlockDev"):
"""
"""
def __init__(
self,
block_dev: "AbstractBlockDev",
readsize: int = 32,
progsize: int = 32,
lookahead: int = 32,
/,
):
"""
Create a filesystem object that uses the `littlefs v1 filesystem format`_.
Storage of the littlefs filesystem is provided by *block_dev*, which must
support the :ref:`extended interface `.
Objects created by this constructor can be mounted using :func:`mount`.
See :ref:`filesystem` for more information.
"""
@staticmethod
def mkfs(
block_dev: "AbstractBlockDev",
readsize: int = 32,
progsize: int = 32,
lookahead: int = 32,
/,
) -> None:
"""
Build a Lfs1 filesystem on *block_dev*.
.. note:: There are reports of littlefs v1 failing in certain situations,
for details see `littlefs issue 347`_.
"""
class VfsLfs2("AbstractBlockDev"):
"""
"""
def __init__(
self,
block_dev: "AbstractBlockDev",
readsize: int = 32,
progsize: int = 32,
lookahead: int = 32,
mtime: bool = True,
/,
):
"""
Create a filesystem object that uses the `littlefs v2 filesystem format`_.
Storage of the littlefs filesystem is provided by *block_dev*, which must
support the :ref:`extended interface `.
Objects created by this constructor can be mounted using :func:`mount`.
The *mtime* argument enables modification timestamps for files, stored using
littlefs attributes. This option can be disabled or enabled differently each
mount time and timestamps will only be added or updated if *mtime* is enabled,
otherwise the timestamps will remain untouched. Littlefs v2 filesystems without
timestamps will work without reformatting and timestamps will be added
transparently to existing files once they are opened for writing. When *mtime*
is enabled `os.stat` on files without timestamps will return 0 for the timestamp.
See :ref:`filesystem` for more information.
"""
@staticmethod
def mkfs(
block_dev: "AbstractBlockDev",
readsize: int = 32,
progsize: int = 32,
lookahead: int = 32,
mtime: bool = True,
/,
) -> None:
"""
Build a Lfs2 filesystem on *block_dev*.
.. note:: There are reports of littlefs v2 failing in certain situations,
for details see `littlefs issue 295`_.
"""
@runtime_checkable
class AbstractBlockDev(Protocol):
"""
Block devices
-------------
A block device is an object which implements the block protocol. This enables a
device to support MicroPython filesystems. The physical hardware is represented
by a user defined class. The :class:`AbstractBlockDev` class is a template for
the design of such a class: MicroPython does not actually provide that class,
but an actual block device class must implement the methods described below.
A concrete implementation of this class will usually allow access to the
memory-like functionality of a piece of hardware (like flash memory). A block
device can be formatted to any supported filesystem and mounted using ``os``
methods.
See :ref:`filesystem` for example implementations of block devices using the
two variants of the block protocol described below.
.. _block-device-interface:
Simple and extended interface
.............................
There are two compatible signatures for the ``readblocks`` and ``writeblocks``
methods (see below), in order to support a variety of use cases. A given block
device may implement one form or the other, or both at the same time. The second
form (with the offset parameter) is referred to as the "extended interface".
Some filesystems (such as littlefs) that require more control over write
operations, for example writing to sub-block regions without erasing, may require
that the block device supports the extended interface.
"""
def __init__(self):
"""
Construct a block device object. The parameters to the constructor are
dependent on the specific block device.
"""
@overload
def readblocks(self, block_num: int, buf: bytearray, /) -> None:
"""
The first form reads aligned, multiples of blocks.
Starting at the block given by the index *block_num*, read blocks from
the device into *buf* (an array of bytes).
The number of blocks to read is given by the length of *buf*,
which will be a multiple of the block size.
The second form allows reading at arbitrary locations within a block,
and arbitrary lengths.
Starting at block index *block_num*, and byte offset within that block
of *offset*, read bytes from the device into *buf* (an array of bytes).
The number of bytes to read is given by the length of *buf*.
"""
@overload
def readblocks(self, block_num: int, buf: bytearray, offset: int, /) -> None:
"""
The first form reads aligned, multiples of blocks.
Starting at the block given by the index *block_num*, read blocks from
the device into *buf* (an array of bytes).
The number of blocks to read is given by the length of *buf*,
which will be a multiple of the block size.
The second form allows reading at arbitrary locations within a block,
and arbitrary lengths.
Starting at block index *block_num*, and byte offset within that block
of *offset*, read bytes from the device into *buf* (an array of bytes).
The number of bytes to read is given by the length of *buf*.
"""
@overload
def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None:
"""
The first form writes aligned, multiples of blocks, and requires that the
blocks that are written to be first erased (if necessary) by this method.
Starting at the block given by the index *block_num*, write blocks from
*buf* (an array of bytes) to the device.
The number of blocks to write is given by the length of *buf*,
which will be a multiple of the block size.
The second form allows writing at arbitrary locations within a block,
and arbitrary lengths. Only the bytes being written should be changed,
and the caller of this method must ensure that the relevant blocks are
erased via a prior ``ioctl`` call.
Starting at block index *block_num*, and byte offset within that block
of *offset*, write bytes from *buf* (an array of bytes) to the device.
The number of bytes to write is given by the length of *buf*.
Note that implementations must never implicitly erase blocks if the offset
argument is specified, even if it is zero.
"""
@overload
def writeblocks(
self, block_num: int, buf: bytes | bytearray, offset: int, /
) -> None:
"""
The first form writes aligned, multiples of blocks, and requires that the
blocks that are written to be first erased (if necessary) by this method.
Starting at the block given by the index *block_num*, write blocks from
*buf* (an array of bytes) to the device.
The number of blocks to write is given by the length of *buf*,
which will be a multiple of the block size.
The second form allows writing at arbitrary locations within a block,
and arbitrary lengths. Only the bytes being written should be changed,
and the caller of this method must ensure that the relevant blocks are
erased via a prior ``ioctl`` call.
Starting at block index *block_num*, and byte offset within that block
of *offset*, write bytes from *buf* (an array of bytes) to the device.
The number of bytes to write is given by the length of *buf*.
Note that implementations must never implicitly erase blocks if the offset
argument is specified, even if it is zero.
"""
@overload
def ioctl(self, op: int, arg: int) -> int | None:
"""
Control the block device and query its parameters. The operation to
perform is given by *op* which is one of the following integers:
- 1 -- initialise the device (*arg* is unused)
- 2 -- shutdown the device (*arg* is unused)
- 3 -- sync the device (*arg* is unused)
- 4 -- get a count of the number of blocks, should return an integer
(*arg* is unused)
- 5 -- get the number of bytes in a block, should return an integer,
or ``None`` in which case the default value of 512 is used
(*arg* is unused)
- 6 -- erase a block, *arg* is the block number to erase
As a minimum ``ioctl(4, ...)`` must be intercepted; for littlefs
``ioctl(6, ...)`` must also be intercepted. The need for others is
hardware dependent.
Prior to any call to ``writeblocks(block, ...)`` littlefs issues
``ioctl(6, block)``. This enables a device driver to erase the block
prior to a write if the hardware requires it. Alternatively a driver
might intercept ``ioctl(6, block)`` and return 0 (success). In this case
the driver assumes responsibility for detecting the need for erasure.
Unless otherwise stated ``ioctl(op, arg)`` can return ``None``.
Consequently an implementation can ignore unused values of ``op``. Where
``op`` is intercepted, the return value for operations 4 and 5 are as
detailed above. Other operations should return 0 on success and non-zero
for failure, with the value returned being an ``OSError`` errno code.
"""
@overload
def ioctl(self, op: Literal[4, 5], arg: int) -> int:
"""
Control the block device and query its parameters. The operation to
perform is given by *op* which is one of the following integers:
- 1 -- initialise the device (*arg* is unused)
- 2 -- shutdown the device (*arg* is unused)
- 3 -- sync the device (*arg* is unused)
- 4 -- get a count of the number of blocks, should return an integer
(*arg* is unused)
- 5 -- get the number of bytes in a block, should return an integer,
or ``None`` in which case the default value of 512 is used
(*arg* is unused)
- 6 -- erase a block, *arg* is the block number to erase
As a minimum ``ioctl(4, ...)`` must be intercepted; for littlefs
``ioctl(6, ...)`` must also be intercepted. The need for others is
hardware dependent.
Prior to any call to ``writeblocks(block, ...)`` littlefs issues
``ioctl(6, block)``. This enables a device driver to erase the block
prior to a write if the hardware requires it. Alternatively a driver
might intercept ``ioctl(6, block)`` and return 0 (success). In this case
the driver assumes responsibility for detecting the need for erasure.
Unless otherwise stated ``ioctl(op, arg)`` can return ``None``.
Consequently an implementation can ignore unused values of ``op``. Where
``op`` is intercepted, the return value for operations 4 and 5 are as
detailed above. Other operations should return 0 on success and non-zero
for failure, with the value returned being an ``OSError`` errno code.
"""
@overload
def ioctl(self, op: Literal[1, 2, 3, 6], arg: int) -> int | None:
"""
Control the block device and query its parameters. The operation to
perform is given by *op* which is one of the following integers:
- 1 -- initialise the device (*arg* is unused)
- 2 -- shutdown the device (*arg* is unused)
- 3 -- sync the device (*arg* is unused)
- 4 -- get a count of the number of blocks, should return an integer
(*arg* is unused)
- 5 -- get the number of bytes in a block, should return an integer,
or ``None`` in which case the default value of 512 is used
(*arg* is unused)
- 6 -- erase a block, *arg* is the block number to erase
As a minimum ``ioctl(4, ...)`` must be intercepted; for littlefs
``ioctl(6, ...)`` must also be intercepted. The need for others is
hardware dependent.
Prior to any call to ``writeblocks(block, ...)`` littlefs issues
``ioctl(6, block)``. This enables a device driver to erase the block
prior to a write if the hardware requires it. Alternatively a driver
might intercept ``ioctl(6, block)`` and return 0 (success). In this case
the driver assumes responsibility for detecting the need for erasure.
Unless otherwise stated ``ioctl(op, arg)`` can return ``None``.
Consequently an implementation can ignore unused values of ``op``. Where
``op`` is intercepted, the return value for operations 4 and 5 are as
detailed above. Other operations should return 0 on success and non-zero
for failure, with the value returned being an ``OSError`` errno code.
"""
================================================
FILE: typehints/stdlib/re.pyi
================================================
"""
regular expressions.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/re.rst.
=======================================
.. module:: re
:synopsis: regular expressions
|see_cpython_module| :mod:`python:re`.
This module implements regular expression operations. Regular expression
syntax supported is a subset of CPython ``re`` module (and actually is
a subset of POSIX extended regular expressions).
Supported operators and special sequences are:
``.``
Match any character.
``[...]``
Match set of characters. Individual characters and ranges are supported,
including negated sets (e.g. ``[^a-c]``).
``^``
Match the start of the string.
``$``
Match the end of the string.
``?``
Match zero or one of the previous sub-pattern.
``*``
Match zero or more of the previous sub-pattern.
``+``
Match one or more of the previous sub-pattern.
``??``
Non-greedy version of ``?``, match zero or one, with the preference
for zero.
``*?``
Non-greedy version of ``*``, match zero or more, with the preference
for the shortest match.
``+?``
Non-greedy version of ``+``, match one or more, with the preference
for the shortest match.
``|``
Match either the left-hand side or the right-hand side sub-patterns of
this operator.
``(...)``
Grouping. Each group is capturing (a substring it captures can be accessed
with `match.group()` method).
``\d``
Matches digit. Equivalent to ``[0-9]``.
``\D``
Matches non-digit. Equivalent to ``[^0-9]``.
``\s``
Matches whitespace. Equivalent to ``[ \t-\r]``.
``\S``
Matches non-whitespace. Equivalent to ``[^ \t-\r]``.
``\w``
Matches "word characters" (ASCII only). Equivalent to ``[A-Za-z0-9_]``.
``\W``
Matches non "word characters" (ASCII only). Equivalent to ``[^A-Za-z0-9_]``.
``\``
Escape character. Any other character following the backslash, except
for those listed above, is taken literally. For example, ``\*`` is
equivalent to literal ``*`` (not treated as the ``*`` operator).
Note that ``\r``, ``\n``, etc. are not handled specially, and will be
equivalent to literal letters ``r``, ``n``, etc. Due to this, it's
not recommended to use raw Python strings (``r""``) for regular
expressions. For example, ``r"\r\n"`` when used as the regular
expression is equivalent to ``"rn"``. To match CR character followed
by LF, use ``"\r\n"``.
**NOT SUPPORTED**:
* counted repetitions (``{m,n}``)
* named groups (``(?P...)``)
* non-capturing groups (``(?:...)``)
* more advanced assertions (``\b``, ``\B``)
* special character escapes like ``\r``, ``\n`` - use Python's own escaping
instead
* etc.
Example::
import re
# As re doesn't support escapes itself, use of r"" strings is not
# recommended.
regex = re.compile("[\r\n]")
regex.split("line1\rline2\nline3\r\n")
# Result:
# ['line1', 'line2', 'line3', '', '']
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import AnyStr, Callable, Generic, Final, Any
_StrLike: Final = str | bytes
def compile(regex_str: _StrLike, flags: int = ..., /) -> "ure":
"""
Compile regular expression, return `regex ` object.
"""
def match(regex_str: _StrLike, string: AnyStr, /) -> "Match[AnyStr]":
"""
Compile *regex_str* and match against *string*. Match always happens
from starting position in a string.
"""
def search(regex_str: _StrLike, string: AnyStr, /) -> "Match[AnyStr]":
"""
Compile *regex_str* and search it in a *string*. Unlike `match`, this will search
string for first position which matches regex (which still may be
0 if regex is anchored).
"""
def sub(
regex_str: _StrLike,
replace: AnyStr | Callable[["Match[AnyStr]"], AnyStr],
string: AnyStr,
count: int = 0,
flags: int = 0,
/,
) -> AnyStr:
"""
Compile *regex_str* and search for it in *string*, replacing all matches
with *replace*, and returning the new string.
*replace* can be a string or a function. If it is a string then escape
sequences of the form ``\`` and ``\g`` can be used to
expand to the corresponding group (or an empty string for unmatched groups).
If *replace* is a function then it must take a single argument (the match)
and should return a replacement string.
If *count* is specified and non-zero then substitution will stop after
this many substitutions are made. The *flags* argument is ignored.
Note: availability of this function depends on :term:`MicroPython port`.
"""
DEBUG: Final[int] = ...
"""
Flag value, display debug information about compiled expression.
(Availability depends on :term:`MicroPython port`.)
"""
# noinspection PyPep8Naming
class ure:
"""
Compiled regular expression. Instances of this class are created using
`re.compile()`.
"""
def match(self, string: AnyStr, /) -> "Match[AnyStr]":
"""
Similar to the module-level functions :meth:`match`, :meth:`search`
and :meth:`sub`.
Using methods is (much) more efficient if the same regex is applied to
multiple strings.
"""
def search(self, string: AnyStr, /) -> "Match[AnyStr]":
"""
Similar to the module-level functions :meth:`match`, :meth:`search`
and :meth:`sub`.
Using methods is (much) more efficient if the same regex is applied to
multiple strings.
"""
def sub(
self,
replace: AnyStr | Callable[["Match[AnyStr]"], AnyStr],
string: AnyStr,
count: int = 0,
flags: int = 0,
/,
) -> AnyStr:
"""
Similar to the module-level functions :meth:`match`, :meth:`search`
and :meth:`sub`.
Using methods is (much) more efficient if the same regex is applied to
multiple strings.
"""
def split(self, string: AnyStr, max_split: int = -1, /) -> list[AnyStr]:
"""
Split a *string* using regex. If *max_split* is given, it specifies
maximum number of splits to perform. Returns list of strings (there
may be up to *max_split+1* elements if it's specified).
"""
class Match(Generic[AnyStr]):
"""
Match objects as returned by `match()` and `search()` methods, and passed
to the replacement function in `sub()`.
The name, `Match`, used for typing is not the same as the runtime name, `match` (note lowercase `m`).
The reason for this difference is that the runtime uses `match` as both a class name and as a method name and
this is not possible within code written entirely in Python and therefore not possible within typing code.
"""
def group(self, index: int, /) -> AnyStr:
"""
Return matching (sub)string. *index* is 0 for entire match,
1 and above for each capturing group. Only numeric groups are supported.
"""
def groups(self) -> tuple[AnyStr | Any, ...]:
"""
Return a tuple containing all the substrings of the groups of the match.
Note: availability of this method depends on :term:`MicroPython port`.
"""
def start(self, index: int = ..., /) -> int:
"""
Return the index in the original string of the start or end of the
substring group that was matched. *index* defaults to the entire
group, otherwise it will select a group.
Note: availability of these methods depends on :term:`MicroPython port`.
"""
def end(self, index: int = ..., /) -> int:
"""
Return the index in the original string of the start or end of the
substring group that was matched. *index* defaults to the entire
group, otherwise it will select a group.
Note: availability of these methods depends on :term:`MicroPython port`.
"""
def span(self, index: int = ..., /) -> tuple[int, int]:
"""
Returns the 2-tuple ``(match.start(index), match.end(index))``.
Note: availability of this method depends on :term:`MicroPython port`.
"""
================================================
FILE: typehints/stdlib/select.pyi
================================================
"""
wait for events on a set of streams.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/select.rst.
====================================================
.. module:: select
:synopsis: wait for events on a set of streams
|see_cpython_module| :mod:`python:select`.
This module provides functions to efficiently wait for events on multiple
`streams ` (select streams which are ready for operations).
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import Iterable, Any, Final, Iterator
from uio import IOBase
POLLIN: Final[int] = ...
"""Data available for reading."""
POLLOUT: Final[int] = ...
"""More data can be written."""
POLLHUP: Final[int] = ...
"""Socket is no longer connected."""
POLLERR: Final[int] = ...
"""Socket got an asynchronous error."""
def poll() -> "Poll":
"""
Create an instance of the Poll class.
"""
def select(
rlist: Iterable[Any],
wlist: Iterable[Any],
xlist: Iterable[Any],
timeout: int = -1,
/,
) -> list[tuple[Any, int, Any, ...]]:
"""
Wait for activity on a set of objects.
This function is provided by some MicroPython ports for compatibility
and is not efficient. Usage of :class:`Poll` is recommended instead.
"""
class Poll:
"""
The name, `Poll`, used for typing is not the same as the runtime name, `poll` (note lowercase `p`).
The reason for this difference is that the runtime uses `poll` as both a class name and as a method name and
this is not possible within code written entirely in Python and therefore not possible within typing code.
"""
def register(self, obj: IOBase, eventmask: int = POLLIN | POLLOUT, /) -> None:
"""
Register `stream` *obj* for polling. *eventmask* is logical OR of:
* ``select.POLLIN`` - data available for reading
* ``select.POLLOUT`` - more data can be written
Note that flags like ``select.POLLHUP`` and ``select.POLLERR`` are
*not* valid as input eventmask (these are unsolicited events which
will be returned from `poll()` regardless of whether they are asked
for). This semantics is per POSIX.
*eventmask* defaults to ``select.POLLIN | select.POLLOUT``.
It is OK to call this function multiple times for the same *obj*.
Successive calls will update *obj*'s eventmask to the value of
*eventmask* (i.e. will behave as `modify()`).
"""
def unregister(self, obj: IOBase, /) -> None:
"""
Unregister *obj* from polling.
"""
def modify(self, obj: IOBase, eventmask: int, /) -> None:
"""
Modify the *eventmask* for *obj*. If *obj* is not registered, `OSError`
is raised with error of ENOENT.
"""
def poll(self, timeout: int = -1, /) -> list[tuple[Any, int, Any, ...]]:
"""
Wait for at least one of the registered objects to become ready or have an
exceptional condition, with optional timeout in milliseconds (if *timeout*
arg is not specified or -1, there is no timeout).
Returns list of (``obj``, ``event``, ...) tuples. There may be other elements in
tuple, depending on a platform and version, so don't assume that its size is 2.
The ``event`` element specifies which events happened with a stream and
is a combination of ``select.POLL*`` constants described above. Note that
flags ``select.POLLHUP`` and ``select.POLLERR`` can be returned at any time
(even if were not asked for), and must be acted on accordingly (the
corresponding stream unregistered from poll and likely closed), because
otherwise all further invocations of `poll()` may return immediately with
these flags set for this stream again.
In case of timeout, an empty list is returned.
.. admonition:: Difference to CPython
:class: attention
Tuples returned may contain more than 2 elements as described above.
"""
def ipoll(
self, timeout: int = -1, flags: int = 0, /
) -> Iterator[tuple[Any, int, Any, ...]]:
"""
Like :meth:`poll.poll`, but instead returns an iterator which yields a
`callee-owned tuple`. This function provides an efficient, allocation-free
way to poll on streams.
If *flags* is 1, one-shot behaviour for events is employed: streams for
which events happened will have their event masks automatically reset
(equivalent to ``poll.modify(obj, 0)``), so new events for such a stream
won't be processed until new mask is set with `poll.modify()`. This
behaviour is useful for asynchronous I/O schedulers.
.. admonition:: Difference to CPython
:class: attention
This function is a MicroPython extension.
"""
================================================
FILE: typehints/stdlib/socket.pyi
================================================
"""
socket.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/socket.rst.
******************************
.. module:: socket
:synopsis: socket module
|see_cpython_module| :mod:`python:socket`.
This module provides access to the BSD socket interface.
.. admonition:: Difference to CPython
:class: attention
For efficiency and consistency, socket objects in MicroPython implement a `stream`
(file-like) interface directly. In CPython, you need to convert a socket to
a file-like object using `makefile()` method. This method is still supported
by MicroPython (but is a no-op), so where compatibility with CPython matters,
be sure to use it.
Socket address format(s)
------------------------
The native socket address format of the ``socket`` module is an opaque data type
returned by `getaddrinfo` function, which must be used to resolve textual address
(including numeric addresses)::
sockaddr = socket.getaddrinfo('www.micropython.org', 80)[0][-1]
# You must use getaddrinfo() even for numeric addresses
sockaddr = socket.getaddrinfo('127.0.0.1', 80)[0][-1]
# Now you can use that address
sock.connect(addr)
Using `getaddrinfo` is the most efficient (both in terms of memory and processing
power) and portable way to work with addresses.
However, ``socket`` module (note the difference with native MicroPython
``socket`` module described here) provides CPython-compatible way to specify
addresses using tuples, as described below. Note that depending on a
:term:`MicroPython port`, ``socket`` module can be builtin or need to be
installed from `micropython-lib` (as in the case of :term:`MicroPython Unix port`),
and some ports still accept only numeric addresses in the tuple format,
and require to use `getaddrinfo` function to resolve domain names.
Summing up:
* Always use `getaddrinfo` when writing portable applications.
* Tuple addresses described below can be used as a shortcut for
quick hacks and interactive use, if your port supports them.
Tuple address format for ``socket`` module:
* IPv4: *(ipv4_address, port)*, where *ipv4_address* is a string with
dot-notation numeric IPv4 address, e.g. ``"8.8.8.8"``, and *port* is and
integer port number in the range 1-65535. Note the domain names are not
accepted as *ipv4_address*, they should be resolved first using
`socket.getaddrinfo()`.
* IPv6: *(ipv6_address, port, flowinfo, scopeid)*, where *ipv6_address*
is a string with colon-notation numeric IPv6 address, e.g. ``"2001:db8::1"``,
and *port* is an integer port number in the range 1-65535. *flowinfo*
must be 0. *scopeid* is the interface scope identifier for link-local
addresses. Note the domain names are not accepted as *ipv6_address*,
they should be resolved first using `socket.getaddrinfo()`. Availability
of IPv6 support depends on a :term:`MicroPython port`.
.. exception:: socket.error
MicroPython does NOT have this exception.
.. admonition:: Difference to CPython
:class: attention
CPython used to have a ``socket.error`` exception which is now deprecated,
and is an alias of `OSError`. In MicroPython, use `OSError` directly.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import Final, Any, Literal, overload
from uio import AnyReadableBuf, AnyWritableBuf
_Address: Final = tuple[str, int] | tuple[str, int, int, int] | str
def socket(
af: int = "AF_INET", type: int = "SOCK_STREAM", proto: int = "IPPROTO_TCP", /,
) -> "Socket":
"""
Create a new socket using the given address family, socket type and
protocol number. Note that specifying *proto* in most cases is not
required (and not recommended, as some MicroPython ports may omit
``IPPROTO_*`` constants). Instead, *type* argument will select needed
protocol automatically::
# Create STREAM TCP socket
socket(AF_INET, SOCK_STREAM)
# Create DGRAM UDP socket
socket(AF_INET, SOCK_DGRAM)
"""
def getaddrinfo(
host: str, port: int, af: int = 0, type: int = 0, proto: int = 0, flags: int = 0, /,
) -> list[tuple[int, int, int, str, tuple[str, int] | tuple[str, int, int, int]]]:
"""
Translate the host/port argument into a sequence of 5-tuples that contain all the
necessary arguments for creating a socket connected to that service. Arguments
*af*, *type*, and *proto* (which have the same meaning as for the `socket()` function)
can be used to filter which kind of addresses are returned. If a parameter is not
specified or zero, all combinations of addresses can be returned (requiring
filtering on the user side).
The resulting list of 5-tuples has the following structure::
(family, type, proto, canonname, sockaddr)
The following example shows how to connect to a given url::
s = socket.socket()
# This assumes that if "type" is not specified, an address for
# SOCK_STREAM will be returned, which may be not true
s.connect(socket.getaddrinfo('www.micropython.org', 80)[0][-1])
Recommended use of filtering params::
s = socket.socket()
# Guaranteed to return an address which can be connect'ed to for
# stream operation.
s.connect(socket.getaddrinfo('www.micropython.org', 80, 0, SOCK_STREAM)[0][-1])
.. admonition:: Difference to CPython
:class: attention
CPython raises a ``socket.gaierror`` exception (`OSError` subclass) in case
of error in this function. MicroPython doesn't have ``socket.gaierror``
and raises OSError directly. Note that error numbers of `getaddrinfo()`
form a separate namespace and may not match error numbers from
the :mod:`errno` module. To distinguish `getaddrinfo()` errors, they are
represented by negative numbers, whereas standard system errors are
positive numbers (error numbers are accessible using ``e.args[0]`` property
from an exception object). The use of negative values is a provisional
detail which may change in the future.
"""
def inet_ntop(af: int, bin_addr: bytes, /) -> str:
"""
Convert a binary network address *bin_addr* of the given address family *af*
to a textual representation::
>>> socket.inet_ntop(socket.AF_INET, b"\x7f\0\0\1")
'127.0.0.1'
"""
def inet_pton(af: int, txt_addr: str, /) -> bytes:
"""
Convert a textual network address *txt_addr* of the given address family *af*
to a binary representation::
>>> socket.inet_pton(socket.AF_INET, "1.2.3.4")
b'\x01\x02\x03\x04'
"""
AF_INET: Final[int] = ...
"""
Address family types. Availability depends on a particular :term:`MicroPython port`.
"""
AF_INET6: Final[int] = ...
"""
Address family types. Availability depends on a particular :term:`MicroPython port`.
"""
SOCK_STREAM: Final[int] = ...
"""
Socket types.
"""
SOCK_DGRAM: Final[int] = ...
"""
Socket types.
"""
IPPROTO_UDP: Final[int] = ...
"""
IP protocol numbers. Availability depends on a particular :term:`MicroPython port`.
Note that you don't need to specify these in a call to `socket.socket()`,
because `SOCK_STREAM` socket type automatically selects `IPPROTO_TCP`, and
`SOCK_DGRAM` - `IPPROTO_UDP`. Thus, the only real use of these constants
is as an argument to `setsockopt()`.
"""
IPPROTO_TCP: Final[int] = ...
"""
IP protocol numbers. Availability depends on a particular :term:`MicroPython port`.
Note that you don't need to specify these in a call to `socket.socket()`,
because `SOCK_STREAM` socket type automatically selects `IPPROTO_TCP`, and
`SOCK_DGRAM` - `IPPROTO_UDP`. Thus, the only real use of these constants
is as an argument to `setsockopt()`.
"""
SOL_SOCKET: Final[int] = ...
"""
Socket option levels (an argument to `setsockopt()`). The exact
inventory depends on a :term:`MicroPython port`.
"""
SO_REUSEADDR: Final[int] = ...
"""
Socket options (an argument to `setsockopt()`). The exact
inventory depends on a :term:`MicroPython port`.
"""
IPPROTO_SEC: Final[int] = ...
"""
Special protocol value to create SSL-compatible socket.
Constants specific to WiPy:
"""
class Socket:
"""
A unix like socket, for more information see module ``socket``'s description.
The name, `Socket`, used for typing is not the same as the runtime name, `socket` (note lowercase `s`).
The reason for this difference is that the runtime uses `socket` as both a class name and as a method name and
this is not possible within code written entirely in Python and therefore not possible within typing code.
"""
def close(self) -> None:
"""
Mark the socket closed and release all resources. Once that happens, all future operations
on the socket object will fail. The remote end will receive EOF indication if
supported by protocol.
Sockets are automatically closed when they are garbage-collected, but it is recommended
to `close()` them explicitly as soon you finished working with them.
"""
def bind(self, address: _Address | bytes, /) -> None:
"""
Bind the socket to *address*. The socket must not already be bound.
"""
def listen(self, backlog: int = ..., /) -> None:
"""
Enable a server to accept connections. If *backlog* is specified, it must be at least 0
(if it's lower, it will be set to 0); and specifies the number of unaccepted connections
that the system will allow before refusing new connections. If not specified, a default
reasonable value is chosen.
"""
def accept(self) -> None:
"""
Accept a connection. The socket must be bound to an address and listening for connections.
The return value is a pair (conn, address) where conn is a new socket object usable to send
and receive data on the connection, and address is the address bound to the socket on the
other end of the connection.
"""
def connect(self, address: _Address | bytes, /) -> None:
"""
Connect to a remote socket at *address*.
"""
def send(self, bytes: AnyReadableBuf, /) -> int:
"""
Send data to the socket. The socket must be connected to a remote socket.
Returns number of bytes sent, which may be smaller than the length of data
("short write").
"""
def sendall(self, bytes: AnyReadableBuf, /) -> None:
"""
Send all data to the socket. The socket must be connected to a remote socket.
Unlike `send()`, this method will try to send all of data, by sending data
chunk by chunk consecutively.
The behaviour of this method on non-blocking sockets is undefined. Due to this,
on MicroPython, it's recommended to use `write()` method instead, which
has the same "no short writes" policy for blocking sockets, and will return
number of bytes sent on non-blocking sockets.
"""
def recv(self, bufsize: int, /) -> bytes:
"""
Receive data from the socket. The return value is a bytes object representing the data
received. The maximum amount of data to be received at once is specified by bufsize.
"""
def sendto(self, bytes: AnyReadableBuf, address: _Address, /) -> int:
"""
Send data to the socket. The socket should not be connected to a remote socket, since the
destination socket is specified by *address*.
"""
def recvfrom(self, bufsize: int, /) -> tuple[bytes, Any]:
"""
Receive data from the socket. The return value is a pair *(bytes, address)* where *bytes* is a
bytes object representing the data received and *address* is the address of the socket sending
the data.
"""
def setsockopt(
self, level: int, optname: int, value: AnyReadableBuf | int, /
) -> None:
"""
Set the value of the given socket option. The needed symbolic constants are defined in the
socket module (SO_* etc.). The *value* can be an integer or a bytes-like object representing
a buffer.
"""
def settimeout(self, value: float | None, /) -> None:
"""
**Note**: Not every port supports this method, see below.
Set a timeout on blocking socket operations. The value argument can be a nonnegative floating
point number expressing seconds, or None. If a non-zero value is given, subsequent socket operations
will raise an `OSError` exception if the timeout period value has elapsed before the operation has
completed. If zero is given, the socket is put in non-blocking mode. If None is given, the socket
is put in blocking mode.
Not every :term:`MicroPython port` supports this method. A more portable and
generic solution is to use `select.poll` object. This allows to wait on
multiple objects at the same time (and not just on sockets, but on generic
`stream` objects which support polling). Example::
# Instead of:
s.settimeout(1.0) # time in seconds
s.read(10) # may timeout
# Use:
poller = select.poll()
poller.register(s, select.POLLIN)
res = poller.poll(1000) # time in milliseconds
if not res:
# s is still not ready for input, i.e. operation timed out
.. admonition:: Difference to CPython
:class: attention
CPython raises a ``socket.timeout`` exception in case of timeout,
which is an `OSError` subclass. MicroPython raises an OSError directly
instead. If you use ``except OSError:`` to catch the exception,
your code will work both in MicroPython and CPython.
"""
def setblocking(self, value: bool, /) -> None:
"""
Set blocking or non-blocking mode of the socket: if flag is false, the socket is set to non-blocking,
else to blocking mode.
This method is a shorthand for certain `settimeout()` calls:
* ``sock.setblocking(True)`` is equivalent to ``sock.settimeout(None)``
* ``sock.setblocking(False)`` is equivalent to ``sock.settimeout(0)``
"""
@overload
def makefile(
self, mode: Literal["rb", "wb", "rwb"] = "rb", buffering: int = 0, /
) -> Socket:
"""
Return a file object associated with the socket. The exact returned type depends on the arguments
given to makefile(). The support is limited to binary modes only ('rb', 'wb', and 'rwb').
CPython's arguments: *encoding*, *errors* and *newline* are not supported.
.. admonition:: Difference to CPython
:class: attention
As MicroPython doesn't support buffered streams, values of *buffering*
parameter is ignored and treated as if it was 0 (unbuffered).
.. admonition:: Difference to CPython
:class: attention
Closing the file object returned by makefile() WILL close the
original socket as well.
"""
@overload
def makefile(self, mode: str, buffering: int = 0, /) -> Socket:
"""
Return a file object associated with the socket. The exact returned type depends on the arguments
given to makefile(). The support is limited to binary modes only ('rb', 'wb', and 'rwb').
CPython's arguments: *encoding*, *errors* and *newline* are not supported.
.. admonition:: Difference to CPython
:class: attention
As MicroPython doesn't support buffered streams, values of *buffering*
parameter is ignored and treated as if it was 0 (unbuffered).
.. admonition:: Difference to CPython
:class: attention
Closing the file object returned by makefile() WILL close the
original socket as well.
"""
@overload
def read(self) -> bytes:
"""
Read up to size bytes from the socket. Return a bytes object. If *size* is not given, it
reads all data available from the socket until EOF; as such the method will not return until
the socket is closed. This function tries to read as much data as
requested (no "short reads"). This may be not possible with
non-blocking socket though, and then less data will be returned.
"""
@overload
def read(self, size: int, /) -> bytes:
"""
Read up to size bytes from the socket. Return a bytes object. If *size* is not given, it
reads all data available from the socket until EOF; as such the method will not return until
the socket is closed. This function tries to read as much data as
requested (no "short reads"). This may be not possible with
non-blocking socket though, and then less data will be returned.
"""
@overload
def readinto(self, buf: AnyWritableBuf, /) -> int | None:
"""
Read bytes into the *buf*. If *nbytes* is specified then read at most
that many bytes. Otherwise, read at most *len(buf)* bytes. Just as
`read()`, this method follows "no short reads" policy.
Return value: number of bytes read and stored into *buf*.
"""
@overload
def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None:
"""
Read bytes into the *buf*. If *nbytes* is specified then read at most
that many bytes. Otherwise, read at most *len(buf)* bytes. Just as
`read()`, this method follows "no short reads" policy.
Return value: number of bytes read and stored into *buf*.
"""
def readline(self) -> bytes:
"""
Read a line, ending in a newline character.
Return value: the line read.
"""
def write(self, buf: AnyReadableBuf, /) -> int | None:
"""
Write the buffer of bytes to the socket. This function will try to
write all data to a socket (no "short writes"). This may be not possible
with a non-blocking socket though, and returned value will be less than
the length of *buf*.
Return value: number of bytes written.
"""
================================================
FILE: typehints/stdlib/ssl.pyi
================================================
"""
TLS/SSL wrapper for socket objects.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/ssl.rst.
|see_cpython_module| :mod:`python:ssl`.
This module provides access to Transport Layer Security (previously and
widely known as “Secure Sockets Layer”) encryption and peer authentication
facilities for network sockets, both client-side and server-side.
.. admonition:: Difference to CPython
:class: attention
The CPython version of ``ssl`` uses ``SSLError``.
This exception does NOT exist. Instead its base class, OSError, is used.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import Final
from uio import StrOrBytesPath
from usocket import Socket
def wrap_socket(
sock: Socket,
server_side: bool = False,
keyfile: StrOrBytesPath | None = None,
certfile: StrOrBytesPath | None = None,
cert_reqs: int = "CERT_NONE",
ca_certs: str | None = None,
do_handshake: bool = True,
/,
) -> Socket:
"""
Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type),
and returns an instance of ssl.SSLSocket, which wraps the underlying stream in
an SSL context. Returned object has the usual `stream` interface methods like
``read()``, ``write()``, etc.
A server-side SSL socket should be created from a normal socket returned from
:meth:`~socket.socket.accept()` on a non-SSL listening server socket.
- *do_handshake* determines whether the handshake is done as part of the ``wrap_socket``
or whether it is deferred to be done as part of the initial reads or writes
(there is no ``do_handshake`` method as in CPython).
For blocking sockets doing the handshake immediately is standard. For non-blocking
sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode)
the handshake should generally be deferred because otherwise ``wrap_socket`` blocks
until it completes. Note that in AXTLS the handshake can be deferred until the first
read or write but it then blocks until completion.
Depending on the underlying module implementation in a particular
:term:`MicroPython port`, some or all keyword arguments above may be not supported.
"""
CERT_NONE: Final[int] = ...
"""
Supported values for *cert_reqs* parameter.
"""
CERT_OPTIONAL: Final[int] = ...
"""
Supported values for *cert_reqs* parameter.
"""
CERT_REQUIRED: Final[int] = ...
"""
Supported values for *cert_reqs* parameter.
"""
================================================
FILE: typehints/stdlib/struct.pyi
================================================
"""
pack and unpack primitive data types.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/struct.rst.
=====================================================
.. module:: struct
:synopsis: pack and unpack primitive data types
|see_cpython_module| :mod:`python:struct`.
Supported size/byte order prefixes: ``@``, ``<``, ``>``, ``!``.
Supported format codes: ``b``, ``B``, ``h``, ``H``, ``i``, ``I``, ``l``,
``L``, ``q``, ``Q``, ``s``, ``P``, ``f``, ``d`` (the latter 2 depending
on the floating-point support).
.. admonition:: Difference to CPython
:class: attention
Whitespace is not supported in format strings.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import Any
from uio import AnyReadableBuf, AnyWritableBuf
def calcsize(fmt: str | bytes, /,) -> int:
"""
Return the number of bytes needed to store the given *fmt*.
"""
def pack(fmt: str | bytes, /, *v: Any) -> bytes:
"""
Pack the values *v1*, *v2*, ... according to the format string *fmt*.
The return value is a bytes object encoding the values.
"""
def pack_into(
fmt: str | bytes, buffer: AnyWritableBuf, offset: int, /, *v: Any
) -> None:
"""
Pack the values *v1*, *v2*, ... according to the format string *fmt*
into a *buffer* starting at *offset*. *offset* may be negative to count
from the end of *buffer*.
"""
def unpack(fmt: str | bytes, data: AnyReadableBuf, /) -> tuple[Any, ...]:
"""
Unpack from the *data* according to the format string *fmt*.
The return value is a tuple of the unpacked values.
"""
def unpack_from(
fmt: str | bytes, data: AnyReadableBuf, offset: int = 0, /
) -> tuple[Any, ...]:
"""
Unpack from the *data* starting at *offset* according to the format string
*fmt*. *offset* may be negative to count from the end of *buffer*. The return
value is a tuple of the unpacked values.
"""
================================================
FILE: typehints/stdlib/sys.pyi
================================================
"""
system specific functions.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/sys.rst.
=======================================
.. module:: sys
:synopsis: system specific functions
|see_cpython_module| :mod:`python:sys`.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import Callable, Final, Literal, NoReturn
from uio import IOBase
class Implementation(tuple[str, tuple[int, int, int], int]):
name: str
version: tuple[int, int, int]
mpy: int
class ModuleType:
__class__: str
__name__: str
def exit(retval: object = 0, /) -> NoReturn:
"""
Terminate current program with a given exit code. Underlyingly, this
function raise as `SystemExit` exception. If an argument is given, its
value given as an argument to `SystemExit`.
"""
def atexit(func: Callable[[], None] | None, /) -> Callable[[], None] | None:
"""
Register *func* to be called upon termination. *func* must be a callable
that takes no arguments, or ``None`` to disable the call. The ``atexit``
function will return the previous value set by this function, which is
initially ``None``.
.. admonition:: Difference to CPython
:class: attention
This function is a MicroPython extension intended to provide similar
functionality to the :mod:`atexit` module in CPython.
"""
def print_exception(exc: BaseException, file: IOBase[str] = "stdout", /) -> None:
"""
Print exception with a traceback to a file-like object *file* (or
`sys.stdout` by default).
.. admonition:: Difference to CPython
:class: attention
This is simplified version of a function which appears in the
``traceback`` module in CPython. Unlike ``traceback.print_exception()``,
this function takes just exception value instead of exception type,
exception value, and traceback object; *file* argument should be
positional; further arguments are not supported. CPython-compatible
``traceback`` module can be found in `micropython-lib`.
"""
argv: Final[list[str]] = ...
"""
A mutable list of arguments the current program was started with.
"""
byteorder: Final[Literal["little", "big"]] = ...
"""
The byte order of the system (``"little"`` or ``"big"``).
"""
implementation: Final[Implementation] = ...
"""
Object with information about the current Python implementation. For
MicroPython, it has following attributes:
* *name* - string "micropython"
* *version* - tuple (major, minor, micro), e.g. (1, 7, 0)
This object is the recommended way to distinguish MicroPython from other
Python implementations (note that it still may not exist in the very
minimal ports).
.. admonition:: Difference to CPython
:class: attention
CPython mandates more attributes for this object, but the actual useful
bare minimum is implemented in MicroPython.
"""
maxsize: Final[int] = ...
"""
Maximum value which a native integer type can hold on the current platform,
or maximum value representable by MicroPython integer type, if it's smaller
than platform max value (that is the case for MicroPython ports without
long int support).
This attribute is useful for detecting "bitness" of a platform (32-bit vs
64-bit, etc.). It's recommended to not compare this attribute to some
value directly, but instead count number of bits in it::
bits = 0
v = sys.maxsize
while v:
bits += 1
v >>= 1
if bits > 32:
# 64-bit (or more) platform
...
else:
# 32-bit (or less) platform
# Note that on 32-bit platform, value of bits may be less than 32
# (e.g. 31) due to peculiarities described above, so use "> 16",
# "> 32", "> 64" style of comparisons.
"""
modules: Final[dict[str, ModuleType]] = ...
"""
Dictionary of loaded modules. On some ports, it may not include builtin
modules.
"""
path: Final[list[str]] = ...
"""
A mutable list of directories to search for imported modules.
"""
platform: Final[str] = ...
"""
The platform that MicroPython is running on. For OS/RTOS ports, this is
usually an identifier of the OS, e.g. ``"linux"``. For baremetal ports it
is an identifier of a board, e.g. ``"pyboard"`` for the original MicroPython
reference board. It thus can be used to distinguish one board from another.
If you need to check whether your program runs on MicroPython (vs other
Python implementation), use `sys.implementation` instead.
"""
stderr: Final[IOBase[str]] = ...
"""
Standard error `stream`.
"""
stdin: Final[IOBase[str]] = ...
"""
Standard input `stream`.
"""
stdout: Final[IOBase[str]] = ...
"""
Standard output `stream`.
"""
version: Final[str] = ...
"""
Python language version that this implementation conforms to, as a string.
"""
version_info: Final[tuple[int, int, int]] = ...
"""
Python language version that this implementation conforms to, as a tuple of ints.
.. admonition:: Difference to CPython
:class: attention
Only the first three version numbers (major, minor, micro) are supported and
they can be referenced only by index, not by name.
"""
================================================
FILE: typehints/stdlib/time.pyi
================================================
"""
time related functions.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/time.rst.
=====================================
.. module:: time
:synopsis: time related functions
|see_cpython_module| :mod:`python:time`.
The ``time`` module provides functions for getting the current time and date,
measuring time intervals, and for delays.
**Time Epoch**: Unix port uses standard for POSIX systems epoch of
1970-01-01 00:00:00 UTC. However, embedded ports use epoch of
2000-01-01 00:00:00 UTC.
**Maintaining actual calendar date/time**: This requires a
Real Time Clock (RTC). On systems with underlying OS (including some
RTOS), an RTC may be implicit. Setting and maintaining actual calendar
time is responsibility of OS/RTOS and is done outside of MicroPython,
it just uses OS API to query date/time. On baremetal ports however
system time depends on ``machine.RTC()`` object. The current calendar time
may be set using ``machine.RTC().datetime(tuple)`` function, and maintained
by following means:
* By a backup battery (which may be an additional, optional component for
a particular board).
* Using networked time protocol (requires setup by a port/user).
* Set manually by a user on each power-up (many boards then maintain
RTC time across hard resets, though some may require setting it again
in such case).
If actual calendar time is not maintained with a system/MicroPython RTC,
functions below which require reference to current absolute time may
behave not as expected.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import Final, TypeVar
class _TicksMs: ...
class _TicksUs: ...
class _TicksCPU: ...
_Ticks: Final = TypeVar("_Ticks", _TicksMs, _TicksUs, _TicksCPU, int)
def gmtime(secs: int | None = None, /) -> tuple[int, int, int, int, int, int, int, int]:
"""
Convert the time *secs* expressed in seconds since the Epoch (see above) into an
8-tuple which contains: ``(year, month, mday, hour, minute, second, weekday, yearday)``
If *secs* is not provided or None, then the current time from the RTC is used.
The `gmtime()` function returns a date-time tuple in UTC, and `localtime()` returns a
date-time tuple in local time.
The format of the entries in the 8-tuple are:
* year includes the century (for example 2014).
* month is 1-12
* mday is 1-31
* hour is 0-23
* minute is 0-59
* second is 0-59
* weekday is 0-6 for Mon-Sun
* yearday is 1-366
"""
def localtime(
secs: int | None = None, /
) -> tuple[int, int, int, int, int, int, int, int]:
"""
Convert the time *secs* expressed in seconds since the Epoch (see above) into an
8-tuple which contains: ``(year, month, mday, hour, minute, second, weekday, yearday)``
If *secs* is not provided or None, then the current time from the RTC is used.
The `gmtime()` function returns a date-time tuple in UTC, and `localtime()` returns a
date-time tuple in local time.
The format of the entries in the 8-tuple are:
* year includes the century (for example 2014).
* month is 1-12
* mday is 1-31
* hour is 0-23
* minute is 0-59
* second is 0-59
* weekday is 0-6 for Mon-Sun
* yearday is 1-366
"""
def mktime(local_time: tuple[int, int, int, int, int, int, int, int], /) -> int:
"""
This is inverse function of localtime. It's argument is a full 8-tuple
which expresses a time as per localtime. It returns an integer which is
the number of seconds since Jan 1, 2000.
"""
def sleep(seconds: float, /) -> None:
"""
Sleep for the given number of seconds. Some boards may accept *seconds* as a
floating-point number to sleep for a fractional number of seconds. Note that
other boards may not accept a floating-point argument, for compatibility with
them use `sleep_ms()` and `sleep_us()` functions.
"""
def sleep_ms(ms: int, /) -> None:
"""
Delay for given number of milliseconds, should be positive or 0.
This function will delay for at least the given number of milliseconds, but
may take longer than that if other processing must take place, for example
interrupt handlers or other threads. Passing in 0 for *ms* will still allow
this other processing to occur. Use `sleep_us()` for more precise delays.
"""
def sleep_us(us: int, /) -> None:
"""
Delay for given number of microseconds, should be positive or 0.
This function attempts to provide an accurate delay of at least *us*
microseconds, but it may take longer if the system has other higher priority
processing to perform.
"""
def ticks_ms() -> _TicksMs:
"""
Returns an increasing millisecond counter with an arbitrary reference point, that
wraps around after some value.
The wrap-around value is not explicitly exposed, but we will
refer to it as *TICKS_MAX* to simplify discussion. Period of the values is
*TICKS_PERIOD = TICKS_MAX + 1*. *TICKS_PERIOD* is guaranteed to be a power of
two, but otherwise may differ from port to port. The same period value is used
for all of `ticks_ms()`, `ticks_us()`, `ticks_cpu()` functions (for
simplicity). Thus, these functions will return a value in range [*0* ..
*TICKS_MAX*], inclusive, total *TICKS_PERIOD* values. Note that only
non-negative values are used. For the most part, you should treat values returned
by these functions as opaque. The only operations available for them are
`ticks_diff()` and `ticks_add()` functions described below.
Note: Performing standard mathematical operations (+, -) or relational
operators (<, <=, >, >=) directly on these value will lead to invalid
result. Performing mathematical operations and then passing their results
as arguments to `ticks_diff()` or `ticks_add()` will also lead to
invalid results from the latter functions.
"""
def ticks_us() -> _TicksUs:
"""
Just like `ticks_ms()` above, but in microseconds.
"""
def ticks_cpu() -> _TicksCPU:
"""
Similar to `ticks_ms()` and `ticks_us()`, but with the highest possible resolution
in the system. This is usually CPU clocks, and that's why the function is named that
way. But it doesn't have to be a CPU clock, some other timing source available in a
system (e.g. high-resolution timer) can be used instead. The exact timing unit
(resolution) of this function is not specified on ``time`` module level, but
documentation for a specific port may provide more specific information. This
function is intended for very fine benchmarking or very tight real-time loops.
Avoid using it in portable code.
Availability: Not every port implements this function.
"""
def ticks_add(ticks: _Ticks, delta: int, /) -> _Ticks:
"""
Offset ticks value by a given number, which can be either positive or negative.
Given a *ticks* value, this function allows to calculate ticks value *delta*
ticks before or after it, following modular-arithmetic definition of tick values
(see `ticks_ms()` above). *ticks* parameter must be a direct result of call
to `ticks_ms()`, `ticks_us()`, or `ticks_cpu()` functions (or from previous
call to `ticks_add()`). However, *delta* can be an arbitrary integer number
or numeric expression. `ticks_add()` is useful for calculating deadlines for
events/tasks. (Note: you must use `ticks_diff()` function to work with
deadlines.)
Examples::
# Find out what ticks value there was 100ms ago
print(ticks_add(time.ticks_ms(), -100))
# Calculate deadline for operation and test for it
deadline = ticks_add(time.ticks_ms(), 200)
while ticks_diff(deadline, time.ticks_ms()) > 0:
do_a_little_of_something()
# Find out TICKS_MAX used by this port
print(ticks_add(0, -1))
"""
def ticks_diff(ticks1: _Ticks, ticks2: _Ticks, /) -> int:
"""
Measure ticks difference between values returned from `ticks_ms()`, `ticks_us()`,
or `ticks_cpu()` functions, as a signed value which may wrap around.
The argument order is the same as for subtraction
operator, ``ticks_diff(ticks1, ticks2)`` has the same meaning as ``ticks1 - ticks2``.
However, values returned by `ticks_ms()`, etc. functions may wrap around, so
directly using subtraction on them will produce incorrect result. That is why
`ticks_diff()` is needed, it implements modular (or more specifically, ring)
arithmetics to produce correct result even for wrap-around values (as long as they not
too distant inbetween, see below). The function returns **signed** value in the range
[*-TICKS_PERIOD/2* .. *TICKS_PERIOD/2-1*] (that's a typical range definition for
two's-complement signed binary integers). If the result is negative, it means that
*ticks1* occurred earlier in time than *ticks2*. Otherwise, it means that
*ticks1* occurred after *ticks2*. This holds **only** if *ticks1* and *ticks2*
are apart from each other for no more than *TICKS_PERIOD/2-1* ticks. If that does
not hold, incorrect result will be returned. Specifically, if two tick values are
apart for *TICKS_PERIOD/2-1* ticks, that value will be returned by the function.
However, if *TICKS_PERIOD/2* of real-time ticks has passed between them, the
function will return *-TICKS_PERIOD/2* instead, i.e. result value will wrap around
to the negative range of possible values.
Informal rationale of the constraints above: Suppose you are locked in a room with no
means to monitor passing of time except a standard 12-notch clock. Then if you look at
dial-plate now, and don't look again for another 13 hours (e.g., if you fall for a
long sleep), then once you finally look again, it may seem to you that only 1 hour
has passed. To avoid this mistake, just look at the clock regularly. Your application
should do the same. "Too long sleep" metaphor also maps directly to application
behaviour: don't let your application run any single task for too long. Run tasks
in steps, and do time-keeping inbetween.
`ticks_diff()` is designed to accommodate various usage patterns, among them:
* Polling with timeout. In this case, the order of events is known, and you will deal
only with positive results of `ticks_diff()`::
# Wait for GPIO pin to be asserted, but at most 500us
start = time.ticks_us()
while pin.value() == 0:
if time.ticks_diff(time.ticks_us(), start) > 500:
raise TimeoutError
* Scheduling events. In this case, `ticks_diff()` result may be negative
if an event is overdue::
# This code snippet is not optimized
now = time.ticks_ms()
scheduled_time = task.scheduled_time()
if ticks_diff(scheduled_time, now) > 0:
print("Too early, let's nap")
sleep_ms(ticks_diff(scheduled_time, now))
task.run()
elif ticks_diff(scheduled_time, now) == 0:
print("Right at time!")
task.run()
elif ticks_diff(scheduled_time, now) < 0:
print("Oops, running late, tell task to run faster!")
task.run(run_faster=true)
Note: Do not pass `time()` values to `ticks_diff()`, you should use
normal mathematical operations on them. But note that `time()` may (and will)
also overflow. This is known as https://en.wikipedia.org/wiki/Year_2038_problem .
"""
def time() -> int:
"""
Returns the number of seconds, as an integer, since the Epoch, assuming that
underlying RTC is set and maintained as described above. If an RTC is not set, this
function returns number of seconds since a port-specific reference point in time (for
embedded boards without a battery-backed RTC, usually since power up or reset). If you
want to develop portable MicroPython application, you should not rely on this function
to provide higher than second precision. If you need higher precision, absolute
timestamps, use `time_ns()`. If relative times are acceptable then use the
`ticks_ms()` and `ticks_us()` functions. If you need calendar time, `gmtime()` or
`localtime()` without an argument is a better choice.
.. admonition:: Difference to CPython
:class: attention
In CPython, this function returns number of
seconds since Unix epoch, 1970-01-01 00:00 UTC, as a floating-point,
usually having microsecond precision. With MicroPython, only Unix port
uses the same Epoch, and if floating-point precision allows,
returns sub-second precision. Embedded hardware usually doesn't have
floating-point precision to represent both long time ranges and subsecond
precision, so they use integer value with second precision. Some embedded
hardware also lacks battery-powered RTC, so returns number of seconds
since last power-up or from other relative, hardware-specific point
(e.g. reset).
"""
def time_ns() -> int:
"""
Similar to `time()` but returns nanoseconds since the Epoch, as an integer (usually
a big integer, so will allocate on the heap).
"""
================================================
FILE: typehints/stdlib/uarray.pyi
================================================
"""
efficient arrays of numeric data.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/array.rst.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import (
overload,
Sequence,
Any,
MutableSequence,
Generic,
Text,
TypeVar,
Final,
)
_T: Final = TypeVar("_T", int, float, Text)
# noinspection PyPep8Naming
class array(MutableSequence[_T], Generic[_T]):
"""
|see_cpython_module| :mod:`python:array`.
Supported format codes: ``b``, ``B``, ``h``, ``H``, ``i``, ``I``, ``l``,
``L``, ``q``, ``Q``, ``f``, ``d`` (the latter 2 depending on the
floating-point support).
+-----------+--------------------+-------------------+-----------------------+
| Type code | C Type | Python Type | Minimum size in bytes |
+===========+====================+===================+=======================+
| ``'b'`` | signed char | int | 1 |
+-----------+--------------------+-------------------+-----------------------+
| ``'B'`` | unsigned char | int | 1 |
+-----------+--------------------+-------------------+-----------------------+
| ``'h'`` | signed short | int | 2 |
+-----------+--------------------+-------------------+-----------------------+
| ``'H'`` | unsigned short | int | 2 |
+-----------+--------------------+-------------------+-----------------------+
| ``'i'`` | signed int | int | 2 |
+-----------+--------------------+-------------------+-----------------------+
| ``'I'`` | unsigned int | int | 2 |
+-----------+--------------------+-------------------+-----------------------+
| ``'l'`` | signed long | int | 4 |
+-----------+--------------------+-------------------+-----------------------+
| ``'L'`` | unsigned long | int | 4 |
+-----------+--------------------+-------------------+-----------------------+
| ``'q'`` | signed long long | int | 8 |
+-----------+--------------------+-------------------+-----------------------+
| ``'Q'`` | unsigned long long | int | 8 |
+-----------+--------------------+-------------------+-----------------------+
| ``'f'`` | float | float | 4 |
+-----------+--------------------+-------------------+-----------------------+
| ``'d'`` | double | float | 8 |
+-----------+--------------------+-------------------+-----------------------+
"""
def __init__(self, typecode: str, iterable: Sequence[Any] = ..., /):
"""
Create array with elements of given type. Initial contents of the
array are given by *iterable*. If it is not provided, an empty
array is created.
"""
def append(self, val: Any, /) -> None:
"""
Append new element *val* to the end of array, growing it.
"""
def extend(self, iterable: Sequence[Any], /) -> None:
"""
Append new elements as contained in *iterable* to the end of
array, growing it.
"""
def decode(self, encoding: str = "utf-8", errors: str = "strict") -> str:
"""
Deprecated *do not use*, likely to be removed in future!
Note: ``decode`` is only meant to be present for ``bytearray``,
but for efficiency of code-size reasons ``bytearray`` is implemented with the same code as the
other array type-codes and hence ``decode`` is on all ``array``s at present.
"""
@overload
def __delitem__(self, i: int) -> None:
"""``array`` object does **not** support item deletion."""
@overload
def __delitem__(self, sl: slice) -> None:
"""``array`` object does **not** support item deletion."""
def insert(self, index: int, value: _T) -> None:
"""``array`` object does **not** support item insertion."""
@overload
def __getitem__(self, index: int) -> _T:
"""
Indexed read of ``self``; called as ``a[index]``, where ``a`` is an ``array``.
Returns the value at the given ``index``.
Negative indices count from end and ``IndexError``is thrown if the index out of range.
**Note:** ``__getitem__`` cannot be called directly (``a.__getitem__(index)`` fails) and
is not present in ``__dict__``, however ``a[index]`` does work.
"""
@overload
def __getitem__(self, sl: slice) -> array[_T]:
"""
Slice read of ``self``; called as ``a[sl]``, where ``a`` is an ``array``.
Returns an ``array`` of values for the given slice.
Negative slice indices count from end and ``IndexError``is thrown if any of the slice indices are out of range.
**Note:** ``__getitem__`` cannot be called directly (``a.__getitem__(sl)`` fails) and
is not present in ``__dict__``, however ``a[sl]`` does work.
"""
@overload
def __setitem__(self, index: int, value: _T) -> None:
"""
Indexed write into ``self``; called as ``a[index] = value`` where ``a`` is an ``array``,
``index`` is an ``int``, and ``value`` is the same type as ``a``'s content.
Negative indices count from end and ``IndexError``is thrown if the index out of range.
**Note:** ``__setitem__`` cannot be called directly (``a.__setitem__(index, value)`` fails) and
is not present in ``__dict__``, however ``a[index] = value`` does work.
"""
@overload
def __setitem__(self, sl: slice, values: array[_T]) -> None:
"""
Indexed write into ``self``; called as ``a[sl] = values``, where ``a`` is an ``array``,
``sl`` is an ``slice``, and ``values`` is the same type as ``a``.
Negative indices count from end and ``IndexError``is thrown if any of the slice indices are out of range.
**Note:** ``__setitem__`` cannot be called directly (``a.__setitem__(index, value)`` fails) and
is not present in ``__dict__``, however ``a[index] = value`` does work.
"""
def __len__(self) -> int:
"""
Returns the number of items in ``self``; called as ``len(a)``, where ``a`` is an ``array``.
**Note:** ``__len__`` cannot be called directly (``a.__len__()`` fails) and the
method is not present in ``__dict__``, however ``len(a)`` does work.
"""
def __add__(self, other: array[_T]) -> array[_T]:
"""
Return a new ``array`` that is the concatenation of ``self`` with ``other``;
called as ``a + other`` (where ``a`` and ``other`` are both ``array``s).
**Note:** ``__add__`` cannot be called directly (``a.__add__(other)`` fails) and
is not present in ``__dict__``, however ``a + other`` does work.
"""
def __iadd__(self, other: array[_T]) -> None:
"""
Concatenates ``self`` with ``other`` in-place;
called as ``a += other``, where ``a`` and ``other`` are both ``array``s.
Equivalent to ``extend(other)``.
**Note:** ``__iadd__`` cannot be called directly (``a.__iadd__(other)`` fails) and
is not present in ``__dict__``, however ``a += other`` does work.
"""
def __repr__(self) -> str:
"""
Returns the string representation of ``self``; called as ``str(a)`` or ``repr(a)```,
where ``a`` is an ``array``.
Returns the string 'array(, [])',
where ```` is the type code letter for ``self`` and ```` is a
comma separated list of the elements of ``self``.
**Note:** ``__repr__`` cannot be called directly (``a.__repr__()`` fails) and
is not present in ``__dict__``, however ``str(a)`` and ``repr(a)`` both work.
"""
================================================
FILE: typehints/stdlib/uasyncio.pyi
================================================
"""
asynchronous I/O scheduler for writing concurrent code.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/uasyncio.rst.
|see_cpython_module|
`asyncio `_
Example::
import uasyncio
async def blink(led, period_ms):
while True:
led.on()
await uasyncio.sleep_ms(5)
led.off()
await uasyncio.sleep_ms(period_ms)
async def main(led1, led2):
uasyncio.create_task(blink(led1, 700))
uasyncio.create_task(blink(led2, 400))
await uasyncio.sleep_ms(10_000)
# Running on a pyboard
from pyb import LED
uasyncio.run(main(LED(1), LED(2)))
# Running on a generic board
from machine import Pin
uasyncio.run(main(Pin(1), Pin(2)))
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from abc import ABC
from typing import Awaitable, TypeVar, Callable
from typing import Coroutine, Any, Dict, Iterable, Generic, Final
from uio import AnyReadableBuf
_T: Final = TypeVar("_T")
# `Coroutine` `_T` is covariant and `Awaitable` `_T` is invariant.
_C: Final = Coroutine[Any, None, _T] | Awaitable[_T]
def create_task(coro: _C, /) -> Task[_T]:
"""
Create a new task from the given coroutine and schedule it to run.
Returns the corresponding `Task` object.
"""
def current_task() -> Task[Any] | None:
"""
Return the `Task` object associated with the currently running task.
"""
def run(coro: _C, /) -> _T:
"""
Create a new task from the given coroutine and run it until it completes.
Returns the value returned by *coro*.
"""
def sleep(t: float) -> Awaitable[None]:
"""
Sleep for *t* seconds (can be a float).
This is a coroutine.
"""
def sleep_ms(t: int, /) -> Awaitable[None]:
"""
Sleep for *t* milliseconds.
This is a coroutine, and a MicroPython extension.
"""
def wait_for(awaitable: Awaitable[_T], timeout: float, /) -> Awaitable[_T]:
"""
Wait for the *awaitable* to complete, but cancel it if it takes longer
that *timeout* seconds. If *awaitable* is not a task then a task will be
created from it.
If a timeout occurs, it cancels the task and raises ``asyncio.TimeoutError``:
this should be trapped by the caller.
Returns the return value of *awaitable*.
This is a coroutine.
"""
def wait_for_ms(awaitable: Awaitable[_T], timeout: int, /) -> Awaitable[_T]:
"""
Similar to `wait_for` but *timeout* is an integer in milliseconds.
This is a coroutine, and a MicroPython extension.
"""
def gather(
*awaitable: Awaitable[Any], return_exceptions: bool = False
) -> Awaitable[list[Any]]:
"""
Run all *awaitables* concurrently. Any *awaitables* that are not tasks are
promoted to tasks.
Returns a list of return values of all *awaitables*.
This is a coroutine.
"""
StreamReader = "Stream"
StreamWriter = "Stream"
def open_connection(
host: str | None, port: str | int | None, /,
) -> Awaitable[tuple[StreamReader, StreamWriter]]:
"""
Open a TCP connection to the given *host* and *port*. The *host* address will be
resolved using `socket.getaddrinfo`, which is currently a blocking call.
Returns a pair of streams: a reader and a writer stream.
Will raise a socket-specific ``OSError`` if the host could not be resolved or if
the connection could not be made.
This is a coroutine.
"""
def start_server(
callback: Callable[[StreamReader, StreamWriter], None],
host: str | None,
port: str | int | None,
backlog: int = 5,
/,
) -> Awaitable[Server]:
"""
Start a TCP server on the given *host* and *port*. The *callback* will be
called with incoming, accepted connections, and be passed 2 arguments: reader
and writer streams for the connection.
Returns a `Server` object.
This is a coroutine.
"""
def get_event_loop() -> Loop:
"""
Return the event loop used to schedule and run tasks. See `Loop`.
"""
def new_event_loop() -> Loop:
"""
Reset the event loop and return it.
Note: since MicroPython only has a single event loop this function just
resets the loop's state, it does not create a new one.
"""
class Task(Awaitable[_T], Iterable[_T], Generic[_T], ABC):
"""
class Task
----------
"""
def __init__(self):
"""
This object wraps a coroutine into a running task. Tasks can be waited on
using ``await task``, which will wait for the task to complete and return
the return value of the task.
Tasks should not be created directly, rather use `create_task` to create them.
"""
def cancel(self) -> None:
"""
Cancel the task by injecting a ``CancelledError`` into it. The task may
or may not ignore this exception.
"""
class Event:
"""
class Event
-----------
"""
def __init__(self):
"""
Create a new event which can be used to synchronise tasks. Events start
in the cleared state.
"""
def is_set(self) -> bool:
"""
Returns ``True`` if the event is set, ``False`` otherwise.
"""
def set(self) -> None:
"""
Set the event. Any tasks waiting on the event will be scheduled to run.
Note: This must be called from within a task. It is not safe to call this
from an IRQ, scheduler callback, or other thread. See `ThreadSafeFlag`.
"""
def clear(self) -> None:
"""
Clear the event.
"""
def wait(self) -> Awaitable[Any]:
"""
Wait for the event to be set. If the event is already set then it returns
immediately.
This is a coroutine.
"""
class ThreadSafeFlag:
"""
class ThreadSafeFlag
--------------------
"""
def __init__(self):
"""
Create a new flag which can be used to synchronise a task with code running
outside the asyncio loop, such as other threads, IRQs, or scheduler
callbacks. Flags start in the cleared state.
"""
def set(self) -> None:
"""
Set the flag. If there is a task waiting on the event, it will be scheduled
to run.
"""
def wait(self) -> Awaitable[None]:
"""
Wait for the flag to be set. If the flag is already set then it returns
immediately.
A flag may only be waited on by a single task at a time.
This is a coroutine.
"""
class Lock(Awaitable[None], ABC):
"""
class Lock
----------
"""
def __init__(self):
"""
Create a new lock which can be used to coordinate tasks. Locks start in
the unlocked state.
In addition to the methods below, locks can be used in an ``async with`` statement.
"""
def locked(self) -> bool:
"""
Returns ``True`` if the lock is locked, otherwise ``False``.
"""
def acquire(self) -> Awaitable[None]:
"""
Wait for the lock to be in the unlocked state and then lock it in an atomic
way. Only one task can acquire the lock at any one time.
This is a coroutine.
"""
def release(self) -> None:
"""
Release the lock. If any tasks are waiting on the lock then the next one in the
queue is scheduled to run and the lock remains locked. Otherwise, no tasks are
waiting an the lock becomes unlocked.
"""
class Stream:
"""
"""
def __init__(self):
"""
This represents a TCP stream connection. To minimise code this class implements
both a reader and a writer, and both ``StreamReader`` and ``StreamWriter`` alias to
this class.
"""
def get_extra_info(self, v: str, /) -> str:
"""
Get extra information about the stream, given by *v*. The valid values for *v* are:
``peername``.
"""
def close(self) -> None:
"""
Close the stream.
"""
def wait_close(self) -> Awaitable[None]:
"""
Wait for the stream to close.
This is a coroutine.
"""
def read(self, n: int, /) -> Awaitable[bytes]:
"""
Read up to *n* bytes and return them.
This is a coroutine.
"""
def readline(self) -> Awaitable[bytes]:
"""
Read a line and return it.
This is a coroutine.
"""
def write(self, buf: AnyReadableBuf, /) -> None:
"""
Accumulated *buf* to the output buffer. The data is only flushed when
`Stream.drain` is called. It is recommended to call `Stream.drain` immediately
after calling this function.
"""
def drain(self) -> Awaitable[None]:
"""
Drain (write) all buffered output data out to the stream.
This is a coroutine.
"""
class Server:
"""
"""
def __init__(self):
"""
This represents the server class returned from `start_server`. It can be used
in an ``async with`` statement to close the server upon exit.
"""
def close(self) -> None:
"""
Close the server.
"""
def wait_close(self) -> Awaitable[None]:
"""
Wait for the server to close.
This is a coroutine.
"""
class Loop:
"""
"""
def __init__(self):
"""
This represents the object which schedules and runs tasks. It cannot be
created, use `get_event_loop` instead.
"""
def create_task(self, coro: _C, /) -> Task[_T]:
"""
Create a task from the given *coro* and return the new `Task` object.
"""
def run_forever(self) -> None:
"""
Run the event loop until `stop()` is called.
"""
def run_until_complete(self, awaitable: Awaitable[_T], /) -> None:
"""
Run the given *awaitable* until it completes. If *awaitable* is not a task
then it will be promoted to one.
"""
def stop(self) -> None:
"""
Stop the event loop.
"""
def close(self) -> None:
"""
Close the event loop.
"""
def set_exception_handler(
self, handler: Callable[[Loop, Dict[str, Any]], None] | None, /
) -> None:
"""
Set the exception handler to call when a Task raises an exception that is not
caught. The *handler* should accept two arguments: ``(loop, context)``.
"""
def get_exception_handler(self) -> Callable[[Loop, Dict[str, Any]], None] | None:
"""
Get the current exception handler. Returns the handler, or ``None`` if no
custom handler is set.
"""
def default_exception_handler(self, context: Dict[str, Any], /) -> None:
"""
The default exception handler that is called.
"""
def call_exception_handler(self, context: Dict[str, Any], /) -> None:
"""
Call the current exception handler. The argument *context* is passed through and
is a dictionary containing keys: ``'message'``, ``'exception'``, ``'future'``.
"""
================================================
FILE: typehints/stdlib/ubinascii.pyi
================================================
"""
binary/ASCII conversions.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/binascii.rst.
===========================================
.. module:: binascii
:synopsis: binary/ASCII conversions
|see_cpython_module| :mod:`python:binascii`.
This module implements conversions between binary data and various
encodings of it in ASCII form (in both directions).
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
def hexlify(data: bytes, sep: str | bytes = ..., /) -> bytes:
"""
Convert the bytes in the *data* object to a hexadecimal representation.
Returns a bytes object.
If the additional argument *sep* is supplied it is used as a separator
between hexadecimal values.
"""
def unhexlify(data: str | bytes, /) -> bytes:
"""
Convert hexadecimal data to binary representation. Returns bytes string.
(i.e. inverse of hexlify)
"""
def a2b_base64(data: str | bytes, /) -> bytes:
"""
Decode base64-encoded data, ignoring invalid characters in the input.
Conforms to `RFC 2045 s.6.8 `_.
Returns a bytes object.
"""
def b2a_base64(data: bytes, /) -> bytes:
"""
Encode binary data in base64 format, as in `RFC 3548
`_. Returns the encoded data
followed by a newline character, as a bytes object.
"""
================================================
FILE: typehints/stdlib/ucollections.pyi
================================================
"""
collection and container types.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/collections.rst.
====================================================
.. module:: collections
:synopsis: collection and container types
|see_cpython_module| :mod:`python:collections`.
This module implements advanced collection and container types to
hold/accumulate various objects.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import overload, Any, Type, Iterable, TypeVar, Generic, Mapping, Dict, Final
_KT: Final = TypeVar("_KT")
_VT: Final = TypeVar("_VT")
def namedtuple(name: str, fields: str | Iterable[str]) -> Type[tuple[Any, ...]]:
"""
This is factory function to create a new namedtuple type with a specific
name and set of fields. A namedtuple is a subclass of tuple which allows
to access its fields not just by numeric index, but also with an attribute
access syntax using symbolic field names. Fields is a sequence of strings
specifying field names. For compatibility with CPython it can also be a
a string with space-separated field named (but this is less efficient).
Example of use::
from collections import namedtuple
MyTuple = namedtuple("MyTuple", ("id", "name"))
t1 = MyTuple(1, "foo")
t2 = MyTuple(2, "bar")
print(t1.name)
assert t2.name == t2[1]
"""
# noinspection PyPep8Naming
class deque:
"""
Minimal implementation of a deque that implements a FIFO buffer.
"""
def __init__(self, iterable: tuple[Any], maxlen: int, flags: int = 0, /):
"""
Deques (double-ended queues) are a list-like container that support O(1)
appends and pops from either side of the deque. New deques are created
using the following arguments:
- *iterable* must be the empty tuple, and the new deque is created empty.
- *maxlen* must be specified and the deque will be bounded to this
maximum length. Once the deque is full, any new items added will
discard items from the opposite end.
- The optional *flags* can be 1 to check for overflow when adding items.
"""
def __bool__(self) -> bool:
"""
Returns true if the `deque` isn't empty.
**Note:** The method isn't listed by ``dir(deque)`` and can't be called directly,
however ``bool(deque)`` and automatic conversion work!
"""
def __len__(self) -> int:
"""
Returns the number of items in the `deque`.
**Note:** The method isn't listed by ``dir(deque)`` and can't be called directly,
however ``len(deque)`` works!
"""
def append(self, x: Any, /) -> None:
"""
Add *x* to the right side of the deque.
Raises IndexError if overflow checking is enabled and there is no more room left.
"""
def popleft(self) -> Any:
"""
Remove and return an item from the left side of the deque.
Raises IndexError if no items are present.
"""
class OrderedDict(Dict[_KT, _VT], Generic[_KT, _VT]):
"""
W
h
e
n
o
r
d
e
r
e
d
d
i
c
t
i
s
i
t
e
r
a
t
e
d
o
v
e
r
,
k
e
y
s
/
i
t
e
m
s
a
r
e
r
e
t
u
r
n
e
d
i
n
t
h
e
o
r
d
e
r
t
h
e
y
w
e
r
e
a
d
d
e
d
.
"""
@overload
def __init__(self):
"""
``dict`` type subclass which remembers and preserves the order of keys
added. When ordered dict is iterated over, keys/items are returned in
the order they were added::
from collections import OrderedDict
# To make benefit of ordered keys, OrderedDict should be initialized
# from sequence of (key, value) pairs.
d = OrderedDict([("z", 1), ("a", 2)])
# More items can be added as usual
d["w"] = 5
d["b"] = 3
for k, v in d.items():
print(k, v)
Output::
z 1
a 2
w 5
b 3
"""
@overload
def __init__(self, **kwargs: _VT):
"""
``dict`` type subclass which remembers and preserves the order of keys
added. When ordered dict is iterated over, keys/items are returned in
the order they were added::
from collections import OrderedDict
# To make benefit of ordered keys, OrderedDict should be initialized
# from sequence of (key, value) pairs.
d = OrderedDict([("z", 1), ("a", 2)])
# More items can be added as usual
d["w"] = 5
d["b"] = 3
for k, v in d.items():
print(k, v)
Output::
z 1
a 2
w 5
b 3
"""
@overload
def __init__(self, map: Mapping[_KT, _VT], **kwargs: _VT):
"""
``dict`` type subclass which remembers and preserves the order of keys
added. When ordered dict is iterated over, keys/items are returned in
the order they were added::
from collections import OrderedDict
# To make benefit of ordered keys, OrderedDict should be initialized
# from sequence of (key, value) pairs.
d = OrderedDict([("z", 1), ("a", 2)])
# More items can be added as usual
d["w"] = 5
d["b"] = 3
for k, v in d.items():
print(k, v)
Output::
z 1
a 2
w 5
b 3
"""
================================================
FILE: typehints/stdlib/uerrno.pyi
================================================
"""
system error codes.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/errno.rst.
==================================
.. module:: errno
:synopsis: system error codes
|see_cpython_module| :mod:`python:errno`.
This module provides access to symbolic error codes for `OSError` exception.
A particular inventory of codes depends on :term:`MicroPython port`.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import Final, Dict
EEXIST: Final[int] = ...
"""
Error codes, based on ANSI C/POSIX standard. All error codes start with
"E". As mentioned above, inventory of the codes depends on
:term:`MicroPython port`. Errors are usually accessible as ``exc.errno``
where ``exc`` is an instance of `OSError`. Usage example::
try:
os.mkdir("my_dir")
except OSError as exc:
if exc.errno == errno.EEXIST:
print("Directory already exists")
"""
EAGAIN: Final[int] = ...
"""
Error codes, based on ANSI C/POSIX standard. All error codes start with
"E". As mentioned above, inventory of the codes depends on
:term:`MicroPython port`. Errors are usually accessible as ``exc.errno``
where ``exc`` is an instance of `OSError`. Usage example::
try:
os.mkdir("my_dir")
except OSError as exc:
if exc.errno == errno.EEXIST:
print("Directory already exists")
"""
errorcode: Final[Dict[int, str]] = ...
"""
Dictionary mapping numeric error codes to strings with symbolic error
code (see above)::
>>> print(errno.errorcode[errno.EEXIST])
EEXIST
"""
================================================
FILE: typehints/stdlib/uhashlib.pyi
================================================
"""
hashing algorithms.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/hashlib.rst.
====================================
.. module:: hashlib
:synopsis: hashing algorithms
|see_cpython_module| :mod:`python:hashlib`.
This module implements binary data hashing algorithms. The exact inventory
of available algorithms depends on a board. Among the algorithms which may
be implemented:
* SHA256 - The current generation, modern hashing algorithm (of SHA2 series).
It is suitable for cryptographically-secure purposes. Included in the
MicroPython core and any board is recommended to provide this, unless
it has particular code size constraints.
* SHA1 - A previous generation algorithm. Not recommended for new usages,
but SHA1 is a part of number of Internet standards and existing
applications, so boards targeting network connectivity and
interoperability will try to provide this.
* MD5 - A legacy algorithm, not considered cryptographically secure. Only
selected boards, targeting interoperability with legacy applications,
will offer this.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from abc import ABC
from typing import overload
from uio import AnyReadableBuf
# noinspection PyPep8Naming
class sha256("_Hash"):
"""
The current generation, modern hashing algorithm (of SHA2 series).
It is suitable for cryptographically-secure purposes. Included in the
MicroPython core and any board is recommended to provide this, unless
it has particular code size constraints.
"""
@overload
def __init__(self):
"""
Create an SHA256 hasher object and optionally feed ``data`` into it.
"""
@overload
def __init__(self, data: AnyReadableBuf):
"""
Create an SHA256 hasher object and optionally feed ``data`` into it.
"""
# noinspection PyPep8Naming
class sha1("_Hash"):
"""
A previous generation algorithm. Not recommended for new usages,
but SHA1 is a part of number of Internet standards and existing
applications, so boards targeting network connectivity and
interoperability will try to provide this.
"""
@overload
def __init__(self):
"""
Create an SHA1 hasher object and optionally feed ``data`` into it.
"""
@overload
def __init__(self, data: AnyReadableBuf):
"""
Create an SHA1 hasher object and optionally feed ``data`` into it.
"""
# noinspection PyPep8Naming
class md5("_Hash"):
"""
A legacy algorithm, not considered cryptographically secure. Only
selected boards, targeting interoperability with legacy applications,
will offer this.
"""
def __init__(self, data: AnyReadableBuf = ..., /):
"""
Create an MD5 hasher object and optionally feed ``data`` into it.
"""
class _Hash(ABC):
"""
Abstract base class for hashing algorithms that defines methods available in all algorithms.
"""
def update(self, data: AnyReadableBuf, /) -> None:
"""
Feed more binary data into hash.
"""
def digest(self) -> bytes:
"""
Return hash for all data passed through hash, as a bytes object. After this
method is called, more data cannot be fed into the hash any longer.
"""
def hexdigest(self) -> str:
"""
This method is NOT implemented. Use ``binascii.hexlify(hash.digest())``
to achieve a similar effect.
"""
================================================
FILE: typehints/stdlib/uheapq.pyi
================================================
"""
heap queue algorithm.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/heapq.rst.
====================================
.. module:: heapq
:synopsis: heap queue algorithm
|see_cpython_module| :mod:`python:heapq`.
This module implements the
`min heap queue algorithm `_.
A heap queue is essentially a list that has its elements stored in such a way
that the first item of the list is always the smallest.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import TypeVar, Any, Final
_T: Final = TypeVar("_T")
def heappush(heap: list[_T], item: _T, /) -> None:
"""
Push the ``item`` onto the ``heap``.
"""
def heappop(heap: list[_T], /) -> _T:
"""
Pop the first item from the ``heap``, and return it. Raise ``IndexError`` if
``heap`` is empty.
The returned item will be the smallest item in the ``heap``.
"""
def heapify(x: list[Any], /) -> None:
"""
Convert the list ``x`` into a heap. This is an in-place operation.
"""
================================================
FILE: typehints/stdlib/uio.pyi
================================================
"""
input/output streams.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/io.rst.
=================================
.. module:: io
:synopsis: input/output streams
|see_cpython_module| :mod:`python:io`.
This module contains additional types of `stream` (file-like) objects
and helper functions.
Conceptual hierarchy
--------------------
.. admonition:: Difference to CPython
:class: attention
Conceptual hierarchy of stream base classes is simplified in MicroPython,
as described in this section.
(Abstract) base stream classes, which serve as a foundation for behaviour
of all the concrete classes, adhere to few dichotomies (pair-wise
classifications) in CPython. In MicroPython, they are somewhat simplified
and made implicit to achieve higher efficiencies and save resources.
An important dichotomy in CPython is unbuffered vs buffered streams. In
MicroPython, all streams are currently unbuffered. This is because all
modern OSes, and even many RTOSes and filesystem drivers already perform
buffering on their side. Adding another layer of buffering is counter-
productive (an issue known as "bufferbloat") and takes precious memory.
Note that there still cases where buffering may be useful, so we may
introduce optional buffering support at a later time.
But in CPython, another important dichotomy is tied with "bufferedness" -
it's whether a stream may incur short read/writes or not. A short read
is when a user asks e.g. 10 bytes from a stream, but gets less, similarly
for writes. In CPython, unbuffered streams are automatically short
operation susceptible, while buffered are guarantee against them. The
no short read/writes is an important trait, as it allows to develop
more concise and efficient programs - something which is highly desirable
for MicroPython. So, while MicroPython doesn't support buffered streams,
it still provides for no-short-operations streams. Whether there will
be short operations or not depends on each particular class' needs, but
developers are strongly advised to favour no-short-operations behaviour
for the reasons stated above. For example, MicroPython sockets are
guaranteed to avoid short read/writes. Actually, at this time, there is
no example of a short-operations stream class in the core, and one would
be a port-specific class, where such a need is governed by hardware
peculiarities.
The no-short-operations behaviour gets tricky in case of non-blocking
streams, blocking vs non-blocking behaviour being another CPython dichotomy,
fully supported by MicroPython. Non-blocking streams never wait for
data either to arrive or be written - they read/write whatever possible,
or signal lack of data (or ability to write data). Clearly, this conflicts
with "no-short-operations" policy, and indeed, a case of non-blocking
buffered (and this no-short-ops) streams is convoluted in CPython - in
some places, such combination is prohibited, in some it's undefined or
just not documented, in some cases it raises verbose exceptions. The
matter is much simpler in MicroPython: non-blocking stream are important
for efficient asynchronous operations, so this property prevails on
the "no-short-ops" one. So, while blocking streams will avoid short
reads/writes whenever possible (the only case to get a short read is
if end of file is reached, or in case of error (but errors don't
return short data, but raise exceptions)), non-blocking streams may
produce short data to avoid blocking the operation.
The final dichotomy is binary vs text streams. MicroPython of course
supports these, but while in CPython text streams are inherently
buffered, they aren't in MicroPython. (Indeed, that's one of the cases
for which we may introduce buffering support.)
Note that for efficiency, MicroPython doesn't provide abstract base
classes corresponding to the hierarchy above, and it's not possible
to implement, or subclass, a stream class in pure Python.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from types import TracebackType
from typing import TypeVar, Final, Protocol, runtime_checkable, Literal
from typing import AnyStr, overload, Type
from uarray import array
_T: Final = TypeVar("_T")
_OpenTextModeUpdating: Final = Literal[
"r+",
"+r",
"rt+",
"r+t",
"+rt",
"tr+",
"t+r",
"+tr",
"w+",
"+w",
"wt+",
"w+t",
"+wt",
"tw+",
"t+w",
"+tw",
"a+",
"+a",
"at+",
"a+t",
"+at",
"ta+",
"t+a",
"+ta",
"x+",
"+x",
"xt+",
"x+t",
"+xt",
"tx+",
"t+x",
"+tx",
]
_OpenTextModeWriting: Final = Literal["w", "wt", "tw", "a", "at", "ta", "x", "xt", "tx"]
_OpenTextModeReading: Final = Literal[
"r", "rt", "tr", "U", "rU", "Ur", "rtU", "rUt", "Urt", "trU", "tUr", "Utr"
]
_OpenTextMode: Final = _OpenTextModeUpdating | _OpenTextModeWriting | _OpenTextModeReading
_OpenBinaryModeUpdating: Final = Literal[
"rb+",
"r+b",
"+rb",
"br+",
"b+r",
"+br",
"wb+",
"w+b",
"+wb",
"bw+",
"b+w",
"+bw",
"ab+",
"a+b",
"+ab",
"ba+",
"b+a",
"+ba",
"xb+",
"x+b",
"+xb",
"bx+",
"b+x",
"+bx",
]
_OpenBinaryModeWriting: Final = Literal["wb", "bw", "ab", "ba", "xb", "bx"]
_OpenBinaryModeReading: Final = Literal[
"rb", "br", "rbU", "rUb", "Urb", "brU", "bUr", "Ubr"
]
_OpenBinaryMode: Final = _OpenBinaryModeUpdating | _OpenBinaryModeReading | _OpenBinaryModeWriting
AnyStr_co: Final = TypeVar("AnyStr_co", str, bytes, covariant=True)
@runtime_checkable
class PathLike(Protocol[AnyStr_co]):
def __fspath__(self) -> AnyStr_co: ...
StrOrBytesPath: Final = str | bytes | PathLike[str] | PathLike[bytes]
_OpenFile: Final = StrOrBytesPath | int
AnyReadableBuf: Final = TypeVar("AnyReadableBuf", bytearray, array, memoryview, bytes)
"""
Type that allows bytearray, array, memoryview, or bytes,
but only one of these and not a mixture in a single declaration.
"""
AnyWritableBuf: Final = TypeVar("AnyWritableBuf", bytearray, array, memoryview)
"""
Type that allows bytearray, array, or memoryview, but only one of these and not a mixture in a single declaration.
"""
_Self: Final = TypeVar("_Self") # The type that extends `IOBase`.
@runtime_checkable
class IOBase(Protocol[AnyStr, _Self]):
"""A `Protocol` (structurally typed) for an IOStream."""
__slots__ = ()
def __enter__(self) -> _Self:
"""
Called on entry to a `with` block.
The `with` statement will bind this method’s return value to the target(s) specified in the `as` clause
of the statement, if any.
"""
def __exit__(
self,
exc_type: Type[BaseException] | None,
exc_value: BaseException | None,
traceback: TracebackType | None,
) -> bool | None:
"""
Called on exit of a `with` block.
The parameters describe the exception that caused the context to be exited.
If the context was exited without an exception, all three arguments will be `None`.
If an exception is supplied, and the method wishes to suppress the exception
(i.e., prevent it from being propagated), it should return a true value.
Otherwise, the exception will be processed normally upon exit from this method.
*Note* that `__exit__()` methods should not re-raise the passed-in exception;
this is the caller’s responsibility.
"""
def __next__(self) -> AnyStr:
"""
Next string.
"""
def __iter__(self) -> _Self:
"""
Start new iteration.
"""
def close(self) -> None:
"""
Flushes the write buffers and closes the IO stream; best not called directly, use a `with` block instead.
Calling `f.close()` without using a `with` block might result in content not being completely written to the
disk, even if the program exits successfully.
A closed file cannot be read or written any more.
Any operation which requires that the file be open will raise a `ValueError` after the file has been closed.
Calling `f.close()` more than once is allowed.
"""
def flush(self) -> None:
"""
Flushes the write buffers of the IO stream.
`flush()` does not necessarily write the file’s data to disk.
Use `f.flush()` followed by `os.sync()` to ensure this behavior.
This method does nothing for read-only and non-blocking streams.
"""
def read(self, size: int | None = -1) -> AnyStr | None:
"""
Read up to `size` bytes from the object and return them as a `str` (text file) or `bytes` (binary file).
As a convenience, if `size` is unspecified or -1, all bytes until EOF are returned.
Otherwise, only one system call is ever made.
Fewer than `size` bytes may be returned if the operating system call returns fewer than `size` bytes.
If 0 bytes are returned, and `size` was not 0, this indicates end of file.
If `self` is in non-blocking mode and no bytes are available, `None` is returned.
"""
def readinto(self, b: AnyWritableBuf) -> int | None:
"""
Read bytes into a pre-allocated, writable bytes-like object b, and return the number of bytes read.
For example, b might be a bytearray.
If `self` is in non-blocking mode and no bytes are available, `None` is returned.
"""
def readline(self, size: int = -1) -> AnyStr:
"""
Read and return, as a `str` (text file) or `bytes` (binary file), one line from the stream.
If size is specified, at most size bytes will be read.
The line terminator is always `b'
'` for binary files;
for text files, the newline argument to `open()` can be used to select the line terminator(s) recognized.
"""
def readlines(self, hint: int | None = -1) -> list[AnyStr]:
"""
Read and return a list of lines, as a `list[str]` (text file) or `list[bytes]` (binary file), from the stream.
`hint` can be specified to control the number of lines read:
no more lines will be read if the total size (in bytes/characters) of all lines so far exceeds `hint`.
`hint` values of 0 or less, as well as `None`, are treated as no hint.
The line terminator is always `b'
'` for binary files;
for text files, the newline argument to `open()` can be used to select the line terminator(s) recognized.
*Note* that it’s already possible to iterate on file objects using `for line in file: ...`
without calling `file.readlines()`.
"""
def write(self, b: AnyReadableBuf) -> int | None:
"""
Write the given bytes-like object, `b`, to the underlying raw stream, and return the number of bytes written.
This can be less than the length of `b` in bytes, depending on specifics of the underlying raw stream,
and especially if it is in non-blocking mode.
`None` is returned if the raw stream is set not to block and no single byte could be readily written to it.
The caller may release or mutate `b` after this method returns,
so the implementation only access `b` during the method call.
"""
def seek(self, offset: int, whence: int = 0) -> int:
"""
Change the stream position to the given byte `offset`.
`offset` is interpreted relative to the position indicated by `whence`.
The default value for whence is 0.
Values for whence are:
* 0 – start of the stream (the default); offset should be zero or positive.
* 1 – current stream position; offset may be negative.
* 2 – end of the stream; offset is usually negative.
Returns the new absolute position.
"""
def tell(self) -> int:
"""
Return the current stream position.
"""
@overload
def open(name: _OpenFile, /, **kwargs) -> "TextIOWrapper":
"""
Open a file. Builtin ``open()`` function is aliased to this function.
All ports (which provide access to file system) are required to support
*mode* parameter, but support for other arguments vary by port.
"""
@overload
def open(name: _OpenFile, mode: _OpenTextMode = ..., /, **kwargs) -> "TextIOWrapper":
"""
Open a file. Builtin ``open()`` function is aliased to this function.
All ports (which provide access to file system) are required to support
*mode* parameter, but support for other arguments vary by port.
"""
@overload
def open(name: _OpenFile, mode: _OpenBinaryMode = ..., /, **kwargs) -> "FileIO":
"""
Open a file. Builtin ``open()`` function is aliased to this function.
All ports (which provide access to file system) are required to support
*mode* parameter, but support for other arguments vary by port.
"""
class FileIO(IOBase[bytes, "FileIO"]):
"""
Bytes stream from a file.
"""
def __init__(self, name: _OpenFile, mode: str = ..., /, **kwargs):
"""
This is type of a file open in binary mode, e.g. using ``open(name, "rb")``.
You should not instantiate this class directly.
"""
class TextIOWrapper(IOBase[str, "TextIOWrapper"]):
"""
Str stream from a file.
"""
def __init__(self, name: _OpenFile, mode: str = ..., /, **kwargs):
"""
This is type of a file open in text mode, e.g. using ``open(name, "rt")``.
You should not instantiate this class directly.
"""
class StringIO(IOBase[str, "StringIO"]):
"""
Str stream from a str (wrapper).
"""
@overload
def __init__(self, string: str = "", /):
"""
In-memory file-like object for input/output.
`StringIO` is used for text-mode I/O (similar to a normal file opened with "t" modifier).
Initial contents can be specified with `string` parameter.
`alloc_size` constructor creates an empty `StringIO` object,
pre-allocated to hold up to `alloc_size` number of bytes.
That means that writing that amount of bytes won't lead to reallocation of the buffer,
and thus won't hit out-of-memory situation or lead to memory fragmentation.
This constructor is a MicroPython extension and is recommended for usage only in special
cases and in system-level libraries, not for end-user applications.
.. admonition:: Difference to CPython
:class: attention
This constructor is a MicroPython extension.
"""
@overload
def __init__(self, alloc_size: int, /):
"""
In-memory file-like object for input/output.
`StringIO` is used for text-mode I/O (similar to a normal file opened with "t" modifier).
Initial contents can be specified with `string` parameter.
`alloc_size` constructor creates an empty `StringIO` object,
pre-allocated to hold up to `alloc_size` number of bytes.
That means that writing that amount of bytes won't lead to reallocation of the buffer,
and thus won't hit out-of-memory situation or lead to memory fragmentation.
This constructor is a MicroPython extension and is recommended for usage only in special
cases and in system-level libraries, not for end-user applications.
.. admonition:: Difference to CPython
:class: attention
This constructor is a MicroPython extension.
"""
def getvalue(self) -> str:
"""Get the current contents of the underlying buffer which holds data."""
class BytesIO(IOBase[bytes, "BytesIO"]):
"""
Bytes stream from a bytes array (wrapper).
"""
@overload
def __init__(self, string: bytes = "", /):
"""
In-memory file-like objects for input/output. `StringIO` is used for
text-mode I/O (similar to a normal file opened with "t" modifier).
`BytesIO` is used for binary-mode I/O (similar to a normal file
opened with "b" modifier). Initial contents of file-like objects
can be specified with *string* parameter (should be normal string
for `StringIO` or bytes object for `BytesIO`). All the usual file
methods like ``read()``, ``write()``, ``seek()``, ``flush()``,
``close()`` are available on these objects, and additionally, a
following method:
`alloc_size` constructor creates an empty `BytesIO` object,
pre-allocated to hold up to `alloc_size` number of bytes.
That means that writing that amount of bytes won't lead to reallocation of the buffer,
and thus won't hit out-of-memory situation or lead to memory fragmentation.
This constructor is a MicroPython extension and is recommended for usage only in special
cases and in system-level libraries, not for end-user applications.
.. admonition:: Difference to CPython
:class: attention
This constructor is a MicroPython extension.
"""
@overload
def __init__(self, alloc_size: int, /):
"""
In-memory file-like objects for input/output. `StringIO` is used for
text-mode I/O (similar to a normal file opened with "t" modifier).
`BytesIO` is used for binary-mode I/O (similar to a normal file
opened with "b" modifier). Initial contents of file-like objects
can be specified with *string* parameter (should be normal string
for `StringIO` or bytes object for `BytesIO`). All the usual file
methods like ``read()``, ``write()``, ``seek()``, ``flush()``,
``close()`` are available on these objects, and additionally, a
following method:
`alloc_size` constructor creates an empty `BytesIO` object,
pre-allocated to hold up to `alloc_size` number of bytes.
That means that writing that amount of bytes won't lead to reallocation of the buffer,
and thus won't hit out-of-memory situation or lead to memory fragmentation.
This constructor is a MicroPython extension and is recommended for usage only in special
cases and in system-level libraries, not for end-user applications.
.. admonition:: Difference to CPython
:class: attention
This constructor is a MicroPython extension.
"""
def getvalue(self) -> bytes:
"""
Get the current contents of the underlying buffer which holds data.
"""
================================================
FILE: typehints/stdlib/ujson.pyi
================================================
"""
JSON encoding and decoding.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/json.rst.
=========================================
.. module:: json
:synopsis: JSON encoding and decoding
|see_cpython_module| :mod:`python:json`.
This modules allows to convert between Python objects and the JSON
data format.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import Any, AnyStr
from uio import IOBase
def dump(
obj: Any, stream: IOBase[str, Any], separators: tuple[str, str] | None = None, /
) -> None:
"""
Serialise *obj* to a JSON string, writing it to the given *stream*.
If specified, separators should be an ``(item_separator, key_separator)``
tuple. The default is ``(', ', ': ')``. To get the most compact JSON
representation, you should specify ``(',', ':')`` to eliminate whitespace.
"""
def dumps(obj: Any, separators: tuple[str, str] | None = None) -> str:
"""
Return *obj* represented as a JSON string.
The arguments have the same meaning as in `dump`.
"""
def load(stream: IOBase[str, Any]) -> Any:
"""
Parse the given *stream*, interpreting it as a JSON string and
deserialising the data to a Python object. The resulting object is
returned.
Parsing continues until end-of-file is encountered.
A :exc:`ValueError` is raised if the data in *stream* is not correctly formed.
"""
def loads(str: AnyStr) -> Any:
"""
Parse the JSON *str* and return an object. Raises :exc:`ValueError` if the
string is not correctly formed.
"""
================================================
FILE: typehints/stdlib/uos.pyi
================================================
"""
basic "operating system" services.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/os.rst.
==============================================
.. module:: os
:synopsis: basic "operating system" services
|see_cpython_module| :mod:`python:os`.
The ``os`` module contains functions for filesystem access and mounting,
terminal redirection and duplication, and the ``uname`` and ``urandom``
functions.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from abc import abstractmethod
from typing import Final, TypeVar, runtime_checkable, Protocol, overload, Literal
from uio import IOBase
_StrOrBytesT: Final = TypeVar("_StrOrBytesT", str, bytes)
class _PathLike(Protocol[_StrOrBytesT]):
@abstractmethod
def __fspath__(self) -> _StrOrBytesT:
"""Return the file system path representation of the object, preferably as a `str`."""
_AnyPath: Final = str | bytes | _PathLike[str] | _PathLike[bytes]
_FdOrAnyPath: Final = int | _AnyPath
def uname() -> tuple[str, str, str, str, str]:
"""
Return a tuple (possibly a named tuple) containing information about the
underlying machine and/or its operating system. The tuple has five fields
in the following order, each of them being a string:
* ``sysname`` -- the name of the underlying system
* ``nodename`` -- the network name (can be the same as ``sysname``)
* ``release`` -- the version of the underlying system
* ``version`` -- the MicroPython version and build date
* ``machine`` -- an identifier for the underlying hardware (eg board, CPU)
"""
def urandom(n: int, /) -> bytes:
"""
Return a bytes object with *n* random bytes. Whenever possible, it is
generated by the hardware random number generator.
"""
def chdir(path: _FdOrAnyPath, /) -> None:
"""
Change current directory.
"""
def getcwd() -> str:
"""
Get the current directory.
"""
@overload
def ilistdir() -> list[tuple[str, int, int] | tuple[str, int, int, int]]:
"""
This function returns an iterator which then yields tuples corresponding to
the entries in the directory that it is listing. With no argument it lists the
current directory, otherwise it lists the directory given by *dir*.
The tuples have the form *(name, type, inode[, size])*:
- *name* is a string (or bytes if *dir* is a bytes object) and is the name of
the entry;
- *type* is an integer that specifies the type of the entry, with 0x4000 for
directories and 0x8000 for regular files;
- *inode* is an integer corresponding to the inode of the file, and may be 0
for filesystems that don't have such a notion.
- Some platforms may return a 4-tuple that includes the entry's *size*. For
file entries, *size* is an integer representing the size of the file
or -1 if unknown. Its meaning is currently undefined for directory
entries.
"""
@overload
def ilistdir(dir: int, /) -> list[tuple[str, int, int] | tuple[str, int, int, int]]:
"""
This function returns an iterator which then yields tuples corresponding to
the entries in the directory that it is listing. With no argument it lists the
current directory, otherwise it lists the directory given by *dir*.
The tuples have the form *(name, type, inode[, size])*:
- *name* is a string (or bytes if *dir* is a bytes object) and is the name of
the entry;
- *type* is an integer that specifies the type of the entry, with 0x4000 for
directories and 0x8000 for regular files;
- *inode* is an integer corresponding to the inode of the file, and may be 0
for filesystems that don't have such a notion.
- Some platforms may return a 4-tuple that includes the entry's *size*. For
file entries, *size* is an integer representing the size of the file
or -1 if unknown. Its meaning is currently undefined for directory
entries.
"""
@overload
def ilistdir(dir: str, /) -> list[tuple[str, int, int] | tuple[str, int, int, int]]:
"""
This function returns an iterator which then yields tuples corresponding to
the entries in the directory that it is listing. With no argument it lists the
current directory, otherwise it lists the directory given by *dir*.
The tuples have the form *(name, type, inode[, size])*:
- *name* is a string (or bytes if *dir* is a bytes object) and is the name of
the entry;
- *type* is an integer that specifies the type of the entry, with 0x4000 for
directories and 0x8000 for regular files;
- *inode* is an integer corresponding to the inode of the file, and may be 0
for filesystems that don't have such a notion.
- Some platforms may return a 4-tuple that includes the entry's *size*. For
file entries, *size* is an integer representing the size of the file
or -1 if unknown. Its meaning is currently undefined for directory
entries.
"""
@overload
def ilistdir(
dir: bytes, /
) -> list[tuple[bytes, int, int] | tuple[bytes, int, int, int]]:
"""
This function returns an iterator which then yields tuples corresponding to
the entries in the directory that it is listing. With no argument it lists the
current directory, otherwise it lists the directory given by *dir*.
The tuples have the form *(name, type, inode[, size])*:
- *name* is a string (or bytes if *dir* is a bytes object) and is the name of
the entry;
- *type* is an integer that specifies the type of the entry, with 0x4000 for
directories and 0x8000 for regular files;
- *inode* is an integer corresponding to the inode of the file, and may be 0
for filesystems that don't have such a notion.
- Some platforms may return a 4-tuple that includes the entry's *size*. For
file entries, *size* is an integer representing the size of the file
or -1 if unknown. Its meaning is currently undefined for directory
entries.
"""
@overload
def ilistdir(
dir: _PathLike[str], /
) -> list[tuple[str, int, int] | tuple[str, int, int, int]]:
"""
This function returns an iterator which then yields tuples corresponding to
the entries in the directory that it is listing. With no argument it lists the
current directory, otherwise it lists the directory given by *dir*.
The tuples have the form *(name, type, inode[, size])*:
- *name* is a string (or bytes if *dir* is a bytes object) and is the name of
the entry;
- *type* is an integer that specifies the type of the entry, with 0x4000 for
directories and 0x8000 for regular files;
- *inode* is an integer corresponding to the inode of the file, and may be 0
for filesystems that don't have such a notion.
- Some platforms may return a 4-tuple that includes the entry's *size*. For
file entries, *size* is an integer representing the size of the file
or -1 if unknown. Its meaning is currently undefined for directory
entries.
"""
@overload
def ilistdir(
dir: _PathLike[bytes], /
) -> list[tuple[bytes, int, int] | tuple[bytes, int, int, int]]:
"""
This function returns an iterator which then yields tuples corresponding to
the entries in the directory that it is listing. With no argument it lists the
current directory, otherwise it lists the directory given by *dir*.
The tuples have the form *(name, type, inode[, size])*:
- *name* is a string (or bytes if *dir* is a bytes object) and is the name of
the entry;
- *type* is an integer that specifies the type of the entry, with 0x4000 for
directories and 0x8000 for regular files;
- *inode* is an integer corresponding to the inode of the file, and may be 0
for filesystems that don't have such a notion.
- Some platforms may return a 4-tuple that includes the entry's *size*. For
file entries, *size* is an integer representing the size of the file
or -1 if unknown. Its meaning is currently undefined for directory
entries.
"""
@overload
def listdir() -> list[str]:
"""
With no argument, list the current directory. Otherwise list the given directory.
"""
@overload
def listdir(dir: int, /) -> list[str]:
"""
With no argument, list the current directory. Otherwise list the given directory.
"""
@overload
def listdir(dir: str, /) -> list[str]:
"""
With no argument, list the current directory. Otherwise list the given directory.
"""
@overload
def listdir(dir: bytes, /) -> list[bytes]:
"""
With no argument, list the current directory. Otherwise list the given directory.
"""
@overload
def listdir(dir: _PathLike[str], /) -> list[str]:
"""
With no argument, list the current directory. Otherwise list the given directory.
"""
@overload
def listdir(dir: _PathLike[bytes], /) -> list[bytes]:
"""
With no argument, list the current directory. Otherwise list the given directory.
"""
def mkdir(path: _AnyPath, /) -> None:
"""
Create a new directory.
"""
def remove(path: _AnyPath, /) -> None:
"""
Remove a file.
"""
def rmdir(path: _AnyPath, /) -> None:
"""
Remove a directory.
"""
def rename(old_path: _AnyPath, new_path: _AnyPath, /) -> None:
"""
Rename a file.
"""
def stat(
path: _FdOrAnyPath, /
) -> tuple[int, int, int, int, int, int, int, int, int, int]:
"""
Get the status of a file or directory.
"""
def statvfs(
path: _FdOrAnyPath, /
) -> tuple[int, int, int, int, int, int, int, int, int, int]:
"""
Get the status of a fileystem.
Returns a tuple with the filesystem information in the following order:
* ``f_bsize`` -- file system block size
* ``f_frsize`` -- fragment size
* ``f_blocks`` -- size of fs in f_frsize units
* ``f_bfree`` -- number of free blocks
* ``f_bavail`` -- number of free blocks for unprivileged users
* ``f_files`` -- number of inodes
* ``f_ffree`` -- number of free inodes
* ``f_favail`` -- number of free inodes for unprivileged users
* ``f_flag`` -- mount flags
* ``f_namemax`` -- maximum filename length
Parameters related to inodes: ``f_files``, ``f_ffree``, ``f_avail``
and the ``f_flags`` parameter may return ``0`` as they can be unavailable
in a port-specific implementation.
"""
def sync() -> None:
"""
Sync all filesystems.
"""
def dupterm(stream_object: IOBase | None, index: int = 0, /) -> IOBase | None:
"""
Duplicate or switch the MicroPython terminal (the REPL) on the given `stream`-like
object. The *stream_object* argument must be a native stream object, or derive
from ``io.IOBase`` and implement the ``readinto()`` and
``write()`` methods. The stream should be in non-blocking mode and
``readinto()`` should return ``None`` if there is no data available for reading.
After calling this function all terminal output is repeated on this stream,
and any input that is available on the stream is passed on to the terminal input.
The *index* parameter should be a non-negative integer and specifies which
duplication slot is set. A given port may implement more than one slot (slot 0
will always be available) and in that case terminal input and output is
duplicated on all the slots that are set.
If ``None`` is passed as the *stream_object* then duplication is cancelled on
the slot given by *index*.
The function returns the previous stream-like object in the given slot.
"""
def mount(
fsobj: "AbstractBlockDev", mount_point: str, /, *, readonly: bool = False
) -> IOBase | None:
"""
Mount the filesystem object *fsobj* at the location in the VFS given by the
*mount_point* string. *fsobj* can be a a VFS object that has a ``mount()``
method, or a block device. If it's a block device then the filesystem type
is automatically detected (an exception is raised if no filesystem was
recognised). *mount_point* may be ``'/'`` to mount *fsobj* at the root,
or ``'/'`` to mount it at a subdirectory under the root.
If *readonly* is ``True`` then the filesystem is mounted read-only.
During the mount process the method ``mount()`` is called on the filesystem
object.
Will raise ``OSError(EPERM)`` if *mount_point* is already mounted.
Filesystem mounting
-------------------
Some ports provide a Virtual Filesystem (VFS) and the ability to mount multiple
"real" filesystems within this VFS. Filesystem objects can be mounted at either
the root of the VFS, or at a subdirectory that lives in the root. This allows
dynamic and flexible configuration of the filesystem that is seen by Python
programs. Ports that have this functionality provide the :func:`mount` and
:func:`umount` functions, and possibly various filesystem implementations
represented by VFS classes.
"""
def umount(mount_point: str, /) -> None:
"""
Unmount a filesystem. *mount_point* can be a string naming the mount location,
or a previously-mounted filesystem object. During the unmount process the
method ``umount()`` is called on the filesystem object.
Will raise ``OSError(EINVAL)`` if *mount_point* is not found.
"""
class VfsFat("AbstractBlockDev"):
"""
"""
def __init__(self, block_dev: "AbstractBlockDev", /):
"""
Create a filesystem object that uses the FAT filesystem format. Storage of
the FAT filesystem is provided by *block_dev*.
Objects created by this constructor can be mounted using :func:`mount`.
"""
@staticmethod
def mkfs(block_dev: "AbstractBlockDev", /) -> None:
"""
Build a FAT filesystem on *block_dev*.
"""
class VfsLfs1("AbstractBlockDev"):
"""
"""
def __init__(
self,
block_dev: "AbstractBlockDev",
readsize: int = 32,
progsize: int = 32,
lookahead: int = 32,
/,
):
"""
Create a filesystem object that uses the `littlefs v1 filesystem format`_.
Storage of the littlefs filesystem is provided by *block_dev*, which must
support the :ref:`extended interface `.
Objects created by this constructor can be mounted using :func:`mount`.
See :ref:`filesystem` for more information.
"""
@staticmethod
def mkfs(
block_dev: "AbstractBlockDev",
readsize: int = 32,
progsize: int = 32,
lookahead: int = 32,
/,
) -> None:
"""
Build a Lfs1 filesystem on *block_dev*.
.. note:: There are reports of littlefs v1 failing in certain situations,
for details see `littlefs issue 347`_.
"""
class VfsLfs2("AbstractBlockDev"):
"""
"""
def __init__(
self,
block_dev: "AbstractBlockDev",
readsize: int = 32,
progsize: int = 32,
lookahead: int = 32,
mtime: bool = True,
/,
):
"""
Create a filesystem object that uses the `littlefs v2 filesystem format`_.
Storage of the littlefs filesystem is provided by *block_dev*, which must
support the :ref:`extended interface `.
Objects created by this constructor can be mounted using :func:`mount`.
The *mtime* argument enables modification timestamps for files, stored using
littlefs attributes. This option can be disabled or enabled differently each
mount time and timestamps will only be added or updated if *mtime* is enabled,
otherwise the timestamps will remain untouched. Littlefs v2 filesystems without
timestamps will work without reformatting and timestamps will be added
transparently to existing files once they are opened for writing. When *mtime*
is enabled `os.stat` on files without timestamps will return 0 for the timestamp.
See :ref:`filesystem` for more information.
"""
@staticmethod
def mkfs(
block_dev: "AbstractBlockDev",
readsize: int = 32,
progsize: int = 32,
lookahead: int = 32,
mtime: bool = True,
/,
) -> None:
"""
Build a Lfs2 filesystem on *block_dev*.
.. note:: There are reports of littlefs v2 failing in certain situations,
for details see `littlefs issue 295`_.
"""
@runtime_checkable
class AbstractBlockDev(Protocol):
"""
Block devices
-------------
A block device is an object which implements the block protocol. This enables a
device to support MicroPython filesystems. The physical hardware is represented
by a user defined class. The :class:`AbstractBlockDev` class is a template for
the design of such a class: MicroPython does not actually provide that class,
but an actual block device class must implement the methods described below.
A concrete implementation of this class will usually allow access to the
memory-like functionality of a piece of hardware (like flash memory). A block
device can be formatted to any supported filesystem and mounted using ``os``
methods.
See :ref:`filesystem` for example implementations of block devices using the
two variants of the block protocol described below.
.. _block-device-interface:
Simple and extended interface
.............................
There are two compatible signatures for the ``readblocks`` and ``writeblocks``
methods (see below), in order to support a variety of use cases. A given block
device may implement one form or the other, or both at the same time. The second
form (with the offset parameter) is referred to as the "extended interface".
Some filesystems (such as littlefs) that require more control over write
operations, for example writing to sub-block regions without erasing, may require
that the block device supports the extended interface.
"""
def __init__(self):
"""
Construct a block device object. The parameters to the constructor are
dependent on the specific block device.
"""
@overload
def readblocks(self, block_num: int, buf: bytearray, /) -> None:
"""
The first form reads aligned, multiples of blocks.
Starting at the block given by the index *block_num*, read blocks from
the device into *buf* (an array of bytes).
The number of blocks to read is given by the length of *buf*,
which will be a multiple of the block size.
The second form allows reading at arbitrary locations within a block,
and arbitrary lengths.
Starting at block index *block_num*, and byte offset within that block
of *offset*, read bytes from the device into *buf* (an array of bytes).
The number of bytes to read is given by the length of *buf*.
"""
@overload
def readblocks(self, block_num: int, buf: bytearray, offset: int, /) -> None:
"""
The first form reads aligned, multiples of blocks.
Starting at the block given by the index *block_num*, read blocks from
the device into *buf* (an array of bytes).
The number of blocks to read is given by the length of *buf*,
which will be a multiple of the block size.
The second form allows reading at arbitrary locations within a block,
and arbitrary lengths.
Starting at block index *block_num*, and byte offset within that block
of *offset*, read bytes from the device into *buf* (an array of bytes).
The number of bytes to read is given by the length of *buf*.
"""
@overload
def writeblocks(self, block_num: int, buf: bytes | bytearray, /) -> None:
"""
The first form writes aligned, multiples of blocks, and requires that the
blocks that are written to be first erased (if necessary) by this method.
Starting at the block given by the index *block_num*, write blocks from
*buf* (an array of bytes) to the device.
The number of blocks to write is given by the length of *buf*,
which will be a multiple of the block size.
The second form allows writing at arbitrary locations within a block,
and arbitrary lengths. Only the bytes being written should be changed,
and the caller of this method must ensure that the relevant blocks are
erased via a prior ``ioctl`` call.
Starting at block index *block_num*, and byte offset within that block
of *offset*, write bytes from *buf* (an array of bytes) to the device.
The number of bytes to write is given by the length of *buf*.
Note that implementations must never implicitly erase blocks if the offset
argument is specified, even if it is zero.
"""
@overload
def writeblocks(
self, block_num: int, buf: bytes | bytearray, offset: int, /
) -> None:
"""
The first form writes aligned, multiples of blocks, and requires that the
blocks that are written to be first erased (if necessary) by this method.
Starting at the block given by the index *block_num*, write blocks from
*buf* (an array of bytes) to the device.
The number of blocks to write is given by the length of *buf*,
which will be a multiple of the block size.
The second form allows writing at arbitrary locations within a block,
and arbitrary lengths. Only the bytes being written should be changed,
and the caller of this method must ensure that the relevant blocks are
erased via a prior ``ioctl`` call.
Starting at block index *block_num*, and byte offset within that block
of *offset*, write bytes from *buf* (an array of bytes) to the device.
The number of bytes to write is given by the length of *buf*.
Note that implementations must never implicitly erase blocks if the offset
argument is specified, even if it is zero.
"""
@overload
def ioctl(self, op: int, arg: int) -> int | None:
"""
Control the block device and query its parameters. The operation to
perform is given by *op* which is one of the following integers:
- 1 -- initialise the device (*arg* is unused)
- 2 -- shutdown the device (*arg* is unused)
- 3 -- sync the device (*arg* is unused)
- 4 -- get a count of the number of blocks, should return an integer
(*arg* is unused)
- 5 -- get the number of bytes in a block, should return an integer,
or ``None`` in which case the default value of 512 is used
(*arg* is unused)
- 6 -- erase a block, *arg* is the block number to erase
As a minimum ``ioctl(4, ...)`` must be intercepted; for littlefs
``ioctl(6, ...)`` must also be intercepted. The need for others is
hardware dependent.
Prior to any call to ``writeblocks(block, ...)`` littlefs issues
``ioctl(6, block)``. This enables a device driver to erase the block
prior to a write if the hardware requires it. Alternatively a driver
might intercept ``ioctl(6, block)`` and return 0 (success). In this case
the driver assumes responsibility for detecting the need for erasure.
Unless otherwise stated ``ioctl(op, arg)`` can return ``None``.
Consequently an implementation can ignore unused values of ``op``. Where
``op`` is intercepted, the return value for operations 4 and 5 are as
detailed above. Other operations should return 0 on success and non-zero
for failure, with the value returned being an ``OSError`` errno code.
"""
@overload
def ioctl(self, op: Literal[4, 5], arg: int) -> int:
"""
Control the block device and query its parameters. The operation to
perform is given by *op* which is one of the following integers:
- 1 -- initialise the device (*arg* is unused)
- 2 -- shutdown the device (*arg* is unused)
- 3 -- sync the device (*arg* is unused)
- 4 -- get a count of the number of blocks, should return an integer
(*arg* is unused)
- 5 -- get the number of bytes in a block, should return an integer,
or ``None`` in which case the default value of 512 is used
(*arg* is unused)
- 6 -- erase a block, *arg* is the block number to erase
As a minimum ``ioctl(4, ...)`` must be intercepted; for littlefs
``ioctl(6, ...)`` must also be intercepted. The need for others is
hardware dependent.
Prior to any call to ``writeblocks(block, ...)`` littlefs issues
``ioctl(6, block)``. This enables a device driver to erase the block
prior to a write if the hardware requires it. Alternatively a driver
might intercept ``ioctl(6, block)`` and return 0 (success). In this case
the driver assumes responsibility for detecting the need for erasure.
Unless otherwise stated ``ioctl(op, arg)`` can return ``None``.
Consequently an implementation can ignore unused values of ``op``. Where
``op`` is intercepted, the return value for operations 4 and 5 are as
detailed above. Other operations should return 0 on success and non-zero
for failure, with the value returned being an ``OSError`` errno code.
"""
@overload
def ioctl(self, op: Literal[1, 2, 3, 6], arg: int) -> int | None:
"""
Control the block device and query its parameters. The operation to
perform is given by *op* which is one of the following integers:
- 1 -- initialise the device (*arg* is unused)
- 2 -- shutdown the device (*arg* is unused)
- 3 -- sync the device (*arg* is unused)
- 4 -- get a count of the number of blocks, should return an integer
(*arg* is unused)
- 5 -- get the number of bytes in a block, should return an integer,
or ``None`` in which case the default value of 512 is used
(*arg* is unused)
- 6 -- erase a block, *arg* is the block number to erase
As a minimum ``ioctl(4, ...)`` must be intercepted; for littlefs
``ioctl(6, ...)`` must also be intercepted. The need for others is
hardware dependent.
Prior to any call to ``writeblocks(block, ...)`` littlefs issues
``ioctl(6, block)``. This enables a device driver to erase the block
prior to a write if the hardware requires it. Alternatively a driver
might intercept ``ioctl(6, block)`` and return 0 (success). In this case
the driver assumes responsibility for detecting the need for erasure.
Unless otherwise stated ``ioctl(op, arg)`` can return ``None``.
Consequently an implementation can ignore unused values of ``op``. Where
``op`` is intercepted, the return value for operations 4 and 5 are as
detailed above. Other operations should return 0 on success and non-zero
for failure, with the value returned being an ``OSError`` errno code.
"""
================================================
FILE: typehints/stdlib/ure.pyi
================================================
"""
regular expressions.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/re.rst.
=======================================
.. module:: re
:synopsis: regular expressions
|see_cpython_module| :mod:`python:re`.
This module implements regular expression operations. Regular expression
syntax supported is a subset of CPython ``re`` module (and actually is
a subset of POSIX extended regular expressions).
Supported operators and special sequences are:
``.``
Match any character.
``[...]``
Match set of characters. Individual characters and ranges are supported,
including negated sets (e.g. ``[^a-c]``).
``^``
Match the start of the string.
``$``
Match the end of the string.
``?``
Match zero or one of the previous sub-pattern.
``*``
Match zero or more of the previous sub-pattern.
``+``
Match one or more of the previous sub-pattern.
``??``
Non-greedy version of ``?``, match zero or one, with the preference
for zero.
``*?``
Non-greedy version of ``*``, match zero or more, with the preference
for the shortest match.
``+?``
Non-greedy version of ``+``, match one or more, with the preference
for the shortest match.
``|``
Match either the left-hand side or the right-hand side sub-patterns of
this operator.
``(...)``
Grouping. Each group is capturing (a substring it captures can be accessed
with `match.group()` method).
``\d``
Matches digit. Equivalent to ``[0-9]``.
``\D``
Matches non-digit. Equivalent to ``[^0-9]``.
``\s``
Matches whitespace. Equivalent to ``[ \t-\r]``.
``\S``
Matches non-whitespace. Equivalent to ``[^ \t-\r]``.
``\w``
Matches "word characters" (ASCII only). Equivalent to ``[A-Za-z0-9_]``.
``\W``
Matches non "word characters" (ASCII only). Equivalent to ``[^A-Za-z0-9_]``.
``\``
Escape character. Any other character following the backslash, except
for those listed above, is taken literally. For example, ``\*`` is
equivalent to literal ``*`` (not treated as the ``*`` operator).
Note that ``\r``, ``\n``, etc. are not handled specially, and will be
equivalent to literal letters ``r``, ``n``, etc. Due to this, it's
not recommended to use raw Python strings (``r""``) for regular
expressions. For example, ``r"\r\n"`` when used as the regular
expression is equivalent to ``"rn"``. To match CR character followed
by LF, use ``"\r\n"``.
**NOT SUPPORTED**:
* counted repetitions (``{m,n}``)
* named groups (``(?P...)``)
* non-capturing groups (``(?:...)``)
* more advanced assertions (``\b``, ``\B``)
* special character escapes like ``\r``, ``\n`` - use Python's own escaping
instead
* etc.
Example::
import re
# As re doesn't support escapes itself, use of r"" strings is not
# recommended.
regex = re.compile("[\r\n]")
regex.split("line1\rline2\nline3\r\n")
# Result:
# ['line1', 'line2', 'line3', '', '']
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import AnyStr, Callable, Generic, Final, Any
_StrLike: Final = str | bytes
def compile(regex_str: _StrLike, flags: int = ..., /) -> "ure":
"""
Compile regular expression, return `regex ` object.
"""
def match(regex_str: _StrLike, string: AnyStr, /) -> "Match[AnyStr]":
"""
Compile *regex_str* and match against *string*. Match always happens
from starting position in a string.
"""
def search(regex_str: _StrLike, string: AnyStr, /) -> "Match[AnyStr]":
"""
Compile *regex_str* and search it in a *string*. Unlike `match`, this will search
string for first position which matches regex (which still may be
0 if regex is anchored).
"""
def sub(
regex_str: _StrLike,
replace: AnyStr | Callable[["Match[AnyStr]"], AnyStr],
string: AnyStr,
count: int = 0,
flags: int = 0,
/,
) -> AnyStr:
"""
Compile *regex_str* and search for it in *string*, replacing all matches
with *replace*, and returning the new string.
*replace* can be a string or a function. If it is a string then escape
sequences of the form ``\`` and ``\g`` can be used to
expand to the corresponding group (or an empty string for unmatched groups).
If *replace* is a function then it must take a single argument (the match)
and should return a replacement string.
If *count* is specified and non-zero then substitution will stop after
this many substitutions are made. The *flags* argument is ignored.
Note: availability of this function depends on :term:`MicroPython port`.
"""
DEBUG: Final[int] = ...
"""
Flag value, display debug information about compiled expression.
(Availability depends on :term:`MicroPython port`.)
"""
# noinspection PyPep8Naming
class ure:
"""
Compiled regular expression. Instances of this class are created using
`re.compile()`.
"""
def match(self, string: AnyStr, /) -> "Match[AnyStr]":
"""
Similar to the module-level functions :meth:`match`, :meth:`search`
and :meth:`sub`.
Using methods is (much) more efficient if the same regex is applied to
multiple strings.
"""
def search(self, string: AnyStr, /) -> "Match[AnyStr]":
"""
Similar to the module-level functions :meth:`match`, :meth:`search`
and :meth:`sub`.
Using methods is (much) more efficient if the same regex is applied to
multiple strings.
"""
def sub(
self,
replace: AnyStr | Callable[["Match[AnyStr]"], AnyStr],
string: AnyStr,
count: int = 0,
flags: int = 0,
/,
) -> AnyStr:
"""
Similar to the module-level functions :meth:`match`, :meth:`search`
and :meth:`sub`.
Using methods is (much) more efficient if the same regex is applied to
multiple strings.
"""
def split(self, string: AnyStr, max_split: int = -1, /) -> list[AnyStr]:
"""
Split a *string* using regex. If *max_split* is given, it specifies
maximum number of splits to perform. Returns list of strings (there
may be up to *max_split+1* elements if it's specified).
"""
class Match(Generic[AnyStr]):
"""
Match objects as returned by `match()` and `search()` methods, and passed
to the replacement function in `sub()`.
The name, `Match`, used for typing is not the same as the runtime name, `match` (note lowercase `m`).
The reason for this difference is that the runtime uses `match` as both a class name and as a method name and
this is not possible within code written entirely in Python and therefore not possible within typing code.
"""
def group(self, index: int, /) -> AnyStr:
"""
Return matching (sub)string. *index* is 0 for entire match,
1 and above for each capturing group. Only numeric groups are supported.
"""
def groups(self) -> tuple[AnyStr | Any, ...]:
"""
Return a tuple containing all the substrings of the groups of the match.
Note: availability of this method depends on :term:`MicroPython port`.
"""
def start(self, index: int = ..., /) -> int:
"""
Return the index in the original string of the start or end of the
substring group that was matched. *index* defaults to the entire
group, otherwise it will select a group.
Note: availability of these methods depends on :term:`MicroPython port`.
"""
def end(self, index: int = ..., /) -> int:
"""
Return the index in the original string of the start or end of the
substring group that was matched. *index* defaults to the entire
group, otherwise it will select a group.
Note: availability of these methods depends on :term:`MicroPython port`.
"""
def span(self, index: int = ..., /) -> tuple[int, int]:
"""
Returns the 2-tuple ``(match.start(index), match.end(index))``.
Note: availability of this method depends on :term:`MicroPython port`.
"""
================================================
FILE: typehints/stdlib/uselect.pyi
================================================
"""
wait for events on a set of streams.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/select.rst.
====================================================
.. module:: select
:synopsis: wait for events on a set of streams
|see_cpython_module| :mod:`python:select`.
This module provides functions to efficiently wait for events on multiple
`streams ` (select streams which are ready for operations).
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import Iterable, Any, Final, Iterator
from uio import IOBase
POLLIN: Final[int] = ...
"""Data available for reading."""
POLLOUT: Final[int] = ...
"""More data can be written."""
POLLHUP: Final[int] = ...
"""Socket is no longer connected."""
POLLERR: Final[int] = ...
"""Socket got an asynchronous error."""
def poll() -> "Poll":
"""
Create an instance of the Poll class.
"""
def select(
rlist: Iterable[Any],
wlist: Iterable[Any],
xlist: Iterable[Any],
timeout: int = -1,
/,
) -> list[tuple[Any, int, Any, ...]]:
"""
Wait for activity on a set of objects.
This function is provided by some MicroPython ports for compatibility
and is not efficient. Usage of :class:`Poll` is recommended instead.
"""
class Poll:
"""
The name, `Poll`, used for typing is not the same as the runtime name, `poll` (note lowercase `p`).
The reason for this difference is that the runtime uses `poll` as both a class name and as a method name and
this is not possible within code written entirely in Python and therefore not possible within typing code.
"""
def register(self, obj: IOBase, eventmask: int = POLLIN | POLLOUT, /) -> None:
"""
Register `stream` *obj* for polling. *eventmask* is logical OR of:
* ``select.POLLIN`` - data available for reading
* ``select.POLLOUT`` - more data can be written
Note that flags like ``select.POLLHUP`` and ``select.POLLERR`` are
*not* valid as input eventmask (these are unsolicited events which
will be returned from `poll()` regardless of whether they are asked
for). This semantics is per POSIX.
*eventmask* defaults to ``select.POLLIN | select.POLLOUT``.
It is OK to call this function multiple times for the same *obj*.
Successive calls will update *obj*'s eventmask to the value of
*eventmask* (i.e. will behave as `modify()`).
"""
def unregister(self, obj: IOBase, /) -> None:
"""
Unregister *obj* from polling.
"""
def modify(self, obj: IOBase, eventmask: int, /) -> None:
"""
Modify the *eventmask* for *obj*. If *obj* is not registered, `OSError`
is raised with error of ENOENT.
"""
def poll(self, timeout: int = -1, /) -> list[tuple[Any, int, Any, ...]]:
"""
Wait for at least one of the registered objects to become ready or have an
exceptional condition, with optional timeout in milliseconds (if *timeout*
arg is not specified or -1, there is no timeout).
Returns list of (``obj``, ``event``, ...) tuples. There may be other elements in
tuple, depending on a platform and version, so don't assume that its size is 2.
The ``event`` element specifies which events happened with a stream and
is a combination of ``select.POLL*`` constants described above. Note that
flags ``select.POLLHUP`` and ``select.POLLERR`` can be returned at any time
(even if were not asked for), and must be acted on accordingly (the
corresponding stream unregistered from poll and likely closed), because
otherwise all further invocations of `poll()` may return immediately with
these flags set for this stream again.
In case of timeout, an empty list is returned.
.. admonition:: Difference to CPython
:class: attention
Tuples returned may contain more than 2 elements as described above.
"""
def ipoll(
self, timeout: int = -1, flags: int = 0, /
) -> Iterator[tuple[Any, int, Any, ...]]:
"""
Like :meth:`poll.poll`, but instead returns an iterator which yields a
`callee-owned tuple`. This function provides an efficient, allocation-free
way to poll on streams.
If *flags* is 1, one-shot behaviour for events is employed: streams for
which events happened will have their event masks automatically reset
(equivalent to ``poll.modify(obj, 0)``), so new events for such a stream
won't be processed until new mask is set with `poll.modify()`. This
behaviour is useful for asynchronous I/O schedulers.
.. admonition:: Difference to CPython
:class: attention
This function is a MicroPython extension.
"""
================================================
FILE: typehints/stdlib/usocket.pyi
================================================
"""
socket.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/socket.rst.
******************************
.. module:: socket
:synopsis: socket module
|see_cpython_module| :mod:`python:socket`.
This module provides access to the BSD socket interface.
.. admonition:: Difference to CPython
:class: attention
For efficiency and consistency, socket objects in MicroPython implement a `stream`
(file-like) interface directly. In CPython, you need to convert a socket to
a file-like object using `makefile()` method. This method is still supported
by MicroPython (but is a no-op), so where compatibility with CPython matters,
be sure to use it.
Socket address format(s)
------------------------
The native socket address format of the ``socket`` module is an opaque data type
returned by `getaddrinfo` function, which must be used to resolve textual address
(including numeric addresses)::
sockaddr = socket.getaddrinfo('www.micropython.org', 80)[0][-1]
# You must use getaddrinfo() even for numeric addresses
sockaddr = socket.getaddrinfo('127.0.0.1', 80)[0][-1]
# Now you can use that address
sock.connect(addr)
Using `getaddrinfo` is the most efficient (both in terms of memory and processing
power) and portable way to work with addresses.
However, ``socket`` module (note the difference with native MicroPython
``socket`` module described here) provides CPython-compatible way to specify
addresses using tuples, as described below. Note that depending on a
:term:`MicroPython port`, ``socket`` module can be builtin or need to be
installed from `micropython-lib` (as in the case of :term:`MicroPython Unix port`),
and some ports still accept only numeric addresses in the tuple format,
and require to use `getaddrinfo` function to resolve domain names.
Summing up:
* Always use `getaddrinfo` when writing portable applications.
* Tuple addresses described below can be used as a shortcut for
quick hacks and interactive use, if your port supports them.
Tuple address format for ``socket`` module:
* IPv4: *(ipv4_address, port)*, where *ipv4_address* is a string with
dot-notation numeric IPv4 address, e.g. ``"8.8.8.8"``, and *port* is and
integer port number in the range 1-65535. Note the domain names are not
accepted as *ipv4_address*, they should be resolved first using
`socket.getaddrinfo()`.
* IPv6: *(ipv6_address, port, flowinfo, scopeid)*, where *ipv6_address*
is a string with colon-notation numeric IPv6 address, e.g. ``"2001:db8::1"``,
and *port* is an integer port number in the range 1-65535. *flowinfo*
must be 0. *scopeid* is the interface scope identifier for link-local
addresses. Note the domain names are not accepted as *ipv6_address*,
they should be resolved first using `socket.getaddrinfo()`. Availability
of IPv6 support depends on a :term:`MicroPython port`.
.. exception:: socket.error
MicroPython does NOT have this exception.
.. admonition:: Difference to CPython
:class: attention
CPython used to have a ``socket.error`` exception which is now deprecated,
and is an alias of `OSError`. In MicroPython, use `OSError` directly.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import Final, Any, Literal, overload
from uio import AnyReadableBuf, AnyWritableBuf
_Address: Final = tuple[str, int] | tuple[str, int, int, int] | str
def socket(
af: int = "AF_INET", type: int = "SOCK_STREAM", proto: int = "IPPROTO_TCP", /,
) -> "Socket":
"""
Create a new socket using the given address family, socket type and
protocol number. Note that specifying *proto* in most cases is not
required (and not recommended, as some MicroPython ports may omit
``IPPROTO_*`` constants). Instead, *type* argument will select needed
protocol automatically::
# Create STREAM TCP socket
socket(AF_INET, SOCK_STREAM)
# Create DGRAM UDP socket
socket(AF_INET, SOCK_DGRAM)
"""
def getaddrinfo(
host: str, port: int, af: int = 0, type: int = 0, proto: int = 0, flags: int = 0, /,
) -> list[tuple[int, int, int, str, tuple[str, int] | tuple[str, int, int, int]]]:
"""
Translate the host/port argument into a sequence of 5-tuples that contain all the
necessary arguments for creating a socket connected to that service. Arguments
*af*, *type*, and *proto* (which have the same meaning as for the `socket()` function)
can be used to filter which kind of addresses are returned. If a parameter is not
specified or zero, all combinations of addresses can be returned (requiring
filtering on the user side).
The resulting list of 5-tuples has the following structure::
(family, type, proto, canonname, sockaddr)
The following example shows how to connect to a given url::
s = socket.socket()
# This assumes that if "type" is not specified, an address for
# SOCK_STREAM will be returned, which may be not true
s.connect(socket.getaddrinfo('www.micropython.org', 80)[0][-1])
Recommended use of filtering params::
s = socket.socket()
# Guaranteed to return an address which can be connect'ed to for
# stream operation.
s.connect(socket.getaddrinfo('www.micropython.org', 80, 0, SOCK_STREAM)[0][-1])
.. admonition:: Difference to CPython
:class: attention
CPython raises a ``socket.gaierror`` exception (`OSError` subclass) in case
of error in this function. MicroPython doesn't have ``socket.gaierror``
and raises OSError directly. Note that error numbers of `getaddrinfo()`
form a separate namespace and may not match error numbers from
the :mod:`errno` module. To distinguish `getaddrinfo()` errors, they are
represented by negative numbers, whereas standard system errors are
positive numbers (error numbers are accessible using ``e.args[0]`` property
from an exception object). The use of negative values is a provisional
detail which may change in the future.
"""
def inet_ntop(af: int, bin_addr: bytes, /) -> str:
"""
Convert a binary network address *bin_addr* of the given address family *af*
to a textual representation::
>>> socket.inet_ntop(socket.AF_INET, b"\x7f\0\0\1")
'127.0.0.1'
"""
def inet_pton(af: int, txt_addr: str, /) -> bytes:
"""
Convert a textual network address *txt_addr* of the given address family *af*
to a binary representation::
>>> socket.inet_pton(socket.AF_INET, "1.2.3.4")
b'\x01\x02\x03\x04'
"""
AF_INET: Final[int] = ...
"""
Address family types. Availability depends on a particular :term:`MicroPython port`.
"""
AF_INET6: Final[int] = ...
"""
Address family types. Availability depends on a particular :term:`MicroPython port`.
"""
SOCK_STREAM: Final[int] = ...
"""
Socket types.
"""
SOCK_DGRAM: Final[int] = ...
"""
Socket types.
"""
IPPROTO_UDP: Final[int] = ...
"""
IP protocol numbers. Availability depends on a particular :term:`MicroPython port`.
Note that you don't need to specify these in a call to `socket.socket()`,
because `SOCK_STREAM` socket type automatically selects `IPPROTO_TCP`, and
`SOCK_DGRAM` - `IPPROTO_UDP`. Thus, the only real use of these constants
is as an argument to `setsockopt()`.
"""
IPPROTO_TCP: Final[int] = ...
"""
IP protocol numbers. Availability depends on a particular :term:`MicroPython port`.
Note that you don't need to specify these in a call to `socket.socket()`,
because `SOCK_STREAM` socket type automatically selects `IPPROTO_TCP`, and
`SOCK_DGRAM` - `IPPROTO_UDP`. Thus, the only real use of these constants
is as an argument to `setsockopt()`.
"""
SOL_SOCKET: Final[int] = ...
"""
Socket option levels (an argument to `setsockopt()`). The exact
inventory depends on a :term:`MicroPython port`.
"""
SO_REUSEADDR: Final[int] = ...
"""
Socket options (an argument to `setsockopt()`). The exact
inventory depends on a :term:`MicroPython port`.
"""
IPPROTO_SEC: Final[int] = ...
"""
Special protocol value to create SSL-compatible socket.
Constants specific to WiPy:
"""
class Socket:
"""
A unix like socket, for more information see module ``socket``'s description.
The name, `Socket`, used for typing is not the same as the runtime name, `socket` (note lowercase `s`).
The reason for this difference is that the runtime uses `socket` as both a class name and as a method name and
this is not possible within code written entirely in Python and therefore not possible within typing code.
"""
def close(self) -> None:
"""
Mark the socket closed and release all resources. Once that happens, all future operations
on the socket object will fail. The remote end will receive EOF indication if
supported by protocol.
Sockets are automatically closed when they are garbage-collected, but it is recommended
to `close()` them explicitly as soon you finished working with them.
"""
def bind(self, address: _Address | bytes, /) -> None:
"""
Bind the socket to *address*. The socket must not already be bound.
"""
def listen(self, backlog: int = ..., /) -> None:
"""
Enable a server to accept connections. If *backlog* is specified, it must be at least 0
(if it's lower, it will be set to 0); and specifies the number of unaccepted connections
that the system will allow before refusing new connections. If not specified, a default
reasonable value is chosen.
"""
def accept(self) -> None:
"""
Accept a connection. The socket must be bound to an address and listening for connections.
The return value is a pair (conn, address) where conn is a new socket object usable to send
and receive data on the connection, and address is the address bound to the socket on the
other end of the connection.
"""
def connect(self, address: _Address | bytes, /) -> None:
"""
Connect to a remote socket at *address*.
"""
def send(self, bytes: AnyReadableBuf, /) -> int:
"""
Send data to the socket. The socket must be connected to a remote socket.
Returns number of bytes sent, which may be smaller than the length of data
("short write").
"""
def sendall(self, bytes: AnyReadableBuf, /) -> None:
"""
Send all data to the socket. The socket must be connected to a remote socket.
Unlike `send()`, this method will try to send all of data, by sending data
chunk by chunk consecutively.
The behaviour of this method on non-blocking sockets is undefined. Due to this,
on MicroPython, it's recommended to use `write()` method instead, which
has the same "no short writes" policy for blocking sockets, and will return
number of bytes sent on non-blocking sockets.
"""
def recv(self, bufsize: int, /) -> bytes:
"""
Receive data from the socket. The return value is a bytes object representing the data
received. The maximum amount of data to be received at once is specified by bufsize.
"""
def sendto(self, bytes: AnyReadableBuf, address: _Address, /) -> int:
"""
Send data to the socket. The socket should not be connected to a remote socket, since the
destination socket is specified by *address*.
"""
def recvfrom(self, bufsize: int, /) -> tuple[bytes, Any]:
"""
Receive data from the socket. The return value is a pair *(bytes, address)* where *bytes* is a
bytes object representing the data received and *address* is the address of the socket sending
the data.
"""
def setsockopt(
self, level: int, optname: int, value: AnyReadableBuf | int, /
) -> None:
"""
Set the value of the given socket option. The needed symbolic constants are defined in the
socket module (SO_* etc.). The *value* can be an integer or a bytes-like object representing
a buffer.
"""
def settimeout(self, value: float | None, /) -> None:
"""
**Note**: Not every port supports this method, see below.
Set a timeout on blocking socket operations. The value argument can be a nonnegative floating
point number expressing seconds, or None. If a non-zero value is given, subsequent socket operations
will raise an `OSError` exception if the timeout period value has elapsed before the operation has
completed. If zero is given, the socket is put in non-blocking mode. If None is given, the socket
is put in blocking mode.
Not every :term:`MicroPython port` supports this method. A more portable and
generic solution is to use `select.poll` object. This allows to wait on
multiple objects at the same time (and not just on sockets, but on generic
`stream` objects which support polling). Example::
# Instead of:
s.settimeout(1.0) # time in seconds
s.read(10) # may timeout
# Use:
poller = select.poll()
poller.register(s, select.POLLIN)
res = poller.poll(1000) # time in milliseconds
if not res:
# s is still not ready for input, i.e. operation timed out
.. admonition:: Difference to CPython
:class: attention
CPython raises a ``socket.timeout`` exception in case of timeout,
which is an `OSError` subclass. MicroPython raises an OSError directly
instead. If you use ``except OSError:`` to catch the exception,
your code will work both in MicroPython and CPython.
"""
def setblocking(self, value: bool, /) -> None:
"""
Set blocking or non-blocking mode of the socket: if flag is false, the socket is set to non-blocking,
else to blocking mode.
This method is a shorthand for certain `settimeout()` calls:
* ``sock.setblocking(True)`` is equivalent to ``sock.settimeout(None)``
* ``sock.setblocking(False)`` is equivalent to ``sock.settimeout(0)``
"""
@overload
def makefile(
self, mode: Literal["rb", "wb", "rwb"] = "rb", buffering: int = 0, /
) -> Socket:
"""
Return a file object associated with the socket. The exact returned type depends on the arguments
given to makefile(). The support is limited to binary modes only ('rb', 'wb', and 'rwb').
CPython's arguments: *encoding*, *errors* and *newline* are not supported.
.. admonition:: Difference to CPython
:class: attention
As MicroPython doesn't support buffered streams, values of *buffering*
parameter is ignored and treated as if it was 0 (unbuffered).
.. admonition:: Difference to CPython
:class: attention
Closing the file object returned by makefile() WILL close the
original socket as well.
"""
@overload
def makefile(self, mode: str, buffering: int = 0, /) -> Socket:
"""
Return a file object associated with the socket. The exact returned type depends on the arguments
given to makefile(). The support is limited to binary modes only ('rb', 'wb', and 'rwb').
CPython's arguments: *encoding*, *errors* and *newline* are not supported.
.. admonition:: Difference to CPython
:class: attention
As MicroPython doesn't support buffered streams, values of *buffering*
parameter is ignored and treated as if it was 0 (unbuffered).
.. admonition:: Difference to CPython
:class: attention
Closing the file object returned by makefile() WILL close the
original socket as well.
"""
@overload
def read(self) -> bytes:
"""
Read up to size bytes from the socket. Return a bytes object. If *size* is not given, it
reads all data available from the socket until EOF; as such the method will not return until
the socket is closed. This function tries to read as much data as
requested (no "short reads"). This may be not possible with
non-blocking socket though, and then less data will be returned.
"""
@overload
def read(self, size: int, /) -> bytes:
"""
Read up to size bytes from the socket. Return a bytes object. If *size* is not given, it
reads all data available from the socket until EOF; as such the method will not return until
the socket is closed. This function tries to read as much data as
requested (no "short reads"). This may be not possible with
non-blocking socket though, and then less data will be returned.
"""
@overload
def readinto(self, buf: AnyWritableBuf, /) -> int | None:
"""
Read bytes into the *buf*. If *nbytes* is specified then read at most
that many bytes. Otherwise, read at most *len(buf)* bytes. Just as
`read()`, this method follows "no short reads" policy.
Return value: number of bytes read and stored into *buf*.
"""
@overload
def readinto(self, buf: AnyWritableBuf, nbytes: int, /) -> int | None:
"""
Read bytes into the *buf*. If *nbytes* is specified then read at most
that many bytes. Otherwise, read at most *len(buf)* bytes. Just as
`read()`, this method follows "no short reads" policy.
Return value: number of bytes read and stored into *buf*.
"""
def readline(self) -> bytes:
"""
Read a line, ending in a newline character.
Return value: the line read.
"""
def write(self, buf: AnyReadableBuf, /) -> int | None:
"""
Write the buffer of bytes to the socket. This function will try to
write all data to a socket (no "short writes"). This may be not possible
with a non-blocking socket though, and returned value will be less than
the length of *buf*.
Return value: number of bytes written.
"""
================================================
FILE: typehints/stdlib/ussl.pyi
================================================
"""
TLS/SSL wrapper for socket objects.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/ssl.rst.
|see_cpython_module| :mod:`python:ssl`.
This module provides access to Transport Layer Security (previously and
widely known as “Secure Sockets Layer”) encryption and peer authentication
facilities for network sockets, both client-side and server-side.
.. admonition:: Difference to CPython
:class: attention
The CPython version of ``ssl`` uses ``SSLError``.
This exception does NOT exist. Instead its base class, OSError, is used.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import Final
from uio import StrOrBytesPath
from usocket import Socket
def wrap_socket(
sock: Socket,
server_side: bool = False,
keyfile: StrOrBytesPath | None = None,
certfile: StrOrBytesPath | None = None,
cert_reqs: int = "CERT_NONE",
ca_certs: str | None = None,
do_handshake: bool = True,
/,
) -> Socket:
"""
Takes a `stream` *sock* (usually socket.socket instance of ``SOCK_STREAM`` type),
and returns an instance of ssl.SSLSocket, which wraps the underlying stream in
an SSL context. Returned object has the usual `stream` interface methods like
``read()``, ``write()``, etc.
A server-side SSL socket should be created from a normal socket returned from
:meth:`~socket.socket.accept()` on a non-SSL listening server socket.
- *do_handshake* determines whether the handshake is done as part of the ``wrap_socket``
or whether it is deferred to be done as part of the initial reads or writes
(there is no ``do_handshake`` method as in CPython).
For blocking sockets doing the handshake immediately is standard. For non-blocking
sockets (i.e. when the *sock* passed into ``wrap_socket`` is in non-blocking mode)
the handshake should generally be deferred because otherwise ``wrap_socket`` blocks
until it completes. Note that in AXTLS the handshake can be deferred until the first
read or write but it then blocks until completion.
Depending on the underlying module implementation in a particular
:term:`MicroPython port`, some or all keyword arguments above may be not supported.
"""
CERT_NONE: Final[int] = ...
"""
Supported values for *cert_reqs* parameter.
"""
CERT_OPTIONAL: Final[int] = ...
"""
Supported values for *cert_reqs* parameter.
"""
CERT_REQUIRED: Final[int] = ...
"""
Supported values for *cert_reqs* parameter.
"""
================================================
FILE: typehints/stdlib/ustruct.pyi
================================================
"""
pack and unpack primitive data types.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/struct.rst.
=====================================================
.. module:: struct
:synopsis: pack and unpack primitive data types
|see_cpython_module| :mod:`python:struct`.
Supported size/byte order prefixes: ``@``, ``<``, ``>``, ``!``.
Supported format codes: ``b``, ``B``, ``h``, ``H``, ``i``, ``I``, ``l``,
``L``, ``q``, ``Q``, ``s``, ``P``, ``f``, ``d`` (the latter 2 depending
on the floating-point support).
.. admonition:: Difference to CPython
:class: attention
Whitespace is not supported in format strings.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import Any
from uio import AnyReadableBuf, AnyWritableBuf
def calcsize(fmt: str | bytes, /,) -> int:
"""
Return the number of bytes needed to store the given *fmt*.
"""
def pack(fmt: str | bytes, /, *v: Any) -> bytes:
"""
Pack the values *v1*, *v2*, ... according to the format string *fmt*.
The return value is a bytes object encoding the values.
"""
def pack_into(
fmt: str | bytes, buffer: AnyWritableBuf, offset: int, /, *v: Any
) -> None:
"""
Pack the values *v1*, *v2*, ... according to the format string *fmt*
into a *buffer* starting at *offset*. *offset* may be negative to count
from the end of *buffer*.
"""
def unpack(fmt: str | bytes, data: AnyReadableBuf, /) -> tuple[Any, ...]:
"""
Unpack from the *data* according to the format string *fmt*.
The return value is a tuple of the unpacked values.
"""
def unpack_from(
fmt: str | bytes, data: AnyReadableBuf, offset: int = 0, /
) -> tuple[Any, ...]:
"""
Unpack from the *data* starting at *offset* according to the format string
*fmt*. *offset* may be negative to count from the end of *buffer*. The return
value is a tuple of the unpacked values.
"""
================================================
FILE: typehints/stdlib/usys.pyi
================================================
"""
system specific functions.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/sys.rst.
=======================================
.. module:: sys
:synopsis: system specific functions
|see_cpython_module| :mod:`python:sys`.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import Callable, Final, Literal, NoReturn
from uio import IOBase
class Implementation(tuple[str, tuple[int, int, int], int]):
name: str
version: tuple[int, int, int]
mpy: int
class ModuleType:
__class__: str
__name__: str
def exit(retval: object = 0, /) -> NoReturn:
"""
Terminate current program with a given exit code. Underlyingly, this
function raise as `SystemExit` exception. If an argument is given, its
value given as an argument to `SystemExit`.
"""
def atexit(func: Callable[[], None] | None, /) -> Callable[[], None] | None:
"""
Register *func* to be called upon termination. *func* must be a callable
that takes no arguments, or ``None`` to disable the call. The ``atexit``
function will return the previous value set by this function, which is
initially ``None``.
.. admonition:: Difference to CPython
:class: attention
This function is a MicroPython extension intended to provide similar
functionality to the :mod:`atexit` module in CPython.
"""
def print_exception(exc: BaseException, file: IOBase[str] = "stdout", /) -> None:
"""
Print exception with a traceback to a file-like object *file* (or
`sys.stdout` by default).
.. admonition:: Difference to CPython
:class: attention
This is simplified version of a function which appears in the
``traceback`` module in CPython. Unlike ``traceback.print_exception()``,
this function takes just exception value instead of exception type,
exception value, and traceback object; *file* argument should be
positional; further arguments are not supported. CPython-compatible
``traceback`` module can be found in `micropython-lib`.
"""
argv: Final[list[str]] = ...
"""
A mutable list of arguments the current program was started with.
"""
byteorder: Final[Literal["little", "big"]] = ...
"""
The byte order of the system (``"little"`` or ``"big"``).
"""
implementation: Final[Implementation] = ...
"""
Object with information about the current Python implementation. For
MicroPython, it has following attributes:
* *name* - string "micropython"
* *version* - tuple (major, minor, micro), e.g. (1, 7, 0)
This object is the recommended way to distinguish MicroPython from other
Python implementations (note that it still may not exist in the very
minimal ports).
.. admonition:: Difference to CPython
:class: attention
CPython mandates more attributes for this object, but the actual useful
bare minimum is implemented in MicroPython.
"""
maxsize: Final[int] = ...
"""
Maximum value which a native integer type can hold on the current platform,
or maximum value representable by MicroPython integer type, if it's smaller
than platform max value (that is the case for MicroPython ports without
long int support).
This attribute is useful for detecting "bitness" of a platform (32-bit vs
64-bit, etc.). It's recommended to not compare this attribute to some
value directly, but instead count number of bits in it::
bits = 0
v = sys.maxsize
while v:
bits += 1
v >>= 1
if bits > 32:
# 64-bit (or more) platform
...
else:
# 32-bit (or less) platform
# Note that on 32-bit platform, value of bits may be less than 32
# (e.g. 31) due to peculiarities described above, so use "> 16",
# "> 32", "> 64" style of comparisons.
"""
modules: Final[dict[str, ModuleType]] = ...
"""
Dictionary of loaded modules. On some ports, it may not include builtin
modules.
"""
path: Final[list[str]] = ...
"""
A mutable list of directories to search for imported modules.
"""
platform: Final[str] = ...
"""
The platform that MicroPython is running on. For OS/RTOS ports, this is
usually an identifier of the OS, e.g. ``"linux"``. For baremetal ports it
is an identifier of a board, e.g. ``"pyboard"`` for the original MicroPython
reference board. It thus can be used to distinguish one board from another.
If you need to check whether your program runs on MicroPython (vs other
Python implementation), use `sys.implementation` instead.
"""
stderr: Final[IOBase[str]] = ...
"""
Standard error `stream`.
"""
stdin: Final[IOBase[str]] = ...
"""
Standard input `stream`.
"""
stdout: Final[IOBase[str]] = ...
"""
Standard output `stream`.
"""
version: Final[str] = ...
"""
Python language version that this implementation conforms to, as a string.
"""
version_info: Final[tuple[int, int, int]] = ...
"""
Python language version that this implementation conforms to, as a tuple of ints.
.. admonition:: Difference to CPython
:class: attention
Only the first three version numbers (major, minor, micro) are supported and
they can be referenced only by index, not by name.
"""
================================================
FILE: typehints/stdlib/utime.pyi
================================================
"""
time related functions.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/time.rst.
=====================================
.. module:: time
:synopsis: time related functions
|see_cpython_module| :mod:`python:time`.
The ``time`` module provides functions for getting the current time and date,
measuring time intervals, and for delays.
**Time Epoch**: Unix port uses standard for POSIX systems epoch of
1970-01-01 00:00:00 UTC. However, embedded ports use epoch of
2000-01-01 00:00:00 UTC.
**Maintaining actual calendar date/time**: This requires a
Real Time Clock (RTC). On systems with underlying OS (including some
RTOS), an RTC may be implicit. Setting and maintaining actual calendar
time is responsibility of OS/RTOS and is done outside of MicroPython,
it just uses OS API to query date/time. On baremetal ports however
system time depends on ``machine.RTC()`` object. The current calendar time
may be set using ``machine.RTC().datetime(tuple)`` function, and maintained
by following means:
* By a backup battery (which may be an additional, optional component for
a particular board).
* Using networked time protocol (requires setup by a port/user).
* Set manually by a user on each power-up (many boards then maintain
RTC time across hard resets, though some may require setting it again
in such case).
If actual calendar time is not maintained with a system/MicroPython RTC,
functions below which require reference to current absolute time may
behave not as expected.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from typing import Final, TypeVar
class _TicksMs: ...
class _TicksUs: ...
class _TicksCPU: ...
_Ticks: Final = TypeVar("_Ticks", _TicksMs, _TicksUs, _TicksCPU, int)
def gmtime(secs: int | None = None, /) -> tuple[int, int, int, int, int, int, int, int]:
"""
Convert the time *secs* expressed in seconds since the Epoch (see above) into an
8-tuple which contains: ``(year, month, mday, hour, minute, second, weekday, yearday)``
If *secs* is not provided or None, then the current time from the RTC is used.
The `gmtime()` function returns a date-time tuple in UTC, and `localtime()` returns a
date-time tuple in local time.
The format of the entries in the 8-tuple are:
* year includes the century (for example 2014).
* month is 1-12
* mday is 1-31
* hour is 0-23
* minute is 0-59
* second is 0-59
* weekday is 0-6 for Mon-Sun
* yearday is 1-366
"""
def localtime(
secs: int | None = None, /
) -> tuple[int, int, int, int, int, int, int, int]:
"""
Convert the time *secs* expressed in seconds since the Epoch (see above) into an
8-tuple which contains: ``(year, month, mday, hour, minute, second, weekday, yearday)``
If *secs* is not provided or None, then the current time from the RTC is used.
The `gmtime()` function returns a date-time tuple in UTC, and `localtime()` returns a
date-time tuple in local time.
The format of the entries in the 8-tuple are:
* year includes the century (for example 2014).
* month is 1-12
* mday is 1-31
* hour is 0-23
* minute is 0-59
* second is 0-59
* weekday is 0-6 for Mon-Sun
* yearday is 1-366
"""
def mktime(local_time: tuple[int, int, int, int, int, int, int, int], /) -> int:
"""
This is inverse function of localtime. It's argument is a full 8-tuple
which expresses a time as per localtime. It returns an integer which is
the number of seconds since Jan 1, 2000.
"""
def sleep(seconds: float, /) -> None:
"""
Sleep for the given number of seconds. Some boards may accept *seconds* as a
floating-point number to sleep for a fractional number of seconds. Note that
other boards may not accept a floating-point argument, for compatibility with
them use `sleep_ms()` and `sleep_us()` functions.
"""
def sleep_ms(ms: int, /) -> None:
"""
Delay for given number of milliseconds, should be positive or 0.
This function will delay for at least the given number of milliseconds, but
may take longer than that if other processing must take place, for example
interrupt handlers or other threads. Passing in 0 for *ms* will still allow
this other processing to occur. Use `sleep_us()` for more precise delays.
"""
def sleep_us(us: int, /) -> None:
"""
Delay for given number of microseconds, should be positive or 0.
This function attempts to provide an accurate delay of at least *us*
microseconds, but it may take longer if the system has other higher priority
processing to perform.
"""
def ticks_ms() -> _TicksMs:
"""
Returns an increasing millisecond counter with an arbitrary reference point, that
wraps around after some value.
The wrap-around value is not explicitly exposed, but we will
refer to it as *TICKS_MAX* to simplify discussion. Period of the values is
*TICKS_PERIOD = TICKS_MAX + 1*. *TICKS_PERIOD* is guaranteed to be a power of
two, but otherwise may differ from port to port. The same period value is used
for all of `ticks_ms()`, `ticks_us()`, `ticks_cpu()` functions (for
simplicity). Thus, these functions will return a value in range [*0* ..
*TICKS_MAX*], inclusive, total *TICKS_PERIOD* values. Note that only
non-negative values are used. For the most part, you should treat values returned
by these functions as opaque. The only operations available for them are
`ticks_diff()` and `ticks_add()` functions described below.
Note: Performing standard mathematical operations (+, -) or relational
operators (<, <=, >, >=) directly on these value will lead to invalid
result. Performing mathematical operations and then passing their results
as arguments to `ticks_diff()` or `ticks_add()` will also lead to
invalid results from the latter functions.
"""
def ticks_us() -> _TicksUs:
"""
Just like `ticks_ms()` above, but in microseconds.
"""
def ticks_cpu() -> _TicksCPU:
"""
Similar to `ticks_ms()` and `ticks_us()`, but with the highest possible resolution
in the system. This is usually CPU clocks, and that's why the function is named that
way. But it doesn't have to be a CPU clock, some other timing source available in a
system (e.g. high-resolution timer) can be used instead. The exact timing unit
(resolution) of this function is not specified on ``time`` module level, but
documentation for a specific port may provide more specific information. This
function is intended for very fine benchmarking or very tight real-time loops.
Avoid using it in portable code.
Availability: Not every port implements this function.
"""
def ticks_add(ticks: _Ticks, delta: int, /) -> _Ticks:
"""
Offset ticks value by a given number, which can be either positive or negative.
Given a *ticks* value, this function allows to calculate ticks value *delta*
ticks before or after it, following modular-arithmetic definition of tick values
(see `ticks_ms()` above). *ticks* parameter must be a direct result of call
to `ticks_ms()`, `ticks_us()`, or `ticks_cpu()` functions (or from previous
call to `ticks_add()`). However, *delta* can be an arbitrary integer number
or numeric expression. `ticks_add()` is useful for calculating deadlines for
events/tasks. (Note: you must use `ticks_diff()` function to work with
deadlines.)
Examples::
# Find out what ticks value there was 100ms ago
print(ticks_add(time.ticks_ms(), -100))
# Calculate deadline for operation and test for it
deadline = ticks_add(time.ticks_ms(), 200)
while ticks_diff(deadline, time.ticks_ms()) > 0:
do_a_little_of_something()
# Find out TICKS_MAX used by this port
print(ticks_add(0, -1))
"""
def ticks_diff(ticks1: _Ticks, ticks2: _Ticks, /) -> int:
"""
Measure ticks difference between values returned from `ticks_ms()`, `ticks_us()`,
or `ticks_cpu()` functions, as a signed value which may wrap around.
The argument order is the same as for subtraction
operator, ``ticks_diff(ticks1, ticks2)`` has the same meaning as ``ticks1 - ticks2``.
However, values returned by `ticks_ms()`, etc. functions may wrap around, so
directly using subtraction on them will produce incorrect result. That is why
`ticks_diff()` is needed, it implements modular (or more specifically, ring)
arithmetics to produce correct result even for wrap-around values (as long as they not
too distant inbetween, see below). The function returns **signed** value in the range
[*-TICKS_PERIOD/2* .. *TICKS_PERIOD/2-1*] (that's a typical range definition for
two's-complement signed binary integers). If the result is negative, it means that
*ticks1* occurred earlier in time than *ticks2*. Otherwise, it means that
*ticks1* occurred after *ticks2*. This holds **only** if *ticks1* and *ticks2*
are apart from each other for no more than *TICKS_PERIOD/2-1* ticks. If that does
not hold, incorrect result will be returned. Specifically, if two tick values are
apart for *TICKS_PERIOD/2-1* ticks, that value will be returned by the function.
However, if *TICKS_PERIOD/2* of real-time ticks has passed between them, the
function will return *-TICKS_PERIOD/2* instead, i.e. result value will wrap around
to the negative range of possible values.
Informal rationale of the constraints above: Suppose you are locked in a room with no
means to monitor passing of time except a standard 12-notch clock. Then if you look at
dial-plate now, and don't look again for another 13 hours (e.g., if you fall for a
long sleep), then once you finally look again, it may seem to you that only 1 hour
has passed. To avoid this mistake, just look at the clock regularly. Your application
should do the same. "Too long sleep" metaphor also maps directly to application
behaviour: don't let your application run any single task for too long. Run tasks
in steps, and do time-keeping inbetween.
`ticks_diff()` is designed to accommodate various usage patterns, among them:
* Polling with timeout. In this case, the order of events is known, and you will deal
only with positive results of `ticks_diff()`::
# Wait for GPIO pin to be asserted, but at most 500us
start = time.ticks_us()
while pin.value() == 0:
if time.ticks_diff(time.ticks_us(), start) > 500:
raise TimeoutError
* Scheduling events. In this case, `ticks_diff()` result may be negative
if an event is overdue::
# This code snippet is not optimized
now = time.ticks_ms()
scheduled_time = task.scheduled_time()
if ticks_diff(scheduled_time, now) > 0:
print("Too early, let's nap")
sleep_ms(ticks_diff(scheduled_time, now))
task.run()
elif ticks_diff(scheduled_time, now) == 0:
print("Right at time!")
task.run()
elif ticks_diff(scheduled_time, now) < 0:
print("Oops, running late, tell task to run faster!")
task.run(run_faster=true)
Note: Do not pass `time()` values to `ticks_diff()`, you should use
normal mathematical operations on them. But note that `time()` may (and will)
also overflow. This is known as https://en.wikipedia.org/wiki/Year_2038_problem .
"""
def time() -> int:
"""
Returns the number of seconds, as an integer, since the Epoch, assuming that
underlying RTC is set and maintained as described above. If an RTC is not set, this
function returns number of seconds since a port-specific reference point in time (for
embedded boards without a battery-backed RTC, usually since power up or reset). If you
want to develop portable MicroPython application, you should not rely on this function
to provide higher than second precision. If you need higher precision, absolute
timestamps, use `time_ns()`. If relative times are acceptable then use the
`ticks_ms()` and `ticks_us()` functions. If you need calendar time, `gmtime()` or
`localtime()` without an argument is a better choice.
.. admonition:: Difference to CPython
:class: attention
In CPython, this function returns number of
seconds since Unix epoch, 1970-01-01 00:00 UTC, as a floating-point,
usually having microsecond precision. With MicroPython, only Unix port
uses the same Epoch, and if floating-point precision allows,
returns sub-second precision. Embedded hardware usually doesn't have
floating-point precision to represent both long time ranges and subsecond
precision, so they use integer value with second precision. Some embedded
hardware also lacks battery-powered RTC, so returns number of seconds
since last power-up or from other relative, hardware-specific point
(e.g. reset).
"""
def time_ns() -> int:
"""
Similar to `time()` but returns nanoseconds since the Epoch, as an integer (usually
a big integer, so will allocate on the heap).
"""
================================================
FILE: typehints/stdlib/uzlib.pyi
================================================
"""
zlib decompression.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/zlib.rst.
=================================
.. module:: zlib
:synopsis: zlib decompression
|see_cpython_module| :mod:`python:zlib`.
This module allows to decompress binary data compressed with
`DEFLATE algorithm `_
(commonly used in zlib library and gzip archiver). Compression
is not yet implemented.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from uio import IOBase
def decompress(data: bytes, wbits: int = 0, bufsize: int = 0, /) -> bytes:
"""
Return decompressed *data* as bytes. *wbits* is DEFLATE dictionary window
size used during compression (8-15, the dictionary size is power of 2 of
that value). Additionally, if value is positive, *data* is assumed to be
zlib stream (with zlib header). Otherwise, if it's negative, it's assumed
to be raw DEFLATE stream. *bufsize* parameter is for compatibility with
CPython and is ignored.
"""
class DecompIO(IOBase[bytes]):
"""
Steam wrapper that decompresses a given stream containing zlib compressed data.
"""
def __init__(self, stream: IOBase[bytes], wbits: int = 0, /):
"""
Create a `stream` wrapper which allows transparent decompression of
compressed data in another *stream*. This allows to process compressed
streams with data larger than available heap size. In addition to
values described in :func:`decompress`, *wbits* may take values
24..31 (16 + 8..15), meaning that input stream has gzip header.
.. admonition:: Difference to CPython
:class: attention
This class is MicroPython extension. It's included on provisional
basis and may be changed considerably or removed in later versions.
"""
================================================
FILE: typehints/stdlib/zlib.pyi
================================================
"""
zlib decompression.
Descriptions taken from:
https://raw.githubusercontent.com/micropython/micropython/master/docs/library/zlib.rst.
=================================
.. module:: zlib
:synopsis: zlib decompression
|see_cpython_module| :mod:`python:zlib`.
This module allows to decompress binary data compressed with
`DEFLATE algorithm `_
(commonly used in zlib library and gzip archiver). Compression
is not yet implemented.
"""
__author__ = "Howard C Lovatt"
__copyright__ = "Howard C Lovatt, 2020 onwards."
__license__ = "MIT https://opensource.org/licenses/MIT (as used by MicroPython)."
__version__ = "7.3.0" # Version set by https://github.com/hlovatt/tag2ver
from uio import IOBase
def decompress(data: bytes, wbits: int = 0, bufsize: int = 0, /) -> bytes:
"""
Return decompressed *data* as bytes. *wbits* is DEFLATE dictionary window
size used during compression (8-15, the dictionary size is power of 2 of
that value). Additionally, if value is positive, *data* is assumed to be
zlib stream (with zlib header). Otherwise, if it's negative, it's assumed
to be raw DEFLATE stream. *bufsize* parameter is for compatibility with
CPython and is ignored.
"""
class DecompIO(IOBase[bytes]):
"""
Steam wrapper that decompresses a given stream containing zlib compressed data.
"""
def __init__(self, stream: IOBase[bytes], wbits: int = 0, /):
"""
Create a `stream` wrapper which allows transparent decompression of
compressed data in another *stream*. This allows to process compressed
streams with data larger than available heap size. In addition to
values described in :func:`decompress`, *wbits* may take values
24..31 (16 + 8..15), meaning that input stream has gzip header.
.. admonition:: Difference to CPython
:class: attention
This class is MicroPython extension. It's included on provisional
basis and may be changed considerably or removed in later versions.
"""