├── .codespellrc ├── .github ├── dependabot.yml └── workflows │ ├── check-arduino.yml │ ├── compile-examples.yml │ ├── report-size-deltas.yml │ ├── spell-check.yml │ └── sync-labels.yml ├── LICENSE.txt ├── README.adoc ├── docs ├── api.md └── readme.md ├── examples └── MultipleBlinks │ └── MultipleBlinks.ino ├── keywords.txt ├── library.properties └── src ├── Scheduler.cpp └── Scheduler.h /.codespellrc: -------------------------------------------------------------------------------- 1 | # See: https://github.com/codespell-project/codespell#using-a-config-file 2 | [codespell] 3 | # In the event of a false positive, add the problematic word, in all lowercase, to a comma-separated list here: 4 | ignore-words-list = , 5 | check-filenames = 6 | check-hidden = 7 | skip = ./.git 8 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # See: https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#about-the-dependabotyml-file 2 | version: 2 3 | 4 | updates: 5 | # Configure check for outdated GitHub Actions actions in workflows. 6 | # See: https://docs.github.com/en/github/administering-a-repository/keeping-your-actions-up-to-date-with-dependabot 7 | - package-ecosystem: github-actions 8 | directory: / # Check the repository's workflows under /.github/workflows/ 9 | schedule: 10 | interval: daily 11 | labels: 12 | - "topic: infrastructure" 13 | -------------------------------------------------------------------------------- /.github/workflows/check-arduino.yml: -------------------------------------------------------------------------------- 1 | name: Check Arduino 2 | 3 | # See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows 4 | on: 5 | push: 6 | pull_request: 7 | schedule: 8 | # Run every Tuesday at 8 AM UTC to catch breakage caused by new rules added to Arduino Lint. 9 | - cron: "0 8 * * TUE" 10 | workflow_dispatch: 11 | repository_dispatch: 12 | 13 | jobs: 14 | lint: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout repository 19 | uses: actions/checkout@v4 20 | 21 | - name: Arduino Lint 22 | uses: arduino/arduino-lint-action@v2 23 | with: 24 | compliance: specification 25 | library-manager: update 26 | # Always use this setting for official repositories. Remove for 3rd party projects. 27 | official: true 28 | project-type: library 29 | -------------------------------------------------------------------------------- /.github/workflows/compile-examples.yml: -------------------------------------------------------------------------------- 1 | name: Compile Examples 2 | 3 | # See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows 4 | on: 5 | push: 6 | paths: 7 | - ".github/workflows/compile-examples.yml" 8 | - "library.properties" 9 | - "examples/**" 10 | - "src/**" 11 | pull_request: 12 | paths: 13 | - ".github/workflows/compile-examples.yml" 14 | - "library.properties" 15 | - "examples/**" 16 | - "src/**" 17 | schedule: 18 | # Run every Tuesday at 8 AM UTC to catch breakage caused by changes to external resources (libraries, platforms). 19 | - cron: "0 8 * * TUE" 20 | workflow_dispatch: 21 | repository_dispatch: 22 | 23 | jobs: 24 | build: 25 | name: ${{ matrix.board.fqbn }} 26 | runs-on: ubuntu-latest 27 | 28 | env: 29 | SKETCHES_REPORTS_PATH: sketches-reports 30 | 31 | strategy: 32 | fail-fast: false 33 | 34 | matrix: 35 | board: 36 | - fqbn: arduino:samd:arduino_zero_edbg 37 | platforms: | 38 | - name: arduino:samd 39 | artifact-name-suffix: arduino-samd-arduino_zero_edbg 40 | - fqbn: arduino:samd:mkrzero 41 | platforms: | 42 | - name: arduino:samd 43 | artifact-name-suffix: arduino-samd-mkrzero 44 | - fqbn: arduino:samd:mkr1000 45 | platforms: | 46 | - name: arduino:samd 47 | artifact-name-suffix: arduino-samd-mkr1000 48 | - fqbn: arduino:samd:mkrwifi1010 49 | platforms: | 50 | - name: arduino:samd 51 | artifact-name-suffix: arduino-samd-mkrwifi1010 52 | - fqbn: arduino:samd:mkrfox1200 53 | platforms: | 54 | - name: arduino:samd 55 | artifact-name-suffix: arduino-samd-mkrfox1200 56 | - fqbn: arduino:samd:mkrwan1300 57 | platforms: | 58 | - name: arduino:samd 59 | artifact-name-suffix: arduino-samd-mkrwan1300 60 | - fqbn: arduino:samd:mkrwan1310 61 | platforms: | 62 | - name: arduino:samd 63 | artifact-name-suffix: arduino-samd-mkrwan1310 64 | - fqbn: arduino:samd:mkrgsm1400 65 | platforms: | 66 | - name: arduino:samd 67 | artifact-name-suffix: arduino-samd-mkrgsm1400 68 | - fqbn: arduino:samd:mkrnb1500 69 | platforms: | 70 | - name: arduino:samd 71 | artifact-name-suffix: arduino-samd-mkrnb1500 72 | - fqbn: arduino:samd:mkrvidor4000 73 | platforms: | 74 | - name: arduino:samd 75 | artifact-name-suffix: arduino-samd-mkrvidor4000 76 | - fqbn: arduino:samd:nano_33_iot 77 | platforms: | 78 | - name: arduino:samd 79 | artifact-name-suffix: arduino-samd-nano_33_iot 80 | 81 | steps: 82 | - name: Checkout repository 83 | uses: actions/checkout@v4 84 | 85 | - name: Compile examples 86 | uses: arduino/compile-sketches@v1 87 | with: 88 | github-token: ${{ secrets.GITHUB_TOKEN }} 89 | fqbn: ${{ matrix.board.fqbn }} 90 | platforms: ${{ matrix.board.platforms }} 91 | libraries: | 92 | # Install the library from the local path. 93 | - source-path: ./ 94 | # Additional library dependencies can be listed here. 95 | # See: https://github.com/arduino/compile-sketches#libraries 96 | sketch-paths: | 97 | - examples 98 | enable-deltas-report: true 99 | sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }} 100 | 101 | - name: Save sketches report as workflow artifact 102 | uses: actions/upload-artifact@v4 103 | with: 104 | if-no-files-found: error 105 | path: ${{ env.SKETCHES_REPORTS_PATH }} 106 | name: sketches-report-${{ matrix.board.artifact-name-suffix }} 107 | -------------------------------------------------------------------------------- /.github/workflows/report-size-deltas.yml: -------------------------------------------------------------------------------- 1 | name: Report Size Deltas 2 | 3 | # See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows 4 | on: 5 | push: 6 | paths: 7 | - ".github/workflows/report-size-deltas.yml" 8 | schedule: 9 | # Run at the minimum interval allowed by GitHub Actions. 10 | # Note: GitHub Actions periodically has outages which result in workflow failures. 11 | # In this event, the workflows will start passing again once the service recovers. 12 | - cron: "*/5 * * * *" 13 | workflow_dispatch: 14 | repository_dispatch: 15 | 16 | jobs: 17 | report: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Comment size deltas reports to PRs 21 | uses: arduino/report-size-deltas@v1 22 | with: 23 | # Regex matching the names of the workflow artifacts created by the "Compile Examples" workflow 24 | sketches-reports-source: ^sketches-report-.+ 25 | -------------------------------------------------------------------------------- /.github/workflows/spell-check.yml: -------------------------------------------------------------------------------- 1 | name: Spell Check 2 | 3 | # See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows 4 | on: 5 | push: 6 | pull_request: 7 | schedule: 8 | # Run every Tuesday at 8 AM UTC to catch new misspelling detections resulting from dictionary updates. 9 | - cron: "0 8 * * TUE" 10 | workflow_dispatch: 11 | repository_dispatch: 12 | 13 | jobs: 14 | spellcheck: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout repository 19 | uses: actions/checkout@v4 20 | 21 | - name: Spell check 22 | uses: codespell-project/actions-codespell@master 23 | -------------------------------------------------------------------------------- /.github/workflows/sync-labels.yml: -------------------------------------------------------------------------------- 1 | # Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/sync-labels.md 2 | name: Sync Labels 3 | 4 | # See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows 5 | on: 6 | push: 7 | paths: 8 | - ".github/workflows/sync-labels.ya?ml" 9 | - ".github/label-configuration-files/*.ya?ml" 10 | pull_request: 11 | paths: 12 | - ".github/workflows/sync-labels.ya?ml" 13 | - ".github/label-configuration-files/*.ya?ml" 14 | schedule: 15 | # Run daily at 8 AM UTC to sync with changes to shared label configurations. 16 | - cron: "0 8 * * *" 17 | workflow_dispatch: 18 | repository_dispatch: 19 | 20 | env: 21 | CONFIGURATIONS_FOLDER: .github/label-configuration-files 22 | CONFIGURATIONS_ARTIFACT: label-configuration-files 23 | 24 | jobs: 25 | check: 26 | runs-on: ubuntu-latest 27 | 28 | steps: 29 | - name: Checkout repository 30 | uses: actions/checkout@v4 31 | 32 | - name: Download JSON schema for labels configuration file 33 | id: download-schema 34 | uses: carlosperate/download-file-action@v2 35 | with: 36 | file-url: https://raw.githubusercontent.com/arduino/tooling-project-assets/main/workflow-templates/assets/sync-labels/arduino-tooling-gh-label-configuration-schema.json 37 | location: ${{ runner.temp }}/label-configuration-schema 38 | 39 | - name: Install JSON schema validator 40 | run: | 41 | sudo npm install \ 42 | --global \ 43 | ajv-cli \ 44 | ajv-formats 45 | 46 | - name: Validate local labels configuration 47 | run: | 48 | # See: https://github.com/ajv-validator/ajv-cli#readme 49 | ajv validate \ 50 | --all-errors \ 51 | -c ajv-formats \ 52 | -s "${{ steps.download-schema.outputs.file-path }}" \ 53 | -d "${{ env.CONFIGURATIONS_FOLDER }}/*.{yml,yaml}" 54 | 55 | download: 56 | needs: check 57 | runs-on: ubuntu-latest 58 | 59 | strategy: 60 | matrix: 61 | filename: 62 | # Filenames of the shared configurations to apply to the repository in addition to the local configuration. 63 | # https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/sync-labels 64 | - universal.yml 65 | 66 | steps: 67 | - name: Download 68 | uses: carlosperate/download-file-action@v2 69 | with: 70 | file-url: https://raw.githubusercontent.com/arduino/tooling-project-assets/main/workflow-templates/assets/sync-labels/${{ matrix.filename }} 71 | 72 | - name: Pass configuration files to next job via workflow artifact 73 | uses: actions/upload-artifact@v4 74 | with: 75 | path: | 76 | *.yaml 77 | *.yml 78 | if-no-files-found: error 79 | name: ${{ env.CONFIGURATIONS_ARTIFACT }} 80 | 81 | sync: 82 | needs: download 83 | runs-on: ubuntu-latest 84 | 85 | steps: 86 | - name: Set environment variables 87 | run: | 88 | # See: https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable 89 | echo "MERGED_CONFIGURATION_PATH=${{ runner.temp }}/labels.yml" >> "$GITHUB_ENV" 90 | 91 | - name: Determine whether to dry run 92 | id: dry-run 93 | if: > 94 | github.event_name == 'pull_request' || 95 | ( 96 | ( 97 | github.event_name == 'push' || 98 | github.event_name == 'workflow_dispatch' 99 | ) && 100 | github.ref != format('refs/heads/{0}', github.event.repository.default_branch) 101 | ) 102 | run: | 103 | # Use of this flag in the github-label-sync command will cause it to only check the validity of the 104 | # configuration. 105 | echo "::set-output name=flag::--dry-run" 106 | 107 | - name: Checkout repository 108 | uses: actions/checkout@v4 109 | 110 | - name: Download configuration files artifact 111 | uses: actions/download-artifact@v4 112 | with: 113 | name: ${{ env.CONFIGURATIONS_ARTIFACT }} 114 | path: ${{ env.CONFIGURATIONS_FOLDER }} 115 | 116 | - name: Remove unneeded artifact 117 | uses: geekyeggo/delete-artifact@v5 118 | with: 119 | name: ${{ env.CONFIGURATIONS_ARTIFACT }} 120 | 121 | - name: Merge label configuration files 122 | run: | 123 | # Merge all configuration files 124 | shopt -s extglob 125 | cat "${{ env.CONFIGURATIONS_FOLDER }}"/*.@(yml|yaml) > "${{ env.MERGED_CONFIGURATION_PATH }}" 126 | 127 | - name: Install github-label-sync 128 | run: sudo npm install --global github-label-sync 129 | 130 | - name: Sync labels 131 | env: 132 | GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} 133 | run: | 134 | # See: https://github.com/Financial-Times/github-label-sync 135 | github-label-sync \ 136 | --labels "${{ env.MERGED_CONFIGURATION_PATH }}" \ 137 | ${{ steps.dry-run.outputs.flag }} \ 138 | ${{ github.repository }} 139 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | :repository-owner: arduino-libraries 2 | :repository-name: Scheduler 3 | 4 | = {repository-name} Library for Arduino = 5 | 6 | image:https://github.com/{repository-owner}/{repository-name}/actions/workflows/check-arduino.yml/badge.svg["Check Arduino status", link="https://github.com/{repository-owner}/{repository-name}/actions/workflows/check-arduino.yml"] 7 | image:https://github.com/{repository-owner}/{repository-name}/actions/workflows/compile-examples.yml/badge.svg["Compile Examples status", link="https://github.com/{repository-owner}/{repository-name}/actions/workflows/compile-examples.yml"] 8 | image:https://github.com/{repository-owner}/{repository-name}/actions/workflows/spell-check.yml/badge.svg["Spell Check status", link="https://github.com/{repository-owner}/{repository-name}/actions/workflows/spell-check.yml"] 9 | 10 | The Scheduler library enables the Arduino link:https://store.arduino.cc/arduino-due[Due], link:https://store.arduino.cc/arduino-zero[Zero], and link:https://store.arduino.cc/arduino-mkr1000-wifi[MKR1000] to run multiple functions at the same time. This allows tasks to happen without interrupting each other. 11 | 12 | For more information about this library please visit us at 13 | http://www.arduino.cc/en/Reference/{repository-name} 14 | 15 | == License == 16 | 17 | Copyright (c) 2012 The Android Open Source Project. All right reserved. 18 | 19 | Licensed under the Apache License, Version 2.0 (the "License"); 20 | you may not use this file except in compliance with the License. 21 | You may obtain a copy of the License at 22 | 23 | http://www.apache.org/licenses/LICENSE-2.0 24 | 25 | Unless required by applicable law or agreed to in writing, software 26 | distributed under the License is distributed on an "AS IS" BASIS, 27 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 | See the License for the specific language governing permissions and 29 | limitations under the License. 30 | -------------------------------------------------------------------------------- /docs/api.md: -------------------------------------------------------------------------------- 1 | # Scheduler library 2 | 3 | ## Methods 4 | 5 | ### `Scheduler.startLoop()` 6 | 7 | Adds a function to the scheduler that will run concurrently with `loop()`. 8 | 9 | #### Syntax 10 | 11 | ``` 12 | Scheduler.startLoop(loopName); 13 | ``` 14 | 15 | #### Parameters 16 | 17 | * `loopName`: the named function to run. 18 | 19 | #### Returns 20 | 21 | None. 22 | 23 | #### Example 24 | 25 | ``` 26 | #include 27 | 28 | int counter = 0; 29 | int counter1 = 0; 30 | 31 | void setup() { 32 | Scheduler.startLoop(loop1); 33 | } 34 | 35 | void loop () { 36 | analogWrite(9, counter); 37 | counter++; 38 | 39 | if (counter > 255){ 40 | counter = 0; 41 | } 42 | 43 | delay(33); 44 | } 45 | 46 | void loop1 () { 47 | analogWrite(10, counter1); 48 | counter1 = counter1 + 5; 49 | 50 | if (counter1 > 255) { 51 | counter1 = 0; 52 | } 53 | 54 | delay(10); 55 | yield(); 56 | } 57 | ``` 58 | 59 | #### See also 60 | 61 | * [yield()](#yield) 62 | 63 | ### `yield()` 64 | 65 | Passes control to other tasks when called. Ideally `yield()` should be used in functions that will take awhile to complete. 66 | 67 | #### Syntax 68 | 69 | ``` 70 | yield(); 71 | ``` 72 | 73 | #### Parameters 74 | 75 | None. 76 | 77 | #### Returns 78 | 79 | None. 80 | 81 | #### Example 82 | 83 | ``` 84 | #include 85 | 86 | int counter = 0; 87 | int counter1 = 0; 88 | 89 | void setup() { 90 | Serial.begin(9600); 91 | Scheduler.startLoop(loop1); 92 | } 93 | 94 | void loop () { 95 | analogWrite(9, counter); 96 | counter++; 97 | 98 | if (counter > 255){ 99 | counter = 0; 100 | } 101 | 102 | delay(33); 103 | } 104 | 105 | void loop1 () { 106 | if (Serial.available()) { 107 | char c = Serial.read(); 108 | 109 | if (c=='0') { 110 | digitalWrite(2, LOW); 111 | Serial.println("Led turned OFF!"); 112 | } 113 | 114 | if (c=='1') { 115 | digitalWrite(2, HIGH); 116 | Serial.println("Led turned ON!"); 117 | } 118 | } 119 | 120 | yield(); 121 | } 122 | ``` 123 | 124 | #### See also 125 | 126 | * [Scheduler.startLoop()](#scheduler.startloop) -------------------------------------------------------------------------------- /docs/readme.md: -------------------------------------------------------------------------------- 1 | # Scheduler library 2 | 3 | The Scheduler library enables an Arduino based on SAM and SAMD architectures (i.e Zero, MKRZero, MKR1000, Due boards) to run multiple functions at the same time. This allows tasks to happen without interrupting each other. This is a cooperative scheduler in that the CPU switches from one task to another. The library includes methods for passing control between tasks. 4 | 5 | To use this library: 6 | 7 | ``` 8 | #include 9 | ``` 10 | 11 | ## Notes and warnings 12 | 13 | The Scheduler library and associated functions are experimental. While it is not likely the API will change in future releases, it is still under development. 14 | 15 | ## Examples 16 | 17 | * [MultipleBlinks](https://www.arduino.cc/en/Tutorial/MultipleBlinks): Blink multiple LEDs in their own loops. -------------------------------------------------------------------------------- /examples/MultipleBlinks/MultipleBlinks.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Multiple Blinks 3 | 4 | Demonstrates the use of the Scheduler library for the Arduino Due 5 | 6 | Hardware required : 7 | * LEDs connected to pins 11, 12, and 13 8 | 9 | created 8 Oct 2012 10 | by Cristian Maglie 11 | Modified by 12 | Scott Fitzgerald 19 Oct 2012 13 | 14 | This example code is in the public domain 15 | 16 | http://www.arduino.cc/en/Tutorial/MultipleBlinks 17 | */ 18 | 19 | // Include Scheduler since we want to manage multiple tasks. 20 | #include 21 | 22 | int led1 = 13; 23 | int led2 = 12; 24 | int led3 = 11; 25 | 26 | void setup() { 27 | Serial.begin(9600); 28 | 29 | // Setup the 3 pins as OUTPUT 30 | pinMode(led1, OUTPUT); 31 | pinMode(led2, OUTPUT); 32 | pinMode(led3, OUTPUT); 33 | 34 | // Add "loop2" and "loop3" to scheduling. 35 | // "loop" is always started by default. 36 | Scheduler.startLoop(loop2); 37 | Scheduler.startLoop(loop3); 38 | } 39 | 40 | // Task no.1: blink LED with 1 second delay. 41 | void loop() { 42 | digitalWrite(led1, HIGH); 43 | 44 | // IMPORTANT: 45 | // When multiple tasks are running 'delay' passes control to 46 | // other tasks while waiting and guarantees they get executed. 47 | delay(1000); 48 | 49 | digitalWrite(led1, LOW); 50 | delay(1000); 51 | } 52 | 53 | // Task no.2: blink LED with 0.1 second delay. 54 | void loop2() { 55 | digitalWrite(led2, HIGH); 56 | delay(100); 57 | digitalWrite(led2, LOW); 58 | delay(100); 59 | } 60 | 61 | // Task no.3: accept commands from Serial port 62 | // '0' turns off LED 63 | // '1' turns on LED 64 | void loop3() { 65 | if (Serial.available()) { 66 | char c = Serial.read(); 67 | if (c == '0') { 68 | digitalWrite(led3, LOW); 69 | Serial.println("LED turned off!"); 70 | } 71 | if (c == '1') { 72 | digitalWrite(led3, HIGH); 73 | Serial.println("LED turned on!"); 74 | } 75 | } 76 | 77 | // IMPORTANT: 78 | // We must call 'yield' at a regular basis to pass 79 | // control to other tasks. 80 | yield(); 81 | } 82 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For Scheduler 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | Scheduler KEYWORD1 Scheduler 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | startLoop KEYWORD2 16 | 17 | ####################################### 18 | # Constants (LITERAL1) 19 | ####################################### 20 | 21 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Scheduler 2 | version=0.4.4 3 | author=Arduino 4 | maintainer=Arduino 5 | sentence=Allows multiple tasks to run at the same time, without interrupting each other. For Arduino SAM and SAMD architectures only (Due, Zero...). 6 | paragraph=The Scheduler library enables the Arduino to run multiple functions at the same time. This allows tasks to happen without interrupting each other.
This is a cooperative scheduler in that the CPU switches from one task to another. The library includes methods for passing control between tasks. 7 | category=Other 8 | url=http://www.arduino.cc/en/Reference/Scheduler 9 | architectures=sam,samd 10 | -------------------------------------------------------------------------------- /src/Scheduler.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "Scheduler.h" 18 | 19 | extern "C" { 20 | 21 | #define NUM_REGS 10 // r4-r11, sp, pc 22 | 23 | typedef struct CoopTask { 24 | uint32_t regs[NUM_REGS]; 25 | void* stackPtr; 26 | struct CoopTask* next; 27 | struct CoopTask* prev; 28 | } CoopTask; 29 | 30 | static CoopTask *cur = 0; 31 | 32 | static CoopTask* __attribute__((noinline)) coopSchedule(char taskDied) { 33 | CoopTask* next = cur->next; 34 | 35 | if (taskDied) { 36 | // Halt if last task died. 37 | if (next == cur) 38 | while (1) 39 | ; 40 | 41 | // Delete task 42 | if (cur->stackPtr) 43 | free(cur->stackPtr); 44 | cur->next->prev = cur->prev; 45 | cur->prev->next = cur->next; 46 | free(cur); 47 | } 48 | cur = next; 49 | return next; 50 | } 51 | 52 | static void __attribute__((naked)) __attribute__((noinline)) coopTaskStart(void) { 53 | asm ( 54 | "mov r0, r5;" 55 | "blx r4;" 56 | /* schedule. */ 57 | "mov r0, #1;" /* returned from task func: task done */ 58 | "bl coopSchedule;" 59 | /* r0 holds address of next task context */ 60 | #if defined(ARDUINO_ARCH_SAMD) 61 | /* for Cortex M0, ldm and stm are restricted to low registers */ 62 | /* load high registers */ 63 | "add r0, #16;" /* they are 4 words higher in memory */ 64 | "ldmia r0, {r1-r6};" /* load them in low registers first... */ 65 | "mov r8, r1;" /* ...and move them into high registers... */ 66 | "mov r9, r2;" 67 | "mov r10, r3;" 68 | "mov r11, r4;" 69 | "mov r12, r5;" 70 | "mov lr, r6;" 71 | /* load low registers */ 72 | "sub r0, r0, #40;" /* back to begin of context */ 73 | "ldmia r0, {r4-r7};" 74 | #else 75 | "ldmia r0, {r4-r12, lr};" 76 | #endif 77 | /* restore task stack */ 78 | "mov sp, r12;" 79 | /* resume task */ 80 | "bx lr;" 81 | ); 82 | } 83 | 84 | static void __attribute__((naked)) __attribute__((noinline)) coopDoYield(CoopTask* curTask) { 85 | asm ( 86 | "mov r12, sp;" 87 | #if defined(ARDUINO_ARCH_SAMD) 88 | /* store low registers */ 89 | "stmia r0, {r4-r7};" 90 | /* store high registers */ 91 | "mov r1, r8;" /* move them to low registers first. */ 92 | "mov r2, r9;" 93 | "mov r3, r10;" 94 | "mov r4, r11;" 95 | "mov r5, r12;" 96 | "mov r6, lr;" 97 | "stmia r0, {r1-r6};" 98 | #else 99 | "stmia r0, {r4-r12, lr};" 100 | #endif 101 | /* schedule. */ 102 | "mov r0, #0;" /* previous task did not complete */ 103 | "bl coopSchedule;" 104 | /* r0 holds address of next task context */ 105 | #if defined(ARDUINO_ARCH_SAMD) 106 | /* for Cortex M0, ldm and stm are restricted to low registers */ 107 | /* load high registers */ 108 | "add r0, #16;" /* they are 4 words higher in memory */ 109 | "ldmia r0, {r1-r6};" /* load them in low registers first... */ 110 | "mov r8, r1;" /* ...and move them into high registers... */ 111 | "mov r9, r2;" 112 | "mov r10, r3;" 113 | "mov r11, r4;" 114 | "mov r12, r5;" 115 | "mov lr, r6;" 116 | /* load low registers */ 117 | "sub r0, r0, #40;" /* back to begin of context */ 118 | "ldmia r0, {r4-r7};" 119 | #else 120 | "ldmia r0, {r4-r12, lr};" 121 | #endif 122 | /* restore task stack */ 123 | "mov sp, r12;" 124 | /* resume task */ 125 | "bx lr;" 126 | ); 127 | } 128 | 129 | static int coopInit(void) { 130 | CoopTask* task; 131 | 132 | task = reinterpret_cast(malloc(sizeof(CoopTask))); 133 | if (!task) 134 | return 0; 135 | task->next = task; 136 | task->prev = task; 137 | task->stackPtr = 0; 138 | cur = task; 139 | 140 | return 1; 141 | } 142 | 143 | static int coopSpawn(SchedulerParametricTask taskF, void* taskData, uint32_t stackSz) { 144 | uint8_t *stack = (uint8_t*)malloc(stackSz); 145 | if (!stack) 146 | return 0; 147 | 148 | CoopTask *task = reinterpret_cast(malloc(sizeof(CoopTask))); 149 | if (!task) { 150 | free(stack); 151 | return 0; 152 | } 153 | task->stackPtr = stack; 154 | task->regs[0] = (uint32_t) taskF; 155 | task->regs[1] = (uint32_t) taskData; 156 | task->regs[8] = ((uint32_t)(stack + stackSz)) & ~7; 157 | task->regs[9] = (uint32_t) & coopTaskStart; 158 | 159 | task->prev = cur; 160 | task->next = cur->next; 161 | cur->next->prev = task; 162 | cur->next = task; 163 | 164 | // These are here so compiler is sure that function is 165 | // referenced in both variants (cancels a warning) 166 | if (stackSz == 0xFFFFFFFF) 167 | coopSchedule(0); 168 | if (stackSz == 0xFFFFFFFE) 169 | coopSchedule(1); 170 | 171 | return 1; 172 | } 173 | 174 | void yield(void) { 175 | coopDoYield(cur); 176 | } 177 | 178 | }; // extern "C" 179 | 180 | SchedulerClass::SchedulerClass() { 181 | coopInit(); 182 | } 183 | 184 | static void startLoopHelper(void *taskData) { 185 | SchedulerTask task = reinterpret_cast(taskData); 186 | while (true) 187 | task(); 188 | } 189 | 190 | void SchedulerClass::startLoop(SchedulerTask task, uint32_t stackSize) { 191 | coopSpawn(startLoopHelper, reinterpret_cast(task), stackSize); 192 | } 193 | 194 | static void startTaskHelper(void *taskData) { 195 | SchedulerTask task = reinterpret_cast(taskData); 196 | task(); 197 | } 198 | 199 | void SchedulerClass::start(SchedulerTask task, uint32_t stackSize) { 200 | coopSpawn(startTaskHelper, reinterpret_cast(task), stackSize); 201 | } 202 | 203 | void SchedulerClass::start(SchedulerParametricTask task, void *taskData, uint32_t stackSize) { 204 | coopSpawn(task, taskData, stackSize); 205 | } 206 | 207 | SchedulerClass Scheduler; 208 | -------------------------------------------------------------------------------- /src/Scheduler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef _SCHEDULER_H_ 18 | #define _SCHEDULER_H_ 19 | 20 | #include 21 | 22 | extern "C" { 23 | typedef void (*SchedulerTask)(void); 24 | typedef void (*SchedulerParametricTask)(void *); 25 | } 26 | 27 | class SchedulerClass { 28 | public: 29 | SchedulerClass(); 30 | static void startLoop(SchedulerTask task, uint32_t stackSize = 1024); 31 | static void start(SchedulerTask task, uint32_t stackSize = 1024); 32 | static void start(SchedulerParametricTask task, void *data, uint32_t stackSize = 1024); 33 | 34 | static void yield() { ::yield(); }; 35 | }; 36 | 37 | extern SchedulerClass Scheduler; 38 | 39 | #endif 40 | 41 | --------------------------------------------------------------------------------