├── .cargo └── config.toml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── avr-atmega328p.json ├── examples ├── serial.rs └── single-task.rs ├── rust-toolchain └── src ├── executor.rs ├── io.rs ├── io ├── ext.rs └── ext │ ├── read.rs │ └── write.rs ├── lib.rs └── spi.rs /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "avr-atmega328p.json" 3 | 4 | [unstable] 5 | build-std = ["core"] 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "arduino-uno" 5 | version = "0.1.0" 6 | source = "git+https://github.com/Rahix/avr-hal?rev=a20277873a8102998d5fd69743771bd8c0aa9423#a20277873a8102998d5fd69743771bd8c0aa9423" 7 | dependencies = [ 8 | "atmega328p-hal", 9 | "avr-hal-generic", 10 | ] 11 | 12 | [[package]] 13 | name = "async-avr" 14 | version = "0.1.0" 15 | dependencies = [ 16 | "arduino-uno", 17 | "atmega328p-hal", 18 | "avr-device", 19 | "avr-hal-generic", 20 | "futures-util", 21 | "panic-halt", 22 | "pin-utils", 23 | "ufmt", 24 | ] 25 | 26 | [[package]] 27 | name = "atmega328p-hal" 28 | version = "0.1.0" 29 | source = "git+https://github.com/Rahix/avr-hal?rev=a20277873a8102998d5fd69743771bd8c0aa9423#a20277873a8102998d5fd69743771bd8c0aa9423" 30 | dependencies = [ 31 | "avr-device", 32 | "avr-hal-generic", 33 | ] 34 | 35 | [[package]] 36 | name = "avr-device" 37 | version = "0.3.0" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "63801a7acebed9c5ad3d89a9d3baa394fdd4de5e3a9a2384f9659fa1dc7fa823" 40 | dependencies = [ 41 | "avr-device-macros", 42 | "bare-metal", 43 | "cfg-if", 44 | "vcell", 45 | ] 46 | 47 | [[package]] 48 | name = "avr-device-macros" 49 | version = "0.3.0" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "bdd9b528ac23fbb2553d35a7cc11bb857df30a9d2786c3686d1e8bbda9a7b4f8" 52 | dependencies = [ 53 | "proc-macro2", 54 | "quote", 55 | "syn", 56 | ] 57 | 58 | [[package]] 59 | name = "avr-hal-generic" 60 | version = "0.1.0" 61 | source = "git+https://github.com/Rahix/avr-hal?rev=a20277873a8102998d5fd69743771bd8c0aa9423#a20277873a8102998d5fd69743771bd8c0aa9423" 62 | dependencies = [ 63 | "avr-device", 64 | "cfg-if", 65 | "embedded-hal", 66 | "nb 0.1.3", 67 | "paste", 68 | "ufmt", 69 | "void", 70 | ] 71 | 72 | [[package]] 73 | name = "bare-metal" 74 | version = "0.2.5" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" 77 | dependencies = [ 78 | "rustc_version", 79 | ] 80 | 81 | [[package]] 82 | name = "cfg-if" 83 | version = "0.1.10" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 86 | 87 | [[package]] 88 | name = "embedded-hal" 89 | version = "0.2.4" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "fa998ce59ec9765d15216393af37a58961ddcefb14c753b4816ba2191d865fcb" 92 | dependencies = [ 93 | "nb 0.1.3", 94 | "void", 95 | ] 96 | 97 | [[package]] 98 | name = "futures-core" 99 | version = "0.3.5" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399" 102 | 103 | [[package]] 104 | name = "futures-macro" 105 | version = "0.3.5" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | checksum = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" 108 | dependencies = [ 109 | "proc-macro-hack", 110 | "proc-macro2", 111 | "quote", 112 | "syn", 113 | ] 114 | 115 | [[package]] 116 | name = "futures-task" 117 | version = "0.3.5" 118 | source = "registry+https://github.com/rust-lang/crates.io-index" 119 | checksum = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626" 120 | 121 | [[package]] 122 | name = "futures-util" 123 | version = "0.3.5" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | checksum = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" 126 | dependencies = [ 127 | "futures-core", 128 | "futures-macro", 129 | "futures-task", 130 | "pin-project", 131 | "pin-utils", 132 | "proc-macro-hack", 133 | "proc-macro-nested", 134 | ] 135 | 136 | [[package]] 137 | name = "nb" 138 | version = "0.1.3" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" 141 | dependencies = [ 142 | "nb 1.0.0", 143 | ] 144 | 145 | [[package]] 146 | name = "nb" 147 | version = "1.0.0" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" 150 | 151 | [[package]] 152 | name = "panic-halt" 153 | version = "0.2.0" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812" 156 | 157 | [[package]] 158 | name = "paste" 159 | version = "1.0.0" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | checksum = "f6ddc8e145de01d9180ac7b78b9676f95a9c2447f6a88b2c2a04702211bc5d71" 162 | 163 | [[package]] 164 | name = "pin-project" 165 | version = "0.4.23" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "ca4433fff2ae79342e497d9f8ee990d174071408f28f726d6d83af93e58e48aa" 168 | dependencies = [ 169 | "pin-project-internal", 170 | ] 171 | 172 | [[package]] 173 | name = "pin-project-internal" 174 | version = "0.4.23" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "2c0e815c3ee9a031fdf5af21c10aa17c573c9c6a566328d99e3936c34e36461f" 177 | dependencies = [ 178 | "proc-macro2", 179 | "quote", 180 | "syn", 181 | ] 182 | 183 | [[package]] 184 | name = "pin-utils" 185 | version = "0.1.0" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 188 | 189 | [[package]] 190 | name = "proc-macro-hack" 191 | version = "0.5.18" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | checksum = "99c605b9a0adc77b7211c6b1f722dcb613d68d66859a44f3d485a6da332b0598" 194 | 195 | [[package]] 196 | name = "proc-macro-nested" 197 | version = "0.1.6" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" 200 | 201 | [[package]] 202 | name = "proc-macro2" 203 | version = "1.0.19" 204 | source = "registry+https://github.com/rust-lang/crates.io-index" 205 | checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" 206 | dependencies = [ 207 | "unicode-xid", 208 | ] 209 | 210 | [[package]] 211 | name = "quote" 212 | version = "1.0.7" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" 215 | dependencies = [ 216 | "proc-macro2", 217 | ] 218 | 219 | [[package]] 220 | name = "rustc_version" 221 | version = "0.2.3" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 224 | dependencies = [ 225 | "semver", 226 | ] 227 | 228 | [[package]] 229 | name = "semver" 230 | version = "0.9.0" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 233 | dependencies = [ 234 | "semver-parser", 235 | ] 236 | 237 | [[package]] 238 | name = "semver-parser" 239 | version = "0.7.0" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 242 | 243 | [[package]] 244 | name = "syn" 245 | version = "1.0.38" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "e69abc24912995b3038597a7a593be5053eb0fb44f3cc5beec0deb421790c1f4" 248 | dependencies = [ 249 | "proc-macro2", 250 | "quote", 251 | "unicode-xid", 252 | ] 253 | 254 | [[package]] 255 | name = "ufmt" 256 | version = "0.1.0" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | checksum = "2e7ecea7ef79d3f8f878eee614afdf5256475c63ad76139d4da6125617c784a0" 259 | dependencies = [ 260 | "proc-macro-hack", 261 | "ufmt-macros", 262 | "ufmt-write", 263 | ] 264 | 265 | [[package]] 266 | name = "ufmt-macros" 267 | version = "0.1.1" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "ed813e34a2bfa9dc58ee2ed8c8314d25e6d70c911486d64b8085cb695cfac069" 270 | dependencies = [ 271 | "proc-macro-hack", 272 | "proc-macro2", 273 | "quote", 274 | "syn", 275 | ] 276 | 277 | [[package]] 278 | name = "ufmt-write" 279 | version = "0.1.0" 280 | source = "registry+https://github.com/rust-lang/crates.io-index" 281 | checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69" 282 | 283 | [[package]] 284 | name = "unicode-xid" 285 | version = "0.2.1" 286 | source = "registry+https://github.com/rust-lang/crates.io-index" 287 | checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" 288 | 289 | [[package]] 290 | name = "vcell" 291 | version = "0.1.2" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "876e32dcadfe563a4289e994f7cb391197f362b6315dc45e8ba4aa6f564a4b3c" 294 | 295 | [[package]] 296 | name = "void" 297 | version = "1.0.2" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 300 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "async-avr" 3 | version = "0.1.0" 4 | license = "MIT OR Apache-2.0" 5 | authors = ["lights0123 "] 6 | edition = "2018" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | panic-halt = "0.2.0" 12 | avr-hal-generic = { git = "https://github.com/Rahix/avr-hal", rev = "a20277873a8102998d5fd69743771bd8c0aa9423" } 13 | arduino-uno = { git = "https://github.com/Rahix/avr-hal", rev = "a20277873a8102998d5fd69743771bd8c0aa9423" } 14 | atmega328p-hal = { git = "https://github.com/Rahix/avr-hal", rev = "a20277873a8102998d5fd69743771bd8c0aa9423" } 15 | avr-device = { version = "0.3.0", features = ["atmega328p"]} 16 | pin-utils = "0.1.0" 17 | futures-util = { version = "0.3.5", default-features = false, features = ["async-await-macro"] } 18 | ufmt = "0.1.0" 19 | 20 | [profile.dev] 21 | panic = "abort" 22 | lto = true 23 | opt-level = "s" 24 | 25 | [profile.release] 26 | panic = "abort" 27 | codegen-units = 1 28 | lto = true 29 | opt-level = "s" 30 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # async-avr 2 | 3 | ## Required packages 4 | 5 | **Arch linux** 6 | 7 | ```bash 8 | sudo pacman -S avr-gcc avr-libc avrdude python-pip 9 | ``` 10 | 11 | **Ubuntu** 12 | 13 | ```bash 14 | sudo apt-get install binutils gcc-avr avr-libc avrdude python3-pip 15 | ``` 16 | 17 | **macOS** 18 | 19 | ```bash 20 | brew tap osx-cross/avr 21 | # removal needed before upgrading 22 | brew remove avr-gcc avr-binutils avr-libc 23 | # avr-libc is now included in avr-gcc 24 | brew install avr-gcc avr-binutils 25 | brew install avrdude 26 | ``` 27 | 28 | Alternatively, on a different OS or if you don't want to install system packages, you may use the 29 | binaries included with the Arduino IDE. To do so, first find where Arduino preferences are located: 30 | 31 | - Windows Store App: `%HOME%\Documents\ArduinoData\` 32 | - Windows: `%APPDATA%\Arduino15\` 33 | - macOS: `$HOME/Library/Arduino15/` 34 | - Linux: `~/.arduino15/` 35 | 36 | Now, append `packages/arduino/tools/avr-gcc/`, find the folder in that directory (e.g. 37 | `7.3.0-atmel3.6.1-arduino7` at the time of writing), and then finally add `/bin`. For example, on 38 | Linux, you may have `$HOME/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin`. 39 | 40 | Once you have the above path, add it to your path. For example, on macOS or Linux, run 41 | `export PATH="$HOME/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin:${PATH}"`. 42 | 43 | ## Initial installation 44 | 45 | `async-avr` needs nightly rust, as of beginning 2021 a special release even see [Rahix/avr-hal#124](https://github.com/Rahix/avr-hal/issues/124) 46 | 47 | create a file called `rust-toolchain` with the contents: 48 | 49 | ```toml 50 | [toolchain] 51 | channel = "nightly-2021-01-07" 52 | components = ["rust-src"] 53 | ``` 54 | 55 | this file allows you to run all cargo commands with that nightly release automatically selected. 56 | 57 | ## Compiling and Running 58 | 59 | We can compile by running 60 | 61 | ```bash 62 | cargo build --examples --release 63 | ``` 64 | 65 | **Note:** If you didn't create `rust-toolchain` this might work: 66 | 67 | ```bash 68 | cargo +nightly build --examples --release 69 | ``` 70 | 71 | Then, to upload it to a device, run: 72 | 73 | ```bash 74 | avrdude -v -patmega328p -carduino -P/dev/ttyACM0 -b115200 -D -Uflash:w:target/avr-atmega328p/release/examples/serial.elf:e 75 | ``` 76 | 77 | Change the upload path (`target/avr-atmega328p/release/examples/serial.elf`) to meet what you want 78 | to upload. 79 | 80 | ### If you only have the Arduino IDE installed 81 | 82 | Enable "Show verbose output during: upload" in the Arduino IDE. Observe the build logs for an 83 | `avrdude` command—it should look something like: 84 | 85 | ```bash 86 | /path/to/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17/bin/avrdude -C/path/to/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17/etc/avrdude.conf -v -patmega328p -carduino -P/dev/ttyACM0 -b115200 -D -Uflash:w:/tmp/arduino_build_721874/Blink.ino.hex:i 87 | ``` 88 | 89 | Copy that command, but delete everything after `-Uflash:w:`. Then, without spaces, add the path to 90 | your binary. This will typically be `target/avr-atmega328p/release/project_name.elf`, or 91 | `target/avr-atmega328p/release/examples/example_name.elf`. Finally, add `:e`. Your final command 92 | will probably look something like: 93 | 94 | ```bash 95 | /path/to/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17/bin/avrdude -C/path/to/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17/etc/avrdude.conf -v -patmega328p -carduino -P/dev/ttyACM0 -b115200 -D -Uflash:w:target/avr-atmega328p/release/example/serial.elf:e 96 | ``` 97 | 98 | > ### What about converting to hex first? 99 | > 100 | > Arduino typically converts the compiled binary to raw hex, and many AVR-Rust projects have 101 | > [followed that pattern][avr-objcopy]. However, there's generally no need to do that, as `avrdude` 102 | > has the ability to upload ELF binaries directly. 103 | 104 | [avr-objcopy]: 105 | https://github.com/Rahix/avr-hal/blob/bfc5dfe67107a68b4a673e54532354af126cb3ba/mkhex.sh#L32 106 | -------------------------------------------------------------------------------- /avr-atmega328p.json: -------------------------------------------------------------------------------- 1 | { 2 | "llvm-target": "avr-unknown-unknown", 3 | "cpu": "atmega328p", 4 | "target-endian": "little", 5 | "target-pointer-width": "16", 6 | "target-c-int-width": "16", 7 | "os": "unknown", 8 | "target-env": "", 9 | "target-vendor": "unknown", 10 | "arch": "avr", 11 | "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8", 12 | 13 | "executables": true, 14 | 15 | "linker": "avr-gcc", 16 | "linker-flavor": "gcc", 17 | "pre-link-args": { 18 | "gcc": ["-Os", "-mmcu=atmega328p"] 19 | }, 20 | "exe-suffix": ".elf", 21 | "post-link-args": { 22 | "gcc": ["-Wl,--gc-sections"] 23 | }, 24 | 25 | "singlethread": false, 26 | "no-builtins": false, 27 | 28 | "no-default-libraries": false, 29 | 30 | "eh-frame-header": false 31 | } 32 | -------------------------------------------------------------------------------- /examples/serial.rs: -------------------------------------------------------------------------------- 1 | //! This example demonstrates how to set up a SPI interface and communicate 2 | //! over it. The physical hardware configuation consists of connecting a 3 | //! jumper directly from pin `~11` to pin `~12`. 4 | //! 5 | //! This example opens a serial connection to the host computer. On most POSIX operating systems (like GNU/Linux or 6 | //! OSX), you can interface with the program by running (assuming the device appears as ttyACM0) 7 | //! 8 | //! $ sudo screen /dev/ttyACM0 57600# 9 | 10 | #![no_std] 11 | #![no_main] 12 | #![feature(abi_avr_interrupt)] 13 | 14 | use panic_halt as _; 15 | 16 | use core::cell::{Cell, RefCell}; 17 | 18 | use arduino_uno::prelude::*; 19 | use arduino_uno::spi::{Settings, Spi}; 20 | 21 | use async_avr::io::{AsyncReadExt, AsyncWriteExt}; 22 | use async_avr::{block_on, AsyncSerial, AsyncSpi, Yield}; 23 | 24 | #[arduino_uno::entry] 25 | fn main() -> ! { 26 | let dp = arduino_uno::Peripherals::take().unwrap(); 27 | 28 | let mut pins = arduino_uno::Pins::new(dp.PORTB, dp.PORTC, dp.PORTD); 29 | 30 | let serial = arduino_uno::Serial::new( 31 | dp.USART0, 32 | pins.d0, 33 | pins.d1.into_output(&mut pins.ddr), 34 | 57600.into_baudrate(), 35 | ); 36 | 37 | // Create SPI interface. 38 | let (spi, _) = Spi::new( 39 | dp.SPI, 40 | pins.d13.into_output(&mut pins.ddr), 41 | pins.d11.into_output(&mut pins.ddr), 42 | pins.d12.into_pull_up_input(&mut pins.ddr), 43 | pins.d10.into_output(&mut pins.ddr), 44 | Settings::default(), 45 | ); 46 | 47 | let mut spi = AsyncSpi::new(spi); 48 | 49 | let (rx, tx) = serial.split(); 50 | let mut rx = AsyncSerial::new(rx); 51 | let tx = RefCell::new(AsyncSerial::new(tx)); 52 | 53 | let serial_lock = Cell::new(false); 54 | 55 | let serial_loop = async { 56 | loop { 57 | let mut b = [0]; 58 | rx.read_exact(&mut b).await.unwrap(); 59 | loop { 60 | if !serial_lock.get() { 61 | serial_lock.set(true); 62 | tx.borrow_mut().write_all(b"hello!\n").await.unwrap(); 63 | serial_lock.set(false); 64 | break; 65 | } 66 | Yield::default().await; 67 | } 68 | } 69 | }; 70 | 71 | let spi_loop = async { 72 | loop { 73 | spi.write_all(b"a").await.unwrap(); 74 | let mut data = [0; 1]; 75 | spi.read_exact(&mut data).await.unwrap(); 76 | loop { 77 | if !serial_lock.get() { 78 | serial_lock.set(true); 79 | let mut tx_ref = tx.borrow_mut(); 80 | tx_ref.write_all(b"wrote ").await.unwrap(); 81 | tx_ref.write_all(&data).await.unwrap(); 82 | tx_ref.write_all(b"!\n").await.unwrap(); 83 | serial_lock.set(false); 84 | break; 85 | } 86 | Yield::default().await; 87 | } 88 | Yield::default().await; 89 | } 90 | }; 91 | 92 | block_on(async { futures_util::join!(serial_loop, spi_loop) }); 93 | loop {} 94 | } 95 | -------------------------------------------------------------------------------- /examples/single-task.rs: -------------------------------------------------------------------------------- 1 | //! This example opens a serial connection to the host computer. On most POSIX operating systems (like GNU/Linux or 2 | //! OSX), you can interface with the program by running (assuming the device appears as ttyACM0) 3 | //! 4 | //! $ sudo screen /dev/ttyACM0 57600 5 | 6 | #![no_std] 7 | #![no_main] 8 | 9 | use panic_halt as _; 10 | 11 | use arduino_uno::prelude::*; 12 | 13 | use async_avr::io::AsyncWriteExt; 14 | use async_avr::{block_on, AsyncSerial}; 15 | 16 | #[arduino_uno::entry] 17 | fn main() -> ! { 18 | let dp = arduino_uno::Peripherals::take().unwrap(); 19 | 20 | let mut pins = arduino_uno::Pins::new(dp.PORTB, dp.PORTC, dp.PORTD); 21 | 22 | let mut serial = AsyncSerial::new(arduino_uno::Serial::new( 23 | dp.USART0, 24 | pins.d0, 25 | pins.d1.into_output(&mut pins.ddr), 26 | 57600.into_baudrate(), 27 | )); 28 | 29 | block_on(async { 30 | loop { 31 | serial.write_all(b"Hello World!\n").await.unwrap(); 32 | } 33 | }); 34 | loop {} 35 | } 36 | -------------------------------------------------------------------------------- /rust-toolchain: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2021-01-07" 3 | components = ["rust-src"] 4 | -------------------------------------------------------------------------------- /src/executor.rs: -------------------------------------------------------------------------------- 1 | use core::cell::UnsafeCell; 2 | use core::future::Future; 3 | use core::ptr; 4 | use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; 5 | use pin_utils::pin_mut; 6 | 7 | #[derive(Debug)] 8 | #[repr(transparent)] 9 | struct Volatile(UnsafeCell); 10 | 11 | impl Volatile { 12 | pub fn new(value: T) -> Volatile { 13 | Volatile(UnsafeCell::new(value)) 14 | } 15 | 16 | pub fn read(&self) -> T { 17 | unsafe { ptr::read_volatile(self.0.get()) } 18 | } 19 | 20 | pub fn write(&self, value: T) { 21 | unsafe { ptr::write_volatile(self.0.get(), value) }; 22 | } 23 | } 24 | 25 | // NOTE `*const ()` is &Volatile 26 | static VTABLE: RawWakerVTable = { 27 | unsafe fn clone(p: *const ()) -> RawWaker { 28 | RawWaker::new(p, &VTABLE) 29 | } 30 | unsafe fn wake(p: *const ()) { 31 | wake_by_ref(p) 32 | } 33 | unsafe fn wake_by_ref(p: *const ()) { 34 | (*(p as *const Volatile)).write(true) 35 | } 36 | unsafe fn drop(_: *const ()) { 37 | // no-op 38 | } 39 | 40 | RawWakerVTable::new(clone, wake, wake_by_ref, drop) 41 | }; 42 | 43 | /// Spawns a task and blocks until the future resolves, returning its result. 44 | pub fn block_on(task: impl Future) -> T { 45 | let ready = Volatile::new(true); 46 | let waker = unsafe { Waker::from_raw(RawWaker::new(&ready as *const _ as *const _, &VTABLE)) }; 47 | let mut context = Context::from_waker(&waker); 48 | pin_mut!(task); 49 | let mut task = task; 50 | loop { 51 | while ready.read() { 52 | match task.as_mut().poll(&mut context) { 53 | Poll::Ready(val) => { 54 | return val; 55 | } 56 | Poll::Pending => { 57 | // ready.write(false); 58 | } 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/io.rs: -------------------------------------------------------------------------------- 1 | use core::pin::Pin; 2 | use core::task::{Context, Poll}; 3 | pub use ext::*; 4 | mod ext; 5 | /// Read bytes asynchronously. 6 | /// 7 | /// This trait is analogous to the `std::io::Read` trait, but integrates 8 | /// with the asynchronous task system. In particular, the `poll_read` 9 | /// method, unlike `Read::read`, will automatically queue the current task 10 | /// for wakeup and return if data is not yet available, rather than blocking 11 | /// the calling thread. 12 | pub trait AsyncRead { 13 | type Error; 14 | /// Determines if this `AsyncRead`er can work with buffers of 15 | /// uninitialized memory. 16 | /// 17 | /// The default implementation returns an initializer which will zero 18 | /// buffers. 19 | /// 20 | /// This method is only available when the `read-initializer` feature of this 21 | /// library is activated. 22 | /// 23 | /// # Safety 24 | /// 25 | /// This method is `unsafe` because an `AsyncRead`er could otherwise 26 | /// return a non-zeroing `Initializer` from another `AsyncRead` type 27 | /// without an `unsafe` block. 28 | #[cfg(feature = "read-initializer")] 29 | #[inline] 30 | unsafe fn initializer(&self) -> Initializer { 31 | Initializer::zeroing() 32 | } 33 | 34 | /// Attempt to read from the `AsyncRead` into `buf`. 35 | /// 36 | /// On success, returns `Poll::Ready(Ok(num_bytes_read))`. 37 | /// 38 | /// If no data is available for reading, the method returns 39 | /// `Poll::Pending` and arranges for the current task (via 40 | /// `cx.waker().wake_by_ref()`) to receive a notification when the object becomes 41 | /// readable or is closed. 42 | /// 43 | /// # Implementation 44 | /// 45 | /// This function may not return errors of kind `WouldBlock` or 46 | /// `Interrupted`. Implementations must convert `WouldBlock` into 47 | /// `Poll::Pending` and either internally retry or convert 48 | /// `Interrupted` into another error kind. 49 | fn poll_read( 50 | self: Pin<&mut Self>, 51 | cx: &mut Context<'_>, 52 | buf: &mut [u8], 53 | ) -> Poll>; 54 | } 55 | 56 | impl AsyncRead for &mut T { 57 | type Error = T::Error; 58 | 59 | #[cfg(feature = "read-initializer")] 60 | unsafe fn initializer(&self) -> Initializer { 61 | (**self).initializer() 62 | } 63 | 64 | fn poll_read( 65 | mut self: Pin<&mut Self>, 66 | cx: &mut Context<'_>, 67 | buf: &mut [u8], 68 | ) -> Poll> { 69 | Pin::new(&mut **self).poll_read(cx, buf) 70 | } 71 | } 72 | 73 | /// Write bytes asynchronously. 74 | /// 75 | /// This trait is analogous to the `std::io::Write` trait, but integrates 76 | /// with the asynchronous task system. In particular, the `poll_write` 77 | /// method, unlike `Write::write`, will automatically queue the current task 78 | /// for wakeup and return if the writer cannot take more data, rather than blocking 79 | /// the calling thread. 80 | pub trait AsyncWrite { 81 | type Error; 82 | /// Attempt to write bytes from `buf` into the object. 83 | /// 84 | /// On success, returns `Poll::Ready(Ok(num_bytes_written))`. 85 | /// 86 | /// If the object is not ready for writing, the method returns 87 | /// `Poll::Pending` and arranges for the current task (via 88 | /// `cx.waker().wake_by_ref()`) to receive a notification when the object becomes 89 | /// writable or is closed. 90 | /// 91 | /// # Implementation 92 | /// 93 | /// This function may not return errors of kind `WouldBlock` or 94 | /// `Interrupted`. Implementations must convert `WouldBlock` into 95 | /// `Poll::Pending` and either internally retry or convert 96 | /// `Interrupted` into another error kind. 97 | /// 98 | /// `poll_write` must try to make progress by flushing the underlying object if 99 | /// that is the only way the underlying object can become writable again. 100 | fn poll_write( 101 | self: Pin<&mut Self>, 102 | cx: &mut Context<'_>, 103 | buf: &[u8], 104 | ) -> Poll>; 105 | 106 | /// Attempt to flush the object, ensuring that any buffered data reach 107 | /// their destination. 108 | /// 109 | /// On success, returns `Poll::Ready(Ok(()))`. 110 | /// 111 | /// If flushing cannot immediately complete, this method returns 112 | /// `Poll::Pending` and arranges for the current task (via 113 | /// `cx.waker().wake_by_ref()`) to receive a notification when the object can make 114 | /// progress towards flushing. 115 | /// 116 | /// # Implementation 117 | /// 118 | /// This function may not return errors of kind `WouldBlock` or 119 | /// `Interrupted`. Implementations must convert `WouldBlock` into 120 | /// `Poll::Pending` and either internally retry or convert 121 | /// `Interrupted` into another error kind. 122 | /// 123 | /// It only makes sense to do anything here if you actually buffer data. 124 | fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>; 125 | 126 | /// Attempt to close the object. 127 | /// 128 | /// On success, returns `Poll::Ready(Ok(()))`. 129 | /// 130 | /// If closing cannot immediately complete, this function returns 131 | /// `Poll::Pending` and arranges for the current task (via 132 | /// `cx.waker().wake_by_ref()`) to receive a notification when the object can make 133 | /// progress towards closing. 134 | /// 135 | /// # Implementation 136 | /// 137 | /// This function may not return errors of kind `WouldBlock` or 138 | /// `Interrupted`. Implementations must convert `WouldBlock` into 139 | /// `Poll::Pending` and either internally retry or convert 140 | /// `Interrupted` into another error kind. 141 | fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll>; 142 | } 143 | 144 | impl AsyncWrite for &mut T { 145 | type Error = T::Error; 146 | 147 | fn poll_write( 148 | mut self: Pin<&mut Self>, 149 | cx: &mut Context<'_>, 150 | buf: &[u8], 151 | ) -> Poll> { 152 | Pin::new(&mut **self).poll_write(cx, buf) 153 | } 154 | 155 | fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 156 | Pin::new(&mut **self).poll_flush(cx) 157 | } 158 | 159 | fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 160 | Pin::new(&mut **self).poll_close(cx) 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/io/ext.rs: -------------------------------------------------------------------------------- 1 | use super::{AsyncRead, AsyncWrite}; 2 | use read::*; 3 | use write::*; 4 | 5 | mod read; 6 | mod write; 7 | /// An extension trait which adds utility methods to `AsyncRead` types. 8 | pub trait AsyncReadExt: AsyncRead { 9 | // /// Creates an adaptor which will chain this stream with another. 10 | // /// 11 | // /// The returned `AsyncRead` instance will first read all bytes from this object 12 | // /// until EOF is encountered. Afterwards the output is equivalent to the 13 | // /// output of `next`. 14 | // /// 15 | // /// # Examples 16 | // /// 17 | // /// ``` 18 | // /// # futures::executor::block_on(async { 19 | // /// use futures::io::{AsyncReadExt, Cursor}; 20 | // /// 21 | // /// let reader1 = Cursor::new([1, 2, 3, 4]); 22 | // /// let reader2 = Cursor::new([5, 6, 7, 8]); 23 | // /// 24 | // /// let mut reader = reader1.chain(reader2); 25 | // /// let mut buffer = Vec::new(); 26 | // /// 27 | // /// // read the value into a Vec. 28 | // /// reader.read_to_end(&mut buffer).await?; 29 | // /// assert_eq!(buffer, [1, 2, 3, 4, 5, 6, 7, 8]); 30 | // /// # Ok::<(), Box>(()) }).unwrap(); 31 | // /// ``` 32 | // fn chain(self, next: R) -> Chain 33 | // where 34 | // Self: Sized, 35 | // R: AsyncRead, 36 | // { 37 | // Chain::new(self, next) 38 | // } 39 | 40 | /// Tries to read some bytes directly into the given `buf` in asynchronous 41 | /// manner, returning a future type. 42 | /// 43 | /// The returned future will resolve to the number of bytes read once the read 44 | /// operation is completed. 45 | /// 46 | /// # Examples 47 | /// 48 | /// ``` 49 | /// # futures::executor::block_on(async { 50 | /// use futures::io::{AsyncReadExt, Cursor}; 51 | /// 52 | /// let mut reader = Cursor::new([1, 2, 3, 4]); 53 | /// let mut output = [0u8; 5]; 54 | /// 55 | /// let bytes = reader.read(&mut output[..]).await?; 56 | /// 57 | /// // This is only guaranteed to be 4 because `&[u8]` is a synchronous 58 | /// // reader. In a real system you could get anywhere from 1 to 59 | /// // `output.len()` bytes in a single read. 60 | /// assert_eq!(bytes, 4); 61 | /// assert_eq!(output, [1, 2, 3, 4, 0]); 62 | /// # Ok::<(), Box>(()) }).unwrap(); 63 | /// ``` 64 | fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Read<'a, Self> 65 | where 66 | Self: Unpin, 67 | { 68 | Read::new(self, buf) 69 | } 70 | 71 | // /// Creates a future which will read from the `AsyncRead` into `bufs` using vectored 72 | // /// IO operations. 73 | // /// 74 | // /// The returned future will resolve to the number of bytes read once the read 75 | // /// operation is completed. 76 | // fn read_vectored<'a>(&'a mut self, bufs: &'a mut [IoSliceMut<'a>]) -> ReadVectored<'a, Self> 77 | // where Self: Unpin, 78 | // { 79 | // ReadVectored::new(self, bufs) 80 | // } 81 | 82 | /// Creates a future which will read exactly enough bytes to fill `buf`, 83 | /// returning an error if end of file (EOF) is hit sooner. 84 | /// 85 | /// The returned future will resolve once the read operation is completed. 86 | /// 87 | /// In the case of an error the buffer and the object will be discarded, with 88 | /// the error yielded. 89 | /// 90 | /// # Examples 91 | /// 92 | /// ``` 93 | /// # futures::executor::block_on(async { 94 | /// use futures::io::{AsyncReadExt, Cursor}; 95 | /// 96 | /// let mut reader = Cursor::new([1, 2, 3, 4]); 97 | /// let mut output = [0u8; 4]; 98 | /// 99 | /// reader.read_exact(&mut output).await?; 100 | /// 101 | /// assert_eq!(output, [1, 2, 3, 4]); 102 | /// # Ok::<(), Box>(()) }).unwrap(); 103 | /// ``` 104 | /// 105 | /// ## EOF is hit before `buf` is filled 106 | /// 107 | /// ``` 108 | /// # futures::executor::block_on(async { 109 | /// use futures::io::{self, AsyncReadExt, Cursor}; 110 | /// 111 | /// let mut reader = Cursor::new([1, 2, 3, 4]); 112 | /// let mut output = [0u8; 5]; 113 | /// 114 | /// let result = reader.read_exact(&mut output).await; 115 | /// 116 | /// assert_eq!(result.unwrap_err().kind(), io::ErrorKind::UnexpectedEof); 117 | /// # }); 118 | /// ``` 119 | fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadExact<'a, Self> 120 | where 121 | Self: Unpin, 122 | { 123 | ReadExact::new(self, buf) 124 | } 125 | 126 | // /// Creates a future which will read all the bytes from this `AsyncRead`. 127 | // /// 128 | // /// On success the total number of bytes read is returned. 129 | // /// 130 | // /// # Examples 131 | // /// 132 | // /// ``` 133 | // /// # futures::executor::block_on(async { 134 | // /// use futures::io::{AsyncReadExt, Cursor}; 135 | // /// 136 | // /// let mut reader = Cursor::new([1, 2, 3, 4]); 137 | // /// let mut output = Vec::with_capacity(4); 138 | // /// 139 | // /// let bytes = reader.read_to_end(&mut output).await?; 140 | // /// 141 | // /// assert_eq!(bytes, 4); 142 | // /// assert_eq!(output, vec![1, 2, 3, 4]); 143 | // /// # Ok::<(), Box>(()) }).unwrap(); 144 | // /// ``` 145 | // fn read_to_end<'a>( 146 | // &'a mut self, 147 | // buf: &'a mut Vec, 148 | // ) -> ReadToEnd<'a, Self> 149 | // where Self: Unpin, 150 | // { 151 | // ReadToEnd::new(self, buf) 152 | // } 153 | // 154 | // /// Creates a future which will read all the bytes from this `AsyncRead`. 155 | // /// 156 | // /// On success the total number of bytes read is returned. 157 | // /// 158 | // /// # Examples 159 | // /// 160 | // /// ``` 161 | // /// # futures::executor::block_on(async { 162 | // /// use futures::io::{AsyncReadExt, Cursor}; 163 | // /// 164 | // /// let mut reader = Cursor::new(&b"1234"[..]); 165 | // /// let mut buffer = String::with_capacity(4); 166 | // /// 167 | // /// let bytes = reader.read_to_string(&mut buffer).await?; 168 | // /// 169 | // /// assert_eq!(bytes, 4); 170 | // /// assert_eq!(buffer, String::from("1234")); 171 | // /// # Ok::<(), Box>(()) }).unwrap(); 172 | // /// ``` 173 | // fn read_to_string<'a>( 174 | // &'a mut self, 175 | // buf: &'a mut String, 176 | // ) -> ReadToString<'a, Self> 177 | // where Self: Unpin, 178 | // { 179 | // ReadToString::new(self, buf) 180 | // } 181 | 182 | // /// Helper method for splitting this read/write object into two halves. 183 | // /// 184 | // /// The two halves returned implement the `AsyncRead` and `AsyncWrite` 185 | // /// traits, respectively. 186 | // /// 187 | // /// # Examples 188 | // /// 189 | // /// ``` 190 | // /// # futures::executor::block_on(async { 191 | // /// use futures::io::{self, AsyncReadExt, Cursor}; 192 | // /// 193 | // /// // Note that for `Cursor` the read and write halves share a single 194 | // /// // seek position. This may or may not be true for other types that 195 | // /// // implement both `AsyncRead` and `AsyncWrite`. 196 | // /// 197 | // /// let reader = Cursor::new([1, 2, 3, 4]); 198 | // /// let mut buffer = Cursor::new(vec![0, 0, 0, 0, 5, 6, 7, 8]); 199 | // /// let mut writer = Cursor::new(vec![0u8; 5]); 200 | // /// 201 | // /// { 202 | // /// let (buffer_reader, mut buffer_writer) = (&mut buffer).split(); 203 | // /// io::copy(reader, &mut buffer_writer).await?; 204 | // /// io::copy(buffer_reader, &mut writer).await?; 205 | // /// } 206 | // /// 207 | // /// assert_eq!(buffer.into_inner(), [1, 2, 3, 4, 5, 6, 7, 8]); 208 | // /// assert_eq!(writer.into_inner(), [5, 6, 7, 8, 0]); 209 | // /// # Ok::<(), Box>(()) }).unwrap(); 210 | // /// ``` 211 | // fn split(self) -> (ReadHalf, WriteHalf) 212 | // where Self: AsyncWrite + Sized, 213 | // { 214 | // split::split(self) 215 | // } 216 | 217 | // /// Creates an AsyncRead adapter which will read at most `limit` bytes 218 | // /// from the underlying reader. 219 | // /// 220 | // /// # Examples 221 | // /// 222 | // /// ``` 223 | // /// # futures::executor::block_on(async { 224 | // /// use futures::io::{AsyncReadExt, Cursor}; 225 | // /// 226 | // /// let reader = Cursor::new(&b"12345678"[..]); 227 | // /// let mut buffer = [0; 5]; 228 | // /// 229 | // /// let mut take = reader.take(4); 230 | // /// let n = take.read(&mut buffer).await?; 231 | // /// 232 | // /// assert_eq!(n, 4); 233 | // /// assert_eq!(&buffer, b"1234\0"); 234 | // /// # Ok::<(), Box>(()) }).unwrap(); 235 | // /// ``` 236 | // fn take(self, limit: u64) -> Take 237 | // where Self: Sized 238 | // { 239 | // Take::new(self, limit) 240 | // } 241 | } 242 | 243 | impl AsyncReadExt for R {} 244 | 245 | /// An extension trait which adds utility methods to `AsyncWrite` types. 246 | pub trait AsyncWriteExt: AsyncWrite { 247 | /// Creates a future which will entirely flush this `AsyncWrite`. 248 | /// 249 | /// # Examples 250 | /// 251 | /// ``` 252 | /// # futures::executor::block_on(async { 253 | /// use futures::io::{AllowStdIo, AsyncWriteExt}; 254 | /// use std::io::{BufWriter, Cursor}; 255 | /// 256 | /// let mut output = vec![0u8; 5]; 257 | /// 258 | /// { 259 | /// let writer = Cursor::new(&mut output); 260 | /// let mut buffered = AllowStdIo::new(BufWriter::new(writer)); 261 | /// buffered.write_all(&[1, 2]).await?; 262 | /// buffered.write_all(&[3, 4]).await?; 263 | /// buffered.flush().await?; 264 | /// } 265 | /// 266 | /// assert_eq!(output, [1, 2, 3, 4, 0]); 267 | /// # Ok::<(), Box>(()) }).unwrap(); 268 | /// ``` 269 | fn flush(&mut self) -> Flush<'_, Self> 270 | where 271 | Self: Unpin, 272 | { 273 | Flush::new(self) 274 | } 275 | 276 | /// Creates a future which will entirely close this `AsyncWrite`. 277 | fn close(&mut self) -> Close<'_, Self> 278 | where 279 | Self: Unpin, 280 | { 281 | Close::new(self) 282 | } 283 | 284 | /// Creates a future which will write bytes from `buf` into the object. 285 | /// 286 | /// The returned future will resolve to the number of bytes written once the write 287 | /// operation is completed. 288 | fn write<'a>(&'a mut self, buf: &'a [u8]) -> Write<'a, Self> 289 | where 290 | Self: Unpin, 291 | { 292 | Write::new(self, buf) 293 | } 294 | 295 | // /// Creates a future which will write bytes from `bufs` into the object using vectored 296 | // /// IO operations. 297 | // /// 298 | // /// The returned future will resolve to the number of bytes written once the write 299 | // /// operation is completed. 300 | // fn write_vectored<'a>(&'a mut self, bufs: &'a [IoSlice<'a>]) -> WriteVectored<'a, Self> 301 | // where Self: Unpin, 302 | // { 303 | // WriteVectored::new(self, bufs) 304 | // } 305 | 306 | /// Write data into this object. 307 | /// 308 | /// Creates a future that will write the entire contents of the buffer `buf` into 309 | /// this `AsyncWrite`. 310 | /// 311 | /// The returned future will not complete until all the data has been written. 312 | /// 313 | /// # Examples 314 | /// 315 | /// ``` 316 | /// # futures::executor::block_on(async { 317 | /// use futures::io::{AsyncWriteExt, Cursor}; 318 | /// 319 | /// let mut writer = Cursor::new(vec![0u8; 5]); 320 | /// 321 | /// writer.write_all(&[1, 2, 3, 4]).await?; 322 | /// 323 | /// assert_eq!(writer.into_inner(), [1, 2, 3, 4, 0]); 324 | /// # Ok::<(), Box>(()) }).unwrap(); 325 | /// ``` 326 | fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> WriteAll<'a, Self> 327 | where 328 | Self: Unpin, 329 | { 330 | WriteAll::new(self, buf) 331 | } 332 | 333 | // /// Attempts to write multiple buffers into this writer. 334 | // /// 335 | // /// Creates a future that will write the entire contents of `bufs` into this 336 | // /// `AsyncWrite` using [vectored writes]. 337 | // /// 338 | // /// The returned future will not complete until all the data has been 339 | // /// written. 340 | // /// 341 | // /// [vectored writes]: std::io::Write::write_vectored 342 | // /// 343 | // /// # Notes 344 | // /// 345 | // /// Unlike `io::Write::write_vectored`, this takes a *mutable* reference to 346 | // /// a slice of `IoSlice`s, not an immutable one. That's because we need to 347 | // /// modify the slice to keep track of the bytes already written. 348 | // /// 349 | // /// Once this futures returns, the contents of `bufs` are unspecified, as 350 | // /// this depends on how many calls to `write_vectored` were necessary. It is 351 | // /// best to understand this function as taking ownership of `bufs` and to 352 | // /// not use `bufs` afterwards. The underlying buffers, to which the 353 | // /// `IoSlice`s point (but not the `IoSlice`s themselves), are unchanged and 354 | // /// can be reused. 355 | // /// 356 | // /// # Examples 357 | // /// 358 | // /// ``` 359 | // /// # futures::executor::block_on(async { 360 | // /// use futures::io::AsyncWriteExt; 361 | // /// use std::io::{Cursor, IoSlice}; 362 | // /// 363 | // /// let mut writer = Cursor::new([0u8; 7]); 364 | // /// let bufs = &mut [ 365 | // /// IoSlice::new(&[1]), 366 | // /// IoSlice::new(&[2, 3]), 367 | // /// IoSlice::new(&[4, 5, 6]), 368 | // /// ]; 369 | // /// 370 | // /// writer.write_all_vectored(bufs).await?; 371 | // /// // Note: the contents of `bufs` is now undefined, see the Notes section. 372 | // /// 373 | // /// assert_eq!(writer.into_inner(), [1, 2, 3, 4, 5, 6, 0]); 374 | // /// # Ok::<(), Box>(()) }).unwrap(); 375 | // /// ``` 376 | // #[cfg(feature = "write_all_vectored")] 377 | // fn write_all_vectored<'a>( 378 | // &'a mut self, 379 | // bufs: &'a mut [IoSlice<'a>], 380 | // ) -> WriteAllVectored<'a, Self> 381 | // where 382 | // Self: Unpin, 383 | // { 384 | // WriteAllVectored::new(self, bufs) 385 | // } 386 | 387 | /// Allow using an [`AsyncWrite`] as a [`Sink`](futures_sink::Sink)`>`. 388 | /// 389 | /// This adapter produces a sink that will write each value passed to it 390 | /// into the underlying writer. 391 | /// 392 | /// Note that this function consumes the given writer, returning a wrapped 393 | /// version. 394 | /// 395 | /// # Examples 396 | /// 397 | /// ``` 398 | /// # futures::executor::block_on(async { 399 | /// use futures::io::AsyncWriteExt; 400 | /// use futures::stream::{self, StreamExt}; 401 | /// 402 | /// let stream = stream::iter(vec![Ok([1, 2, 3]), Ok([4, 5, 6])]); 403 | /// 404 | /// let mut writer = vec![]; 405 | /// 406 | /// stream.forward((&mut writer).into_sink()).await?; 407 | /// 408 | /// assert_eq!(writer, vec![1, 2, 3, 4, 5, 6]); 409 | /// # Ok::<(), Box>(()) 410 | /// # })?; 411 | /// # Ok::<(), Box>(()) 412 | /// ``` 413 | #[cfg(feature = "sink")] 414 | fn into_sink>(self) -> IntoSink 415 | where 416 | Self: Sized, 417 | { 418 | IntoSink::new(self) 419 | } 420 | } 421 | 422 | impl AsyncWriteExt for W {} 423 | -------------------------------------------------------------------------------- /src/io/ext/read.rs: -------------------------------------------------------------------------------- 1 | use crate::io::AsyncRead; 2 | use core::future::Future; 3 | use core::mem; 4 | use core::pin::Pin; 5 | use core::task::{Context, Poll}; 6 | use futures_util::ready; 7 | 8 | /// Future for the [`read`](super::AsyncReadExt::read) method. 9 | #[derive(Debug)] 10 | #[must_use = "futures do nothing unless you `.await` or poll them"] 11 | pub struct Read<'a, R: ?Sized> { 12 | reader: &'a mut R, 13 | buf: &'a mut [u8], 14 | } 15 | 16 | impl Unpin for Read<'_, R> {} 17 | 18 | impl<'a, R: AsyncRead + ?Sized + Unpin> Read<'a, R> { 19 | pub(super) fn new(reader: &'a mut R, buf: &'a mut [u8]) -> Self { 20 | Read { reader, buf } 21 | } 22 | } 23 | 24 | impl Future for Read<'_, R> { 25 | type Output = Result; 26 | 27 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 28 | let this = &mut *self; 29 | Pin::new(&mut this.reader).poll_read(cx, this.buf) 30 | } 31 | } 32 | 33 | /// Future for the [`read_exact`](super::AsyncReadExt::read_exact) method. 34 | #[derive(Debug)] 35 | #[must_use = "futures do nothing unless you `.await` or poll them"] 36 | pub struct ReadExact<'a, R: ?Sized> { 37 | reader: &'a mut R, 38 | buf: &'a mut [u8], 39 | } 40 | 41 | impl Unpin for ReadExact<'_, R> {} 42 | 43 | impl<'a, R: AsyncRead + ?Sized + Unpin> ReadExact<'a, R> { 44 | pub(super) fn new(reader: &'a mut R, buf: &'a mut [u8]) -> Self { 45 | ReadExact { reader, buf } 46 | } 47 | } 48 | 49 | #[derive(Debug, Eq, PartialEq, Copy, Clone)] 50 | pub enum ReadExactError { 51 | UnexpectedEof, 52 | Other(E), 53 | } 54 | 55 | impl From for ReadExactError { 56 | fn from(err: E) -> Self { 57 | ReadExactError::Other(err) 58 | } 59 | } 60 | 61 | impl Future for ReadExact<'_, R> { 62 | type Output = Result<(), ReadExactError>; 63 | 64 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 65 | let this = &mut *self; 66 | while !this.buf.is_empty() { 67 | let n = ready!(Pin::new(&mut this.reader).poll_read(cx, this.buf))?; 68 | { 69 | let (_, rest) = mem::replace(&mut this.buf, &mut []).split_at_mut(n); 70 | this.buf = rest; 71 | } 72 | if n == 0 { 73 | return Poll::Ready(Err(ReadExactError::UnexpectedEof)); 74 | } 75 | } 76 | Poll::Ready(Ok(())) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/io/ext/write.rs: -------------------------------------------------------------------------------- 1 | use crate::io::AsyncWrite; 2 | use core::future::Future; 3 | use core::mem; 4 | use core::pin::Pin; 5 | use core::task::{Context, Poll}; 6 | use futures_util::ready; 7 | 8 | /// Future for the [`write`](super::AsyncWriteExt::write) method. 9 | #[derive(Debug)] 10 | #[must_use = "futures do nothing unless you `.await` or poll them"] 11 | pub struct Write<'a, W: ?Sized> { 12 | writer: &'a mut W, 13 | buf: &'a [u8], 14 | } 15 | 16 | impl Unpin for Write<'_, W> {} 17 | 18 | impl<'a, W: AsyncWrite + ?Sized + Unpin> Write<'a, W> { 19 | pub(super) fn new(writer: &'a mut W, buf: &'a [u8]) -> Self { 20 | Self { writer, buf } 21 | } 22 | } 23 | 24 | impl Future for Write<'_, W> { 25 | type Output = Result; 26 | 27 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 28 | let this = &mut *self; 29 | Pin::new(&mut this.writer).poll_write(cx, this.buf) 30 | } 31 | } 32 | /// Future for the [`write_all`](super::AsyncWriteExt::write_all) method. 33 | #[derive(Debug)] 34 | #[must_use = "futures do nothing unless you `.await` or poll them"] 35 | pub struct WriteAll<'a, W: ?Sized> { 36 | writer: &'a mut W, 37 | buf: &'a [u8], 38 | } 39 | 40 | impl Unpin for WriteAll<'_, W> {} 41 | 42 | impl<'a, W: AsyncWrite + ?Sized + Unpin> WriteAll<'a, W> { 43 | pub(super) fn new(writer: &'a mut W, buf: &'a [u8]) -> Self { 44 | WriteAll { writer, buf } 45 | } 46 | } 47 | 48 | #[derive(Debug, Eq, PartialEq, Copy, Clone)] 49 | pub enum WriteAllError { 50 | WriteZero, 51 | Other(E), 52 | } 53 | 54 | impl From for WriteAllError { 55 | fn from(err: E) -> Self { 56 | WriteAllError::Other(err) 57 | } 58 | } 59 | 60 | impl Future for WriteAll<'_, W> { 61 | type Output = Result<(), WriteAllError>; 62 | 63 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 64 | let this = &mut *self; 65 | while !this.buf.is_empty() { 66 | let n = ready!(Pin::new(&mut this.writer).poll_write(cx, this.buf))?; 67 | { 68 | let (_, rest) = mem::replace(&mut this.buf, &[]).split_at(n); 69 | this.buf = rest; 70 | } 71 | if n == 0 { 72 | return Poll::Ready(Err(WriteAllError::WriteZero)); 73 | } 74 | } 75 | 76 | Poll::Ready(Ok(())) 77 | } 78 | } 79 | /// Future for the [`flush`](super::AsyncWriteExt::flush) method. 80 | #[derive(Debug)] 81 | #[must_use = "futures do nothing unless you `.await` or poll them"] 82 | pub struct Flush<'a, W: ?Sized> { 83 | writer: &'a mut W, 84 | } 85 | 86 | impl Unpin for Flush<'_, W> {} 87 | 88 | impl<'a, W: AsyncWrite + ?Sized + Unpin> Flush<'a, W> { 89 | pub(super) fn new(writer: &'a mut W) -> Self { 90 | Flush { writer } 91 | } 92 | } 93 | 94 | impl Future for Flush<'_, W> 95 | where 96 | W: AsyncWrite + ?Sized + Unpin, 97 | { 98 | type Output = Result<(), W::Error>; 99 | 100 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 101 | Pin::new(&mut *self.writer).poll_flush(cx) 102 | } 103 | } 104 | 105 | /// Future for the [`close`](super::AsyncWriteExt::close) method. 106 | #[derive(Debug)] 107 | #[must_use = "futures do nothing unless you `.await` or poll them"] 108 | pub struct Close<'a, W: ?Sized> { 109 | writer: &'a mut W, 110 | } 111 | 112 | impl Unpin for Close<'_, W> {} 113 | 114 | impl<'a, W: AsyncWrite + ?Sized + Unpin> Close<'a, W> { 115 | pub(super) fn new(writer: &'a mut W) -> Self { 116 | Close { writer } 117 | } 118 | } 119 | 120 | impl Future for Close<'_, W> { 121 | type Output = Result<(), W::Error>; 122 | 123 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 124 | Pin::new(&mut *self.writer).poll_close(cx) 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use core::pin::Pin; 4 | use core::task::{Context, Poll}; 5 | 6 | use avr_hal_generic::hal; 7 | use avr_hal_generic::nb; 8 | 9 | mod executor; 10 | pub mod io; 11 | mod spi; 12 | pub use executor::block_on; 13 | use futures_util::future::Future; 14 | pub use spi::AsyncSpi; 15 | 16 | pub struct AsyncSerial(T); 17 | 18 | impl AsyncSerial { 19 | pub fn new(serial: T) -> Self { 20 | serial.into() 21 | } 22 | } 23 | 24 | impl From for AsyncSerial { 25 | fn from(serial: T) -> Self { 26 | AsyncSerial(serial) 27 | } 28 | } 29 | 30 | impl + Unpin> io::AsyncRead for AsyncSerial { 31 | type Error = T::Error; 32 | 33 | fn poll_read( 34 | mut self: Pin<&mut Self>, 35 | _cx: &mut Context<'_>, 36 | buf: &mut [u8], 37 | ) -> Poll> { 38 | if let Some(ptr) = buf.first_mut() { 39 | match self.0.read() { 40 | Ok(byte) => { 41 | *ptr = byte; 42 | Poll::Ready(Ok(1)) 43 | } 44 | Err(nb::Error::WouldBlock) => Poll::Pending, 45 | Err(nb::Error::Other(err)) => Poll::Ready(Err(err)), 46 | } 47 | } else { 48 | Poll::Ready(Ok(0)) 49 | } 50 | } 51 | } 52 | 53 | impl + Unpin> io::AsyncWrite for AsyncSerial { 54 | type Error = T::Error; 55 | 56 | fn poll_write( 57 | mut self: Pin<&mut Self>, 58 | _cx: &mut Context<'_>, 59 | buf: &[u8], 60 | ) -> Poll> { 61 | if let Some(byte) = buf.first() { 62 | match self.0.write(*byte) { 63 | Ok(()) => Poll::Ready(Ok(1)), 64 | Err(nb::Error::WouldBlock) => Poll::Pending, 65 | Err(nb::Error::Other(err)) => Poll::Ready(Err(err)), 66 | } 67 | } else { 68 | Poll::Ready(Ok(0)) 69 | } 70 | } 71 | 72 | fn poll_flush(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { 73 | match self.0.flush() { 74 | Ok(()) => Poll::Ready(Ok(())), 75 | Err(nb::Error::WouldBlock) => Poll::Pending, 76 | Err(nb::Error::Other(err)) => Poll::Ready(Err(err)), 77 | } 78 | } 79 | 80 | fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { 81 | Poll::Ready(Ok(())) 82 | } 83 | } 84 | 85 | pub struct Yield(bool); 86 | 87 | impl Default for Yield { 88 | fn default() -> Self { 89 | Yield(false) 90 | } 91 | } 92 | 93 | impl Future for Yield { 94 | type Output = (); 95 | 96 | fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { 97 | if self.0 { 98 | Poll::Ready(()) 99 | } else { 100 | self.0 = true; 101 | Poll::Pending 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/spi.rs: -------------------------------------------------------------------------------- 1 | use crate::io; 2 | 3 | use avr_hal_generic::hal; 4 | use avr_hal_generic::nb; 5 | use core::pin::Pin; 6 | use core::task::{Context, Poll}; 7 | 8 | pub struct AsyncSpi(T); 9 | 10 | impl AsyncSpi { 11 | pub fn new(serial: T) -> Self { 12 | serial.into() 13 | } 14 | } 15 | 16 | impl From for AsyncSpi { 17 | fn from(serial: T) -> Self { 18 | AsyncSpi(serial) 19 | } 20 | } 21 | 22 | impl + Unpin> io::AsyncRead for AsyncSpi { 23 | type Error = T::Error; 24 | 25 | fn poll_read( 26 | mut self: Pin<&mut Self>, 27 | _cx: &mut Context<'_>, 28 | buf: &mut [u8], 29 | ) -> Poll> { 30 | if let Some(ptr) = buf.first_mut() { 31 | match self.0.read() { 32 | Ok(byte) => { 33 | *ptr = byte; 34 | Poll::Ready(Ok(1)) 35 | } 36 | Err(nb::Error::WouldBlock) => Poll::Pending, 37 | Err(nb::Error::Other(err)) => Poll::Ready(Err(err)), 38 | } 39 | } else { 40 | Poll::Ready(Ok(0)) 41 | } 42 | } 43 | } 44 | 45 | impl + Unpin> io::AsyncWrite for AsyncSpi { 46 | type Error = T::Error; 47 | 48 | fn poll_write( 49 | mut self: Pin<&mut Self>, 50 | _cx: &mut Context<'_>, 51 | buf: &[u8], 52 | ) -> Poll> { 53 | if let Some(byte) = buf.first() { 54 | match self.0.send(*byte) { 55 | Ok(()) => Poll::Ready(Ok(1)), 56 | Err(nb::Error::WouldBlock) => Poll::Pending, 57 | Err(nb::Error::Other(err)) => Poll::Ready(Err(err)), 58 | } 59 | } else { 60 | Poll::Ready(Ok(0)) 61 | } 62 | } 63 | 64 | fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { 65 | Poll::Ready(Ok(())) 66 | } 67 | 68 | fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { 69 | Poll::Ready(Ok(())) 70 | } 71 | } 72 | --------------------------------------------------------------------------------