Contributions Guide
We welcome contributions to the Arduino ESP32 project!
How to Contribute
Contributions to the Arduino ESP32 (fixing bugs, adding features, adding documentation) are welcome.We accept contributions viaGithub Pull Requests.
Before Contributing
Before sending us a Pull Request, please consider this:
All contributions must be written in English to ensure effective communication and support.Pull Requests written in other languages will be closed, with a request to rewrite them in English.
Is the contribution entirely your own work, or is it already licensed under an LGPL 2.1 compatible Open Source License?If not, cannot accept it.
Is the code adequately commented and can people understand how it is structured?
Is there documentation or examples that go with code contributions?
Are comments and documentation written in clear English, with no spelling or grammar errors?
Example contributions are also welcome.
If you are contributing by adding a new example, please use theArduino style guide and the example guideline below.
If the contribution contains multiple commits, are they grouped together into logical changes (one major change per pull request)?Are any commits with names like “fixed typo”squashed into previous commits?
If you’re unsure about any of these points, please open the Pull Request anyhow and then ask us for feedback.
Pull Request Process
After you open the Pull Request, there will probably be some discussion in the comments field of the request itself.
Once the Pull Request is ready to merge, it will first be merged into our internal git system for “in-house” automated testing.
If this process passes, it will be merged into the public GitHub repository.
Example Contribution Guideline
Checklist
Check if your example proposal has no similarities to the project (already existing examples)
Use theArduino style guide
Add the header to all source files
Add the
README.mdfileAdd inline comments if needed
Test the example
Header
All the source files must include the header with the example name and license, if applicable. You can change this header as you wish,but it will be reviewed by the community and may not be accepted.
Ideally, you can add some description about the example, links to the documentation, or the author’s name.Just have in mind to keep it simple and short.
Header Example
/* Wi-Fi FTM Initiator Arduino Example This example code is in the Public Domain (or CC0 licensed, at your option.) Unless required by applicable law or agreed to in writing, this software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.*/
README file
TheREADME.md file should contain the example details.
Please see the recommendedREADME.md file in theexample template folder.
Inline Comments
Inline comments are important if the example contains complex algorithms or specific configurations that the user needs to change.
Brief and clear inline comments are really helpful for the example understanding and it’s fast usage.
See theFTM exampleas a reference:
// Number of FTM frames requested in terms of 4 or 8 bursts (allowed values - 0 (No pref), 16, 24, 32, 64)Also:
constchar*WIFI_FTM_SSID="WiFi_FTM_Responder";// SSID of AP that has FTM Enabledconstchar*WIFI_FTM_PASS="ftm_responder";// STA Password
Testing
Be sure you have tested the example in all the supported targets. If the example some specific hardware requirements,edit/add theci.yml in the same folder as the sketch to specify the regular expression for therequired configurations fromsdkconfig.This will ensure that the CI system will run the test only on the targets that have the required configurations.
You can check the available configurations in thesdkconfig file in thetools/esp32-arduino-libs/<target> folder.
Here is an example of theci.yml file where the example requires Wi-Fi to work properly:
requires:-CONFIG_SOC_WIFI_SUPPORTED=y
Note
The list of configurations will be checked against thesdkconfig file in the target folder. If the configuration is not present in thesdkconfig,the test will be skipped for that target. That means that the test will only run on the targets that haveALL the required configurations.
Also, by default, the “match start of line” character (^) will be added to the beginning of each configuration.That means that the configuration must be at the beginning of the line in thesdkconfig file.
Sometimes, the example might not be supported by some target, even if the target has the required configurations(like resources limitations or requiring a specific SoC). To avoid compilation errors, you can add the target to theci.ymlfile so the CI system will force to skip the test on that target.
Here is an example of theci.yml file where the example is requires Wi-Fi to work properly but is also not supported by the ESP32-S2 target:
requires:-CONFIG_SOC_WIFI_SUPPORTED=ytargets:esp32s2:false
You also need to add this information in theREADME.md file, on theSupported Targets, and in the example code as an inline comment.For example, in the sketch:
/* THIS FEATURE REQUIRES WI-FI SUPPORT AND IS NOT AVAILABLE FOR ESP32-S2 AS IT DOES NOT HAVE ENOUGH RAM.*/
And in theREADME.md file:
Currently, this example requires Wi-Fi and supports the following targets.| Supported Targets | ESP32 | ESP32-S3 | ESP32-C3 | ESP32-C6 || ----------------- | ----- | -------- | -------- | -------- |
By default, the CI system will use the FQBNs specified in the.github/scripts/sketch_utils.sh file to compile the sketches.Currently, the default FQBNs are:
espressif:esp32:esp32:PSRAM=enabledespressif:esp32:esp32s2:PSRAM=enabledespressif:esp32:esp32s3:PSRAM=opi,USBMode=defaultespressif:esp32:esp32c3espressif:esp32:esp32c6espressif:esp32:esp32h2espressif:esp32:esp32p4:USBMode=default,ChipVariant=postv3
There are two ways to alter the FQBNs used to compile the sketches: by using thefqbn orfqbn_append fields in theci.yml file.
If you just want to append a string to the default FQBNs, you can use thefqbn_append field. For example, to add theDebugLevel=debug to the FQBNs, you would use:
fqbn_append:DebugLevel=debug
If you want to override the default FQBNs, you can use thefqbn field. It is a dictionary where the key is the target name and the value is a list of FQBNs.The FQBNs in the list will be used in sequence to compile the sketch. For example, to compile a sketch for ESP32-S2 with and without PSRAM enabled, you would use:
fqbn:esp32s2:-espressif:esp32:esp32s2:PSRAM=enabled,FlashMode=dio-espressif:esp32:esp32s2:PSRAM=disabled,FlashMode=dio
Note
The FQBNs specified in thefqbn field will also override the options specified in thefqbn_append field.That means that if thefqbn field is specified, thefqbn_append field will be ignored and will have no effect.
Example Template
The example template can be foundhereand can be used as a reference.
Documentation
If you are contributing to the documentation, please follow the instructions described in thedocumentation guidelines to properly format and test your changes.
Testing and CI
After you have made your changes, you should test them. You can do this in different ways depending on the type of change you have made.
Examples
The easiest way to test an example is to load it into the Arduino IDE and run it on your board. If you have multiple boards,you should test it on all of them to ensure that the example works on all supported targets.
You can refer to theExample Contribution Guideline section for more information on how to write and test examples.
Library Changes
If you have made changes to a library, you should test it on all supported targets. You can do this by loading the library examples (or creating new ones)into the Arduino IDE and running them on your board. If you have multiple boards, you should test it on all of them to ensure that the libraryworks as expected on all targets.
You can also add a new test suite to automatically check the library. You can refer to theAdding a New Test Suite section for more information.
Core Changes
If you have made changes to the core, it is important to ensure that the changes do not break the existing functionality. You can do this by running thetests on all supported targets. You can refer to theRuntime Tests section for more information.
CI
In our repository, we have a Continuous Integration (CI) system that runs tests and fixes on every Pull Request. This system will run the testson all supported targets and check if everything is working as expected.
We have many types of tests and checks, including:
Compilation tests;
Runtime tests;
Documentation checks;
Code style checks;
And more.
Let’s go deeper into each type of test in the CI system:
Compilation Tests
The compilation tests are the first type of tests in the CI system. They check if the code compiles on all supported targets.If the code does not compile, the CI system will fail the test and the Pull Request will not be merged.This is important to ensure that the code is compatible with all supported targets and no broken code is merged.
It will go through all the sketches in the repository and check if they compile on all supported targets. This process is automated and controlledby GitHub Actions. The CI system will run thearduino-cli tool to compile the sketches on all supported targets.
Testing it locally using the CI scripts would be too time consuming, so we recommend running the tests locally using the Arduino IDE witha sketch that uses the changes you made (you can also add the sketch as an example if your change is not covered by the existing ones).Make sure to setCompilerWarnings toAll in the Arduino IDE to catch any potential issues.
Runtime Tests
Another type of test is the runtime tests. They check if the code runs and behaves as expected on all supported targets. If thecode does not run as expected, the CI system will fail the test and the Pull Request will not be merged. This is important to ensure that the codeworks as expected on all supported targets and no unintended crashes or bugs are introduced.
These tests are specialized sketches that run on the target board and check if the code behaves as expected. This process is automated andcontrolled by thepytest_embedded tool. You can read more about this tool in itsdocumentation.
The tests are divided into two categories inside thetests folder:
validation: These tests are used to validate the behavior of the Arduino core and libraries. They are used to check if the core and librariesare working as expected;performance: These tests are used to check the performance of the Arduino core and libraries. They are used to check if the changes madeto the core and libraries have any big impact on the performance. These tests usually run for a longer time than the validation tests and includecommon benchmark tools likeCoreMark.
Note
Keep in mind that to run the CI scripts locally, you need to have the Go-basedyq frommikefarah/yqinstalled and not the Python-basedyq from PyPI orkislyuk/yq.The syntax is slightly different and will not work with the CI scripts.You can install the Go-basedyq throughbrew,chocolatey or downloading the binary directly from thereleases page.
To run the runtime tests locally, first install the required dependencies by running:
pipinstall-U-rtests/requirements.txt
Before running the test, we need to build it by running:
./.github/scripts/tests_build.sh-s<test_name>-t<target>
The<test_name> is the name of the test you want to run (you can check the available tests in thetests/validation andtests/performance folders), and the<target> is the target board you want to run the test on. For example, to run theuart test on theESP32-C3 target, you would run:
./.github/scripts/tests_build.sh-suart-tesp32c3
You should see the output of the build process and the test binary should be generated in the~/.arduino/tests/<target_chip>/<test_name>/build.tmp folder.
Now that the test is built, you can run it in the target board. Connect the target board to your computer and run:
./.github/scripts/tests_run.sh-s<test_name>-t<target>
For example, to run theuart test on the ESP32-C3 target, you would run:
./.github/scripts/tests_run.sh-suart-tesp32c3
The test will run on the target board and you should see the output of the test in the terminal:
lucassvaz@Lucas--MacBook-Proesp32%./.github/scripts/tests_run.sh-suart-tesp32c3Sketchuarttesttype:validationRunningtest:uart--Config:Defaultpytesttests--build-dir/Users/lucassvaz/.arduino/tests/esp32c3/uart/build.tmp-ktest_uart--junit-xml=/Users/lucassvaz/Espressif/Arduino/hardware/espressif/esp32/tests/validation/uart/esp32c3/uart.xml--embedded-servicesesp,arduino===============================================================================================testsessionstarts================================================================================================platformdarwin--Python3.12.3,pytest-8.2.2,pluggy-1.5.0rootdir:/Users/lucassvaz/Espressif/Arduino/hardware/espressif/esp32/testsconfigfile:pytest.iniplugins:cov-5.0.0,embedded-1.11.5,anyio-4.4.0collected15items/14deselected/1selectedtests/validation/uart/test_uart.py::test_uart--------------------------------------------------------------------------------------------------livelogsetup--------------------------------------------------------------------------------------------------2024-08-2211:49:30INFOTarget:esp32c3,Port:/dev/cu.usbserial-2120PASSED[100%]------------------------------------------------------------------------------------------------livelogteardown-------------------------------------------------------------------------------------------------2024-08-2211:49:52INFOCreatedunityoutputjunitreport:/private/var/folders/vp/g9wctsvn7b91k3pv_7cwpt_h0000gn/T/pytest-embedded/2024-08-22_14-49-30-392993/test_uart/dut.xml----------------------------------------------generatedxmlfile:/Users/lucassvaz/Espressif/Arduino/hardware/espressif/esp32/tests/validation/uart/esp32c3/uart.xml----------------------------------------------========================================================================================1passed,14deselectedin22.18s=========================================================================================
After the test is finished, you can check the output in the terminal and the generated XML file in the test folder.Additionally, for performance tests, you can check the generated JSON file in the same folder.
You can also run the tests inWokwi orEspressif’s QEMUby using the-W and-Q flags respectively. You will need to have the Wokwi and/or QEMU installed in your systemand set theWOKWI_CLI_TOKEN and/orQEMU_PATH environment variables. TheWOKWI_CLI_TOKEN is the CI token that can be obtained from theWokwi website and theQEMU_PATH is the path to the QEMU binary.
For example, to run theuart test using Wokwi, you would run:
WOKWI_CLI_TOKEN=<your_wokwi_token>./.github/scripts/tests_run.sh-suart-tesp32c3-W
And to run theuart test using QEMU, you would run:
QEMU_PATH=<path_to_qemu_binary>./.github/scripts/tests_run.sh-suart-tesp32c3-Q
Note
Not all tests are supported by Wokwi and QEMU. QEMU is only supported for ESP32 and ESP32-C3 targets.Wokwi support depends on thecurrently implemented peripherals.
Adding a New Test Suite
If you want to add a new test suite, you can create a new folder insidetests/validation ortests/performance with the name of the test suite.You can use thehello_world test suite as a starting point and the other test suites as a reference.
A test suite contains the following files:
test_<test_name>.py: Is the test file that contains the test cases. Required.<test_name>.ino: This is the sketch that will be tested. Required.ci.yml: The file that specifies how the test suite will be run in the CI system. Optional.diagram.<target>.json: The diagram file that specifies the connections between the components in Wokwi. Optional.Any other files that are needed for the test suite.
You can read more about the test python API in thepytest-embedded documentation.For more information about the Unity testing framework, you can check theUnity documentation.
After creating the test suite, make sure to test it locally and run it in the CI system to ensure that it works as expected.
CI YAML File
Theci.yml file is used to specify how the test suite and sketches will handled by the CI system. It can contain the following fields:
requires: A list of configurations insdkconfigthat are required to run the test suite. The test suite will only run on the targetsthat haveALL the required configurations. By default, no configurations are required.requires_any: A list of configurations insdkconfigthat are required to run the test suite. The test suite will only run on the targetsthat haveANY of the required configurations. By default, no configurations are required.targets: A dictionary that specifies the targets for which the tests will be run. The key is the target name and the value is a booleanthat specifies if the test should be run for that target. By default, all targets are enabled as long as they have the required configurationsspecified in therequiresfield. This field is also valid for examples.platforms: A dictionary that specifies the supported platforms. The key is the platform name and the value is a boolean that specifies ifthe platform is supported. By default, all platforms are assumed to be supported.tags: A list of tags that all runners will require when running the test suite in hardware. By default, no tags are required.soc_tags: A dictionary that specifies SoC-specific tags required for hardware runners. The key is the target name and the value is a listof tags. By default, no SoC-specific tags are required.fqbn_append: A string to be appended to the default FQBNs. By default, no string is appended. This has no effect iffqbnis specified.fqbn: A dictionary that specifies the FQBNs that will be used to compile the sketch. The key is the target name and the value is a listof FQBNs. Thedefault FQBNsare used if this field is not specified. This overrides the default FQBNs and thefqbn_appendfield.libs: A list of libraries that are required to run the test suite. The libraries will be installed automatically if they are not already present.Libraries are installed using thearduino-clilibinstallcommand, so you can specify libraries by name + version (e.g.,AudioZero@1.0.0)or by URL (e.g.,https://github.com/arduino-libraries/WiFi101.git).More information can be found in theArduino CLI documentation.
Thewifi test suite is a good example of how to use theci.yml file:
tags:-wifi_routerfqbn:esp32:-espressif:esp32:esp32:PSRAM=enabled,PartitionScheme=huge_app,FlashMode=dio-espressif:esp32:esp32:PSRAM=disabled,PartitionScheme=huge_app,FlashMode=dioesp32s2:-espressif:esp32:esp32s2:PSRAM=enabled,PartitionScheme=huge_app,FlashMode=dio-espressif:esp32:esp32s2:PSRAM=disabled,PartitionScheme=huge_app,FlashMode=dioesp32s3:-espressif:esp32:esp32s3:PSRAM=opi,USBMode=default,PartitionScheme=huge_app,FlashMode=qio-espressif:esp32:esp32s3:PSRAM=disabled,USBMode=default,PartitionScheme=huge_app,FlashMode=qio-espressif:esp32:esp32s3:PSRAM=enabled,USBMode=default,PartitionScheme=huge_app,FlashMode=qioplatforms:hardware:falseqemu:falserequires:-CONFIG_SOC_WIFI_SUPPORTED=y
Documentation Checks
The CI also checks the documentation for any compilation errors. This is important to ensure that the documentation layout is not broken.To build the documentation locally, please refer to thedocumentation guidelines.
Code Style Checks
For checking the code style and other code quality checks, we use pre-commit hooks.These hooks will be automatically run by the CI when a Pull Request is marked asStatus:PendingMerge.You can check which hooks are being run in the.pre-commit-config.yaml file.
Currently, we have hooks for the following tasks:
Formatters for C, C++, Python, Bash, JSON, Markdown and ReStructuredText files;
Linters for Python, Bash and prose (spoken language);
Checking for spelling errors in the code and documentation;
Removing trailing whitespaces and tabs in the code;
Checking for the presence of private keys and other sensitive information in the code;
Fixing the line endings and end of files (EOF) in the code;
And more.
You can read more about the pre-commit hooks in thepre-commit documentation.
If you want to run the pre-commit hooks locally, you first need to install the required dependencies by running:
pipinstall-U-rtools/pre-commit/requirements.txt
Then, you can run the pre-commit hooks staging your changes and running:
pre-commitrun
To run a specific hook, you can use the hook name as an argument. For example, to run thecodespell hook, you would run:
pre-commitruncodespell
If you want to run the pre-commit hooks automatically against the changed files on everygitcommit,you can install the pre-commit hooks by running:
pre-commitinstall
Legal Part
Before a contribution can be accepted, you will need to sign our contributor agreement. You will be prompted for this automatically as part ofthe Pull Request process.