From c327c6cd6fc3c11cfaf83cf64591940d401c5f6b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 30 May 2023 22:42:49 +0200 Subject: cyw43: move crate to subdir. --- .github/workflows/rust.yml | 29 - .gitignore | 2 - .vscode/extensions.json | 11 - .vscode/settings.json | 17 - Cargo.toml | 40 - LICENSE-APACHE | 201 --- LICENSE-MIT | 25 - README.md | 57 - ci.sh | 25 - cyw43-firmware/43439A0.bin | Bin 0 -> 224190 bytes cyw43-firmware/43439A0_clm.bin | Bin 0 -> 4752 bytes .../LICENSE-permissive-binary-license-1.0.txt | 49 + cyw43-firmware/README.md | 5 + cyw43-pio/Cargo.toml | 2 +- cyw43/Cargo.toml | 40 + cyw43/README.md | 57 + cyw43/src/bus.rs | 328 ++++ cyw43/src/consts.rs | 318 ++++ cyw43/src/control.rs | 457 ++++++ cyw43/src/countries.rs | 481 ++++++ cyw43/src/events.rs | 400 +++++ cyw43/src/fmt.rs | 257 +++ cyw43/src/ioctl.rs | 126 ++ cyw43/src/lib.rs | 236 +++ cyw43/src/nvram.rs | 54 + cyw43/src/runner.rs | 575 +++++++ cyw43/src/structs.rs | 496 ++++++ examples/rpi-pico-w/Cargo.lock | 1707 ++++++++++++++++++++ examples/rpi-pico-w/Cargo.toml | 2 +- examples/rpi-pico-w/src/bin/tcp_server.rs | 25 +- examples/rpi-pico-w/src/bin/tcp_server_ap.rs | 20 +- examples/rpi-pico-w/src/bin/wifi_scan.rs | 20 +- firmware/43439A0.bin | Bin 224190 -> 0 bytes firmware/43439A0_clm.bin | Bin 4752 -> 0 bytes firmware/LICENSE-permissive-binary-license-1.0.txt | 49 - firmware/README.md | 5 - rust-toolchain.toml | 8 - rustfmt.toml | 3 - src/bus.rs | 328 ---- src/consts.rs | 318 ---- src/control.rs | 457 ------ src/countries.rs | 481 ------ src/events.rs | 400 ----- src/fmt.rs | 257 --- src/ioctl.rs | 126 -- src/lib.rs | 236 --- src/nvram.rs | 54 - src/runner.rs | 575 ------- src/structs.rs | 496 ------ 49 files changed, 5640 insertions(+), 4215 deletions(-) delete mode 100644 .github/workflows/rust.yml delete mode 100644 .gitignore delete mode 100644 .vscode/extensions.json delete mode 100644 .vscode/settings.json delete mode 100644 Cargo.toml delete mode 100644 LICENSE-APACHE delete mode 100644 LICENSE-MIT delete mode 100644 README.md delete mode 100755 ci.sh create mode 100755 cyw43-firmware/43439A0.bin create mode 100755 cyw43-firmware/43439A0_clm.bin create mode 100644 cyw43-firmware/LICENSE-permissive-binary-license-1.0.txt create mode 100644 cyw43-firmware/README.md create mode 100644 cyw43/Cargo.toml create mode 100644 cyw43/README.md create mode 100644 cyw43/src/bus.rs create mode 100644 cyw43/src/consts.rs create mode 100644 cyw43/src/control.rs create mode 100644 cyw43/src/countries.rs create mode 100644 cyw43/src/events.rs create mode 100644 cyw43/src/fmt.rs create mode 100644 cyw43/src/ioctl.rs create mode 100644 cyw43/src/lib.rs create mode 100644 cyw43/src/nvram.rs create mode 100644 cyw43/src/runner.rs create mode 100644 cyw43/src/structs.rs create mode 100644 examples/rpi-pico-w/Cargo.lock delete mode 100755 firmware/43439A0.bin delete mode 100755 firmware/43439A0_clm.bin delete mode 100644 firmware/LICENSE-permissive-binary-license-1.0.txt delete mode 100644 firmware/README.md delete mode 100644 rust-toolchain.toml delete mode 100644 rustfmt.toml delete mode 100644 src/bus.rs delete mode 100644 src/consts.rs delete mode 100644 src/control.rs delete mode 100644 src/countries.rs delete mode 100644 src/events.rs delete mode 100644 src/fmt.rs delete mode 100644 src/ioctl.rs delete mode 100644 src/lib.rs delete mode 100644 src/nvram.rs delete mode 100644 src/runner.rs delete mode 100644 src/structs.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml deleted file mode 100644 index 2cd3ba5d7..000000000 --- a/.github/workflows/rust.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Rust - -on: - push: - branches: [master] - pull_request: - branches: [master] - merge_group: - -env: - CARGO_TERM_COLOR: always - -jobs: - build-nightly: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/cache@v2 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - target - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - - - name: Check fmt - run: cargo fmt -- --check - - name: Build - run: ./ci.sh diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 1e7caa9ea..000000000 --- a/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -Cargo.lock -target/ diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index a8bb78adb..000000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. - // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp - // List of extensions which should be recommended for users of this workspace. - "recommendations": [ - "rust-lang.rust-analyzer", - "tamasfe.even-better-toml", - ], - // List of extensions recommended by VS Code that should not be recommended for users of this workspace. - "unwantedRecommendations": [] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index dd479929e..000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "editor.formatOnSave": true, - "[toml]": { - "editor.formatOnSave": false - }, - "rust-analyzer.cargo.target": "thumbv6m-none-eabi", - "rust-analyzer.cargo.noDefaultFeatures": true, - "rust-analyzer.check.allTargets": false, - "rust-analyzer.check.noDefaultFeatures": true, - "rust-analyzer.linkedProjects": [ - "examples/rpi-pico-w/Cargo.toml", - ], - "rust-analyzer.server.extraEnv": { - "WIFI_NETWORK": "foo", - "WIFI_PASSWORD": "foo", - } -} \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index 2bb2b8d93..000000000 --- a/Cargo.toml +++ /dev/null @@ -1,40 +0,0 @@ -[package] -name = "cyw43" -version = "0.1.0" -edition = "2021" - -[features] -defmt = ["dep:defmt"] -log = ["dep:log"] - -# Fetch console logs from the WiFi firmware and forward them to `log` or `defmt`. -firmware-logs = [] - -[dependencies] -embassy-time = { version = "0.1.0" } -embassy-sync = { version = "0.2.0" } -embassy-futures = { version = "0.1.0" } -embassy-net-driver-channel = { version = "0.1.0" } -atomic-polyfill = "0.1.5" - -defmt = { version = "0.3", optional = true } -log = { version = "0.4.17", optional = true } - -cortex-m = "0.7.6" -cortex-m-rt = "0.7.0" -futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } - -embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.10" } -num_enum = { version = "0.5.7", default-features = false } - -[patch.crates-io] -embassy-time = { git = "https://github.com/embassy-rs/embassy", rev = "82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" } -embassy-futures = { git = "https://github.com/embassy-rs/embassy", rev = "82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" } -embassy-sync = { git = "https://github.com/embassy-rs/embassy", rev = "82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" } -embassy-net-driver-channel = { git = "https://github.com/embassy-rs/embassy", rev = "82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" } -embassy-rp = { git = "https://github.com/embassy-rs/embassy", rev = "82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" } - -[workspace] -members = ["cyw43-pio"] -default-members = ["cyw43-pio", "."] -exclude = ["examples"] \ No newline at end of file diff --git a/LICENSE-APACHE b/LICENSE-APACHE deleted file mode 100644 index ea4fa15c9..000000000 --- a/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright 2019-2022 Embassy project contributors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/LICENSE-MIT b/LICENSE-MIT deleted file mode 100644 index 87c052836..000000000 --- a/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2019-2022 Embassy project contributors - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md deleted file mode 100644 index defea489f..000000000 --- a/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# cyw43 - -WIP driver for the CYW43439 wifi chip, used in the Raspberry Pi Pico W. Implementation based on [Infineon/wifi-host-driver](https://github.com/Infineon/wifi-host-driver). - -## Current status - -Working: - -- Station mode (joining an AP). -- AP mode (creating an AP) -- Scanning -- Sending and receiving Ethernet frames. -- Using the default MAC address. -- [`embassy-net`](https://embassy.dev) integration. -- RP2040 PIO driver for the nonstandard half-duplex SPI used in the Pico W. -- Using IRQ for device events -- GPIO support (for LED on the Pico W) - -TODO: - -- Setting a custom MAC address. -- Bus sleep (unclear what the benefit is. Is it needed for IRQs? or is it just power consumption optimization?) - -## Running the examples - -- `cargo install probe-rs-cli` -- `cd examples/rpi-pico-w` -### Example 1: Scan the wifi stations -- `cargo run --release --bin wifi_scan` -### Example 2: Create an access point (IP and credentials in the code) -- `cargo run --release --bin tcp_server_ap` -### Example 3: Connect to an existing network and create a server -- `WIFI_NETWORK=MyWifiNetwork WIFI_PASSWORD=MyWifiPassword cargo run --release` - -After a few seconds, you should see that DHCP picks up an IP address like this -``` -11.944489 DEBUG Acquired IP configuration: -11.944517 DEBUG IP address: 192.168.0.250/24 -11.944620 DEBUG Default gateway: 192.168.0.33 -11.944722 DEBUG DNS server 0: 192.168.0.33 -``` -This example implements a TCP echo server on port 1234. You can try connecting to it with: -``` -nc 192.168.0.250 1234 -``` -Send it some data, you should see it echoed back and printed in the firmware's logs. - -## License - -This work is licensed under either of - -- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - ) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) - -at your option. - diff --git a/ci.sh b/ci.sh deleted file mode 100755 index 916838200..000000000 --- a/ci.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash - -set -euxo pipefail -cd $(dirname $0) - -export CARGO_TARGET_DIR=$(pwd)/target -export DEFMT_LOG=trace - -# build examples -#================== - -(cd examples/rpi-pico-w; WIFI_NETWORK=foo WIFI_PASSWORD=bar cargo build --release) - - -# build with log/defmt combinations -#===================================== - -cargo build --target thumbv6m-none-eabi --features '' -cargo build --target thumbv6m-none-eabi --features 'log' -cargo build --target thumbv6m-none-eabi --features 'defmt' -cargo build --target thumbv6m-none-eabi --features 'log,firmware-logs' -cargo build --target thumbv6m-none-eabi --features 'defmt,firmware-logs' - -(cd cyw43-pio; cargo build --target thumbv6m-none-eabi --features '') -(cd cyw43-pio; cargo build --target thumbv6m-none-eabi --features 'overclock') diff --git a/cyw43-firmware/43439A0.bin b/cyw43-firmware/43439A0.bin new file mode 100755 index 000000000..b46b3beff Binary files /dev/null and b/cyw43-firmware/43439A0.bin differ diff --git a/cyw43-firmware/43439A0_clm.bin b/cyw43-firmware/43439A0_clm.bin new file mode 100755 index 000000000..6e3ba786b Binary files /dev/null and b/cyw43-firmware/43439A0_clm.bin differ diff --git a/cyw43-firmware/LICENSE-permissive-binary-license-1.0.txt b/cyw43-firmware/LICENSE-permissive-binary-license-1.0.txt new file mode 100644 index 000000000..cbb51f9c9 --- /dev/null +++ b/cyw43-firmware/LICENSE-permissive-binary-license-1.0.txt @@ -0,0 +1,49 @@ +Permissive Binary License + +Version 1.0, July 2019 + +Redistribution. Redistribution and use in binary form, without +modification, are permitted provided that the following conditions are +met: + +1) Redistributions must reproduce the above copyright notice and the + following disclaimer in the documentation and/or other materials + provided with the distribution. + +2) Unless to the extent explicitly permitted by law, no reverse + engineering, decompilation, or disassembly of this software is + permitted. + +3) Redistribution as part of a software development kit must include the + accompanying file named �DEPENDENCIES� and any dependencies listed in + that file. + +4) Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +Limited patent license. The copyright holders (and contributors) grant a +worldwide, non-exclusive, no-charge, royalty-free patent license to +make, have made, use, offer to sell, sell, import, and otherwise +transfer this software, where such license applies only to those patent +claims licensable by the copyright holders (and contributors) that are +necessarily infringed by this software. This patent license shall not +apply to any combinations that include this software. No hardware is +licensed hereunder. + +If you institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the software +itself infringes your patent(s), then your rights granted under this +license shall terminate as of the date such litigation is filed. + +DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS." ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/cyw43-firmware/README.md b/cyw43-firmware/README.md new file mode 100644 index 000000000..7381fdc56 --- /dev/null +++ b/cyw43-firmware/README.md @@ -0,0 +1,5 @@ +# WiFi firmware + +Firmware obtained from https://github.com/Infineon/wifi-host-driver/tree/master/WiFi_Host_Driver/resources/firmware/COMPONENT_43439 + +Licensed under the [Infineon Permissive Binary License](./LICENSE-permissive-binary-license-1.0.txt) \ No newline at end of file diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml index 2238f7617..a7af2c8e2 100644 --- a/cyw43-pio/Cargo.toml +++ b/cyw43-pio/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" overclock = [] [dependencies] -cyw43 = { path = "../" } +cyw43 = { path = "../cyw43" } embassy-rp = { version = "0.1.0", features = ["unstable-traits", "nightly", "unstable-pac", "time-driver"] } pio-proc = "0.2" pio = "0.2.1" diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml new file mode 100644 index 000000000..2bb2b8d93 --- /dev/null +++ b/cyw43/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "cyw43" +version = "0.1.0" +edition = "2021" + +[features] +defmt = ["dep:defmt"] +log = ["dep:log"] + +# Fetch console logs from the WiFi firmware and forward them to `log` or `defmt`. +firmware-logs = [] + +[dependencies] +embassy-time = { version = "0.1.0" } +embassy-sync = { version = "0.2.0" } +embassy-futures = { version = "0.1.0" } +embassy-net-driver-channel = { version = "0.1.0" } +atomic-polyfill = "0.1.5" + +defmt = { version = "0.3", optional = true } +log = { version = "0.4.17", optional = true } + +cortex-m = "0.7.6" +cortex-m-rt = "0.7.0" +futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } + +embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.10" } +num_enum = { version = "0.5.7", default-features = false } + +[patch.crates-io] +embassy-time = { git = "https://github.com/embassy-rs/embassy", rev = "82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" } +embassy-futures = { git = "https://github.com/embassy-rs/embassy", rev = "82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" } +embassy-sync = { git = "https://github.com/embassy-rs/embassy", rev = "82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" } +embassy-net-driver-channel = { git = "https://github.com/embassy-rs/embassy", rev = "82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" } +embassy-rp = { git = "https://github.com/embassy-rs/embassy", rev = "82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" } + +[workspace] +members = ["cyw43-pio"] +default-members = ["cyw43-pio", "."] +exclude = ["examples"] \ No newline at end of file diff --git a/cyw43/README.md b/cyw43/README.md new file mode 100644 index 000000000..defea489f --- /dev/null +++ b/cyw43/README.md @@ -0,0 +1,57 @@ +# cyw43 + +WIP driver for the CYW43439 wifi chip, used in the Raspberry Pi Pico W. Implementation based on [Infineon/wifi-host-driver](https://github.com/Infineon/wifi-host-driver). + +## Current status + +Working: + +- Station mode (joining an AP). +- AP mode (creating an AP) +- Scanning +- Sending and receiving Ethernet frames. +- Using the default MAC address. +- [`embassy-net`](https://embassy.dev) integration. +- RP2040 PIO driver for the nonstandard half-duplex SPI used in the Pico W. +- Using IRQ for device events +- GPIO support (for LED on the Pico W) + +TODO: + +- Setting a custom MAC address. +- Bus sleep (unclear what the benefit is. Is it needed for IRQs? or is it just power consumption optimization?) + +## Running the examples + +- `cargo install probe-rs-cli` +- `cd examples/rpi-pico-w` +### Example 1: Scan the wifi stations +- `cargo run --release --bin wifi_scan` +### Example 2: Create an access point (IP and credentials in the code) +- `cargo run --release --bin tcp_server_ap` +### Example 3: Connect to an existing network and create a server +- `WIFI_NETWORK=MyWifiNetwork WIFI_PASSWORD=MyWifiPassword cargo run --release` + +After a few seconds, you should see that DHCP picks up an IP address like this +``` +11.944489 DEBUG Acquired IP configuration: +11.944517 DEBUG IP address: 192.168.0.250/24 +11.944620 DEBUG Default gateway: 192.168.0.33 +11.944722 DEBUG DNS server 0: 192.168.0.33 +``` +This example implements a TCP echo server on port 1234. You can try connecting to it with: +``` +nc 192.168.0.250 1234 +``` +Send it some data, you should see it echoed back and printed in the firmware's logs. + +## License + +This work is licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + ) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) + +at your option. + diff --git a/cyw43/src/bus.rs b/cyw43/src/bus.rs new file mode 100644 index 000000000..e26f11120 --- /dev/null +++ b/cyw43/src/bus.rs @@ -0,0 +1,328 @@ +use embassy_futures::yield_now; +use embassy_time::{Duration, Timer}; +use embedded_hal_1::digital::OutputPin; +use futures::FutureExt; + +use crate::consts::*; +use crate::slice8_mut; + +/// Custom Spi Trait that _only_ supports the bus operation of the cyw43 +/// Implementors are expected to hold the CS pin low during an operation. +pub trait SpiBusCyw43 { + /// Issues a write command on the bus + /// First 32 bits of `word` are expected to be a cmd word + async fn cmd_write(&mut self, write: &[u32]) -> u32; + + /// Issues a read command on the bus + /// `write` is expected to be a 32 bit cmd word + /// `read` will contain the response of the device + /// Backplane reads have a response delay that produces one extra unspecified word at the beginning of `read`. + /// Callers that want to read `n` word from the backplane, have to provide a slice that is `n+1` words long. + async fn cmd_read(&mut self, write: u32, read: &mut [u32]) -> u32; + + /// Wait for events from the Device. A typical implementation would wait for the IRQ pin to be high. + /// The default implementation always reports ready, resulting in active polling of the device. + async fn wait_for_event(&mut self) { + yield_now().await; + } +} + +pub(crate) struct Bus { + backplane_window: u32, + pwr: PWR, + spi: SPI, + status: u32, +} + +impl Bus +where + PWR: OutputPin, + SPI: SpiBusCyw43, +{ + pub(crate) fn new(pwr: PWR, spi: SPI) -> Self { + Self { + backplane_window: 0xAAAA_AAAA, + pwr, + spi, + status: 0, + } + } + + pub async fn init(&mut self) { + // Reset + self.pwr.set_low().unwrap(); + Timer::after(Duration::from_millis(20)).await; + self.pwr.set_high().unwrap(); + Timer::after(Duration::from_millis(250)).await; + + while self + .read32_swapped(REG_BUS_TEST_RO) + .inspect(|v| trace!("{:#x}", v)) + .await + != FEEDBEAD + {} + + self.write32_swapped(REG_BUS_TEST_RW, TEST_PATTERN).await; + let val = self.read32_swapped(REG_BUS_TEST_RW).await; + trace!("{:#x}", val); + assert_eq!(val, TEST_PATTERN); + + let val = self.read32_swapped(REG_BUS_CTRL).await; + trace!("{:#010b}", (val & 0xff)); + + // 32-bit word length, little endian (which is the default endianess). + self.write32_swapped( + REG_BUS_CTRL, + WORD_LENGTH_32 | HIGH_SPEED | INTERRUPT_HIGH | WAKE_UP | STATUS_ENABLE | INTERRUPT_WITH_STATUS, + ) + .await; + + let val = self.read8(FUNC_BUS, REG_BUS_CTRL).await; + trace!("{:#b}", val); + + let val = self.read32(FUNC_BUS, REG_BUS_TEST_RO).await; + trace!("{:#x}", val); + assert_eq!(val, FEEDBEAD); + let val = self.read32(FUNC_BUS, REG_BUS_TEST_RW).await; + trace!("{:#x}", val); + assert_eq!(val, TEST_PATTERN); + } + + pub async fn wlan_read(&mut self, buf: &mut [u32], len_in_u8: u32) { + let cmd = cmd_word(READ, INC_ADDR, FUNC_WLAN, 0, len_in_u8); + let len_in_u32 = (len_in_u8 as usize + 3) / 4; + + self.status = self.spi.cmd_read(cmd, &mut buf[..len_in_u32]).await; + } + + pub async fn wlan_write(&mut self, buf: &[u32]) { + let cmd = cmd_word(WRITE, INC_ADDR, FUNC_WLAN, 0, buf.len() as u32 * 4); + //TODO try to remove copy? + let mut cmd_buf = [0_u32; 513]; + cmd_buf[0] = cmd; + cmd_buf[1..][..buf.len()].copy_from_slice(buf); + + self.status = self.spi.cmd_write(&cmd_buf).await; + } + + #[allow(unused)] + pub async fn bp_read(&mut self, mut addr: u32, mut data: &mut [u8]) { + // It seems the HW force-aligns the addr + // to 2 if data.len() >= 2 + // to 4 if data.len() >= 4 + // To simplify, enforce 4-align for now. + assert!(addr % 4 == 0); + + // Backplane read buffer has one extra word for the response delay. + let mut buf = [0u32; BACKPLANE_MAX_TRANSFER_SIZE / 4 + 1]; + + while !data.is_empty() { + // Ensure transfer doesn't cross a window boundary. + let window_offs = addr & BACKPLANE_ADDRESS_MASK; + let window_remaining = BACKPLANE_WINDOW_SIZE - window_offs as usize; + + let len = data.len().min(BACKPLANE_MAX_TRANSFER_SIZE).min(window_remaining); + + self.backplane_set_window(addr).await; + + let cmd = cmd_word(READ, INC_ADDR, FUNC_BACKPLANE, window_offs, len as u32); + + // round `buf` to word boundary, add one extra word for the response delay + self.status = self.spi.cmd_read(cmd, &mut buf[..(len + 3) / 4 + 1]).await; + + // when writing out the data, we skip the response-delay byte + data[..len].copy_from_slice(&slice8_mut(&mut buf[1..])[..len]); + + // Advance ptr. + addr += len as u32; + data = &mut data[len..]; + } + } + + pub async fn bp_write(&mut self, mut addr: u32, mut data: &[u8]) { + // It seems the HW force-aligns the addr + // to 2 if data.len() >= 2 + // to 4 if data.len() >= 4 + // To simplify, enforce 4-align for now. + assert!(addr % 4 == 0); + + let mut buf = [0u32; BACKPLANE_MAX_TRANSFER_SIZE / 4 + 1]; + + while !data.is_empty() { + // Ensure transfer doesn't cross a window boundary. + let window_offs = addr & BACKPLANE_ADDRESS_MASK; + let window_remaining = BACKPLANE_WINDOW_SIZE - window_offs as usize; + + let len = data.len().min(BACKPLANE_MAX_TRANSFER_SIZE).min(window_remaining); + slice8_mut(&mut buf[1..])[..len].copy_from_slice(&data[..len]); + + self.backplane_set_window(addr).await; + + let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BACKPLANE, window_offs, len as u32); + buf[0] = cmd; + + self.status = self.spi.cmd_write(&buf[..(len + 3) / 4 + 1]).await; + + // Advance ptr. + addr += len as u32; + data = &data[len..]; + } + } + + pub async fn bp_read8(&mut self, addr: u32) -> u8 { + self.backplane_readn(addr, 1).await as u8 + } + + pub async fn bp_write8(&mut self, addr: u32, val: u8) { + self.backplane_writen(addr, val as u32, 1).await + } + + pub async fn bp_read16(&mut self, addr: u32) -> u16 { + self.backplane_readn(addr, 2).await as u16 + } + + #[allow(unused)] + pub async fn bp_write16(&mut self, addr: u32, val: u16) { + self.backplane_writen(addr, val as u32, 2).await + } + + #[allow(unused)] + pub async fn bp_read32(&mut self, addr: u32) -> u32 { + self.backplane_readn(addr, 4).await + } + + pub async fn bp_write32(&mut self, addr: u32, val: u32) { + self.backplane_writen(addr, val, 4).await + } + + async fn backplane_readn(&mut self, addr: u32, len: u32) -> u32 { + self.backplane_set_window(addr).await; + + let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK; + if len == 4 { + bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG + } + self.readn(FUNC_BACKPLANE, bus_addr, len).await + } + + async fn backplane_writen(&mut self, addr: u32, val: u32, len: u32) { + self.backplane_set_window(addr).await; + + let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK; + if len == 4 { + bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG + } + self.writen(FUNC_BACKPLANE, bus_addr, val, len).await + } + + async fn backplane_set_window(&mut self, addr: u32) { + let new_window = addr & !BACKPLANE_ADDRESS_MASK; + + if (new_window >> 24) as u8 != (self.backplane_window >> 24) as u8 { + self.write8( + FUNC_BACKPLANE, + REG_BACKPLANE_BACKPLANE_ADDRESS_HIGH, + (new_window >> 24) as u8, + ) + .await; + } + if (new_window >> 16) as u8 != (self.backplane_window >> 16) as u8 { + self.write8( + FUNC_BACKPLANE, + REG_BACKPLANE_BACKPLANE_ADDRESS_MID, + (new_window >> 16) as u8, + ) + .await; + } + if (new_window >> 8) as u8 != (self.backplane_window >> 8) as u8 { + self.write8( + FUNC_BACKPLANE, + REG_BACKPLANE_BACKPLANE_ADDRESS_LOW, + (new_window >> 8) as u8, + ) + .await; + } + self.backplane_window = new_window; + } + + pub async fn read8(&mut self, func: u32, addr: u32) -> u8 { + self.readn(func, addr, 1).await as u8 + } + + pub async fn write8(&mut self, func: u32, addr: u32, val: u8) { + self.writen(func, addr, val as u32, 1).await + } + + pub async fn read16(&mut self, func: u32, addr: u32) -> u16 { + self.readn(func, addr, 2).await as u16 + } + + #[allow(unused)] + pub async fn write16(&mut self, func: u32, addr: u32, val: u16) { + self.writen(func, addr, val as u32, 2).await + } + + pub async fn read32(&mut self, func: u32, addr: u32) -> u32 { + self.readn(func, addr, 4).await + } + + #[allow(unused)] + pub async fn write32(&mut self, func: u32, addr: u32, val: u32) { + self.writen(func, addr, val, 4).await + } + + async fn readn(&mut self, func: u32, addr: u32, len: u32) -> u32 { + let cmd = cmd_word(READ, INC_ADDR, func, addr, len); + let mut buf = [0; 2]; + // if we are reading from the backplane, we need an extra word for the response delay + let len = if func == FUNC_BACKPLANE { 2 } else { 1 }; + + self.status = self.spi.cmd_read(cmd, &mut buf[..len]).await; + + // if we read from the backplane, the result is in the second word, after the response delay + if func == FUNC_BACKPLANE { + buf[1] + } else { + buf[0] + } + } + + async fn writen(&mut self, func: u32, addr: u32, val: u32, len: u32) { + let cmd = cmd_word(WRITE, INC_ADDR, func, addr, len); + + self.status = self.spi.cmd_write(&[cmd, val]).await; + } + + async fn read32_swapped(&mut self, addr: u32) -> u32 { + let cmd = cmd_word(READ, INC_ADDR, FUNC_BUS, addr, 4); + let cmd = swap16(cmd); + let mut buf = [0; 1]; + + self.status = self.spi.cmd_read(cmd, &mut buf).await; + + swap16(buf[0]) + } + + async fn write32_swapped(&mut self, addr: u32, val: u32) { + let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BUS, addr, 4); + let buf = [swap16(cmd), swap16(val)]; + + self.status = self.spi.cmd_write(&buf).await; + } + + pub async fn wait_for_event(&mut self) { + self.spi.wait_for_event().await; + } + + pub fn status(&self) -> u32 { + self.status + } +} + +fn swap16(x: u32) -> u32 { + x.rotate_left(16) +} + +fn cmd_word(write: bool, incr: bool, func: u32, addr: u32, len: u32) -> u32 { + (write as u32) << 31 | (incr as u32) << 30 | (func & 0b11) << 28 | (addr & 0x1FFFF) << 11 | (len & 0x7FF) +} diff --git a/cyw43/src/consts.rs b/cyw43/src/consts.rs new file mode 100644 index 000000000..1f6551589 --- /dev/null +++ b/cyw43/src/consts.rs @@ -0,0 +1,318 @@ +#![allow(unused)] + +pub(crate) const FUNC_BUS: u32 = 0; +pub(crate) const FUNC_BACKPLANE: u32 = 1; +pub(crate) const FUNC_WLAN: u32 = 2; +pub(crate) const FUNC_BT: u32 = 3; + +pub(crate) const REG_BUS_CTRL: u32 = 0x0; +pub(crate) const REG_BUS_INTERRUPT: u32 = 0x04; // 16 bits - Interrupt status +pub(crate) const REG_BUS_INTERRUPT_ENABLE: u32 = 0x06; // 16 bits - Interrupt mask +pub(crate) const REG_BUS_STATUS: u32 = 0x8; +pub(crate) const REG_BUS_TEST_RO: u32 = 0x14; +pub(crate) const REG_BUS_TEST_RW: u32 = 0x18; +pub(crate) const REG_BUS_RESP_DELAY: u32 = 0x1c; +pub(crate) const WORD_LENGTH_32: u32 = 0x1; +pub(crate) const HIGH_SPEED: u32 = 0x10; +pub(crate) const INTERRUPT_HIGH: u32 = 1 << 5; +pub(crate) const WAKE_UP: u32 = 1 << 7; +pub(crate) const STATUS_ENABLE: u32 = 1 << 16; +pub(crate) const INTERRUPT_WITH_STATUS: u32 = 1 << 17; + +// SPI_STATUS_REGISTER bits +pub(crate) const STATUS_DATA_NOT_AVAILABLE: u32 = 0x00000001; +pub(crate) const STATUS_UNDERFLOW: u32 = 0x00000002; +pub(crate) const STATUS_OVERFLOW: u32 = 0x00000004; +pub(crate) const STATUS_F2_INTR: u32 = 0x00000008; +pub(crate) const STATUS_F3_INTR: u32 = 0x00000010; +pub(crate) const STATUS_F2_RX_READY: u32 = 0x00000020; +pub(crate) const STATUS_F3_RX_READY: u32 = 0x00000040; +pub(crate) const STATUS_HOST_CMD_DATA_ERR: u32 = 0x00000080; +pub(crate) const STATUS_F2_PKT_AVAILABLE: u32 = 0x00000100; +pub(crate) const STATUS_F2_PKT_LEN_MASK: u32 = 0x000FFE00; +pub(crate) const STATUS_F2_PKT_LEN_SHIFT: u32 = 9; +pub(crate) const STATUS_F3_PKT_AVAILABLE: u32 = 0x00100000; +pub(crate) const STATUS_F3_PKT_LEN_MASK: u32 = 0xFFE00000; +pub(crate) const STATUS_F3_PKT_LEN_SHIFT: u32 = 21; + +pub(crate) const REG_BACKPLANE_GPIO_SELECT: u32 = 0x10005; +pub(crate) const REG_BACKPLANE_GPIO_OUTPUT: u32 = 0x10006; +pub(crate) const REG_BACKPLANE_GPIO_ENABLE: u32 = 0x10007; +pub(crate) const REG_BACKPLANE_FUNCTION2_WATERMARK: u32 = 0x10008; +pub(crate) const REG_BACKPLANE_DEVICE_CONTROL: u32 = 0x10009; +pub(crate) const REG_BACKPLANE_BACKPLANE_ADDRESS_LOW: u32 = 0x1000A; +pub(crate) const REG_BACKPLANE_BACKPLANE_ADDRESS_MID: u32 = 0x1000B; +pub(crate) const REG_BACKPLANE_BACKPLANE_ADDRESS_HIGH: u32 = 0x1000C; +pub(crate) const REG_BACKPLANE_FRAME_CONTROL: u32 = 0x1000D; +pub(crate) const REG_BACKPLANE_CHIP_CLOCK_CSR: u32 = 0x1000E; +pub(crate) const REG_BACKPLANE_PULL_UP: u32 = 0x1000F; +pub(crate) const REG_BACKPLANE_READ_FRAME_BC_LOW: u32 = 0x1001B; +pub(crate) const REG_BACKPLANE_READ_FRAME_BC_HIGH: u32 = 0x1001C; +pub(crate) const REG_BACKPLANE_WAKEUP_CTRL: u32 = 0x1001E; +pub(crate) const REG_BACKPLANE_SLEEP_CSR: u32 = 0x1001F; + +pub(crate) const BACKPLANE_WINDOW_SIZE: usize = 0x8000; +pub(crate) const BACKPLANE_ADDRESS_MASK: u32 = 0x7FFF; +pub(crate) const BACKPLANE_ADDRESS_32BIT_FLAG: u32 = 0x08000; +pub(crate) const BACKPLANE_MAX_TRANSFER_SIZE: usize = 64; +// Active Low Power (ALP) clock constants +pub(crate) const BACKPLANE_ALP_AVAIL_REQ: u8 = 0x08; +pub(crate) const BACKPLANE_ALP_AVAIL: u8 = 0x40; + +// Broadcom AMBA (Advanced Microcontroller Bus Architecture) Interconnect +// (AI) pub (crate) constants +pub(crate) const AI_IOCTRL_OFFSET: u32 = 0x408; +pub(crate) const AI_IOCTRL_BIT_FGC: u8 = 0x0002; +pub(crate) const AI_IOCTRL_BIT_CLOCK_EN: u8 = 0x0001; +pub(crate) const AI_IOCTRL_BIT_CPUHALT: u8 = 0x0020; + +pub(crate) const AI_RESETCTRL_OFFSET: u32 = 0x800; +pub(crate) const AI_RESETCTRL_BIT_RESET: u8 = 1; + +pub(crate) const AI_RESETSTATUS_OFFSET: u32 = 0x804; + +pub(crate) const TEST_PATTERN: u32 = 0x12345678; +pub(crate) const FEEDBEAD: u32 = 0xFEEDBEAD; + +// SPI_INTERRUPT_REGISTER and SPI_INTERRUPT_ENABLE_REGISTER Bits +pub(crate) const IRQ_DATA_UNAVAILABLE: u16 = 0x0001; // Requested data not available; Clear by writing a "1" +pub(crate) const IRQ_F2_F3_FIFO_RD_UNDERFLOW: u16 = 0x0002; +pub(crate) const IRQ_F2_F3_FIFO_WR_OVERFLOW: u16 = 0x0004; +pub(crate) const IRQ_COMMAND_ERROR: u16 = 0x0008; // Cleared by writing 1 +pub(crate) const IRQ_DATA_ERROR: u16 = 0x0010; // Cleared by writing 1 +pub(crate) const IRQ_F2_PACKET_AVAILABLE: u16 = 0x0020; +pub(crate) const IRQ_F3_PACKET_AVAILABLE: u16 = 0x0040; +pub(crate) const IRQ_F1_OVERFLOW: u16 = 0x0080; // Due to last write. Bkplane has pending write requests +pub(crate) const IRQ_MISC_INTR0: u16 = 0x0100; +pub(crate) const IRQ_MISC_INTR1: u16 = 0x0200; +pub(crate) const IRQ_MISC_INTR2: u16 = 0x0400; +pub(crate) const IRQ_MISC_INTR3: u16 = 0x0800; +pub(crate) const IRQ_MISC_INTR4: u16 = 0x1000; +pub(crate) const IRQ_F1_INTR: u16 = 0x2000; +pub(crate) const IRQ_F2_INTR: u16 = 0x4000; +pub(crate) const IRQ_F3_INTR: u16 = 0x8000; + +pub(crate) const IOCTL_CMD_UP: u32 = 2; +pub(crate) const IOCTL_CMD_DOWN: u32 = 3; +pub(crate) const IOCTL_CMD_SET_SSID: u32 = 26; +pub(crate) const IOCTL_CMD_SET_CHANNEL: u32 = 30; +pub(crate) const IOCTL_CMD_ANTDIV: u32 = 64; +pub(crate) const IOCTL_CMD_SET_AP: u32 = 118; +pub(crate) const IOCTL_CMD_SET_VAR: u32 = 263; +pub(crate) const IOCTL_CMD_GET_VAR: u32 = 262; +pub(crate) const IOCTL_CMD_SET_PASSPHRASE: u32 = 268; + +pub(crate) const CHANNEL_TYPE_CONTROL: u8 = 0; +pub(crate) const CHANNEL_TYPE_EVENT: u8 = 1; +pub(crate) const CHANNEL_TYPE_DATA: u8 = 2; + +// CYW_SPID command structure constants. +pub(crate) const WRITE: bool = true; +pub(crate) const READ: bool = false; +pub(crate) const INC_ADDR: bool = true; +pub(crate) const FIXED_ADDR: bool = false; + +pub(crate) const AES_ENABLED: u32 = 0x0004; +pub(crate) const WPA2_SECURITY: u32 = 0x00400000; + +pub(crate) const MIN_PSK_LEN: usize = 8; +pub(crate) const MAX_PSK_LEN: usize = 64; + +// Security type (authentication and encryption types are combined using bit mask) +#[allow(non_camel_case_types)] +#[derive(Copy, Clone, PartialEq)] +#[repr(u32)] +pub(crate) enum Security { + OPEN = 0, + WPA2_AES_PSK = WPA2_SECURITY | AES_ENABLED, +} + +#[allow(non_camel_case_types)] +#[derive(Copy, Clone)] +#[repr(u8)] +pub enum EStatus { + /// operation was successful + SUCCESS = 0, + /// operation failed + FAIL = 1, + /// operation timed out + TIMEOUT = 2, + /// failed due to no matching network found + NO_NETWORKS = 3, + /// operation was aborted + ABORT = 4, + /// protocol failure: packet not ack'd + NO_ACK = 5, + /// AUTH or ASSOC packet was unsolicited + UNSOLICITED = 6, + /// attempt to assoc to an auto auth configuration + ATTEMPT = 7, + /// scan results are incomplete + PARTIAL = 8, + /// scan aborted by another scan + NEWSCAN = 9, + /// scan aborted due to assoc in progress + NEWASSOC = 10, + /// 802.11h quiet period started + _11HQUIET = 11, + /// user disabled scanning (WLC_SET_SCANSUPPRESS) + SUPPRESS = 12, + /// no allowable channels to scan + NOCHANS = 13, + /// scan aborted due to CCX fast roam + CCXFASTRM = 14, + /// abort channel select + CS_ABORT = 15, +} + +impl PartialEq for u32 { + fn eq(&self, other: &EStatus) -> bool { + *self == *other as Self + } +} + +#[allow(dead_code)] +pub(crate) struct FormatStatus(pub u32); + +#[cfg(feature = "defmt")] +impl defmt::Format for FormatStatus { + fn format(&self, fmt: defmt::Formatter) { + macro_rules! implm { + ($($name:ident),*) => { + $( + if self.0 & $name > 0 { + defmt::write!(fmt, " | {}", &stringify!($name)[7..]); + } + )* + }; + } + + implm!( + STATUS_DATA_NOT_AVAILABLE, + STATUS_UNDERFLOW, + STATUS_OVERFLOW, + STATUS_F2_INTR, + STATUS_F3_INTR, + STATUS_F2_RX_READY, + STATUS_F3_RX_READY, + STATUS_HOST_CMD_DATA_ERR, + STATUS_F2_PKT_AVAILABLE, + STATUS_F3_PKT_AVAILABLE + ); + } +} + +#[cfg(feature = "log")] +impl core::fmt::Debug for FormatStatus { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + macro_rules! implm { + ($($name:ident),*) => { + $( + if self.0 & $name > 0 { + core::write!(fmt, " | {}", &stringify!($name)[7..])?; + } + )* + }; + } + + implm!( + STATUS_DATA_NOT_AVAILABLE, + STATUS_UNDERFLOW, + STATUS_OVERFLOW, + STATUS_F2_INTR, + STATUS_F3_INTR, + STATUS_F2_RX_READY, + STATUS_F3_RX_READY, + STATUS_HOST_CMD_DATA_ERR, + STATUS_F2_PKT_AVAILABLE, + STATUS_F3_PKT_AVAILABLE + ); + Ok(()) + } +} + +#[cfg(feature = "log")] +impl core::fmt::Display for FormatStatus { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::Debug::fmt(self, f) + } +} + +#[allow(dead_code)] +pub(crate) struct FormatInterrupt(pub u16); + +#[cfg(feature = "defmt")] +impl defmt::Format for FormatInterrupt { + fn format(&self, fmt: defmt::Formatter) { + macro_rules! implm { + ($($name:ident),*) => { + $( + if self.0 & $name > 0 { + defmt::write!(fmt, " | {}", &stringify!($name)[4..]); + } + )* + }; + } + + implm!( + IRQ_DATA_UNAVAILABLE, + IRQ_F2_F3_FIFO_RD_UNDERFLOW, + IRQ_F2_F3_FIFO_WR_OVERFLOW, + IRQ_COMMAND_ERROR, + IRQ_DATA_ERROR, + IRQ_F2_PACKET_AVAILABLE, + IRQ_F3_PACKET_AVAILABLE, + IRQ_F1_OVERFLOW, + IRQ_MISC_INTR0, + IRQ_MISC_INTR1, + IRQ_MISC_INTR2, + IRQ_MISC_INTR3, + IRQ_MISC_INTR4, + IRQ_F1_INTR, + IRQ_F2_INTR, + IRQ_F3_INTR + ); + } +} + +#[cfg(feature = "log")] +impl core::fmt::Debug for FormatInterrupt { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + macro_rules! implm { + ($($name:ident),*) => { + $( + if self.0 & $name > 0 { + core::write!(fmt, " | {}", &stringify!($name)[7..])?; + } + )* + }; + } + + implm!( + IRQ_DATA_UNAVAILABLE, + IRQ_F2_F3_FIFO_RD_UNDERFLOW, + IRQ_F2_F3_FIFO_WR_OVERFLOW, + IRQ_COMMAND_ERROR, + IRQ_DATA_ERROR, + IRQ_F2_PACKET_AVAILABLE, + IRQ_F3_PACKET_AVAILABLE, + IRQ_F1_OVERFLOW, + IRQ_MISC_INTR0, + IRQ_MISC_INTR1, + IRQ_MISC_INTR2, + IRQ_MISC_INTR3, + IRQ_MISC_INTR4, + IRQ_F1_INTR, + IRQ_F2_INTR, + IRQ_F3_INTR + ); + Ok(()) + } +} + +#[cfg(feature = "log")] +impl core::fmt::Display for FormatInterrupt { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::Debug::fmt(self, f) + } +} diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs new file mode 100644 index 000000000..6919d569e --- /dev/null +++ b/cyw43/src/control.rs @@ -0,0 +1,457 @@ +use core::cmp::{max, min}; + +use ch::driver::LinkState; +use embassy_net_driver_channel as ch; +use embassy_time::{Duration, Timer}; + +pub use crate::bus::SpiBusCyw43; +use crate::consts::*; +use crate::events::{Event, EventSubscriber, Events}; +use crate::fmt::Bytes; +use crate::ioctl::{IoctlState, IoctlType}; +use crate::structs::*; +use crate::{countries, events, PowerManagementMode}; + +#[derive(Debug)] +pub struct Error { + pub status: u32, +} + +pub struct Control<'a> { + state_ch: ch::StateRunner<'a>, + events: &'a Events, + ioctl_state: &'a IoctlState, +} + +impl<'a> Control<'a> { + pub(crate) fn new(state_ch: ch::StateRunner<'a>, event_sub: &'a Events, ioctl_state: &'a IoctlState) -> Self { + Self { + state_ch, + events: event_sub, + ioctl_state, + } + } + + pub async fn init(&mut self, clm: &[u8]) { + const CHUNK_SIZE: usize = 1024; + + debug!("Downloading CLM..."); + + let mut offs = 0; + for chunk in clm.chunks(CHUNK_SIZE) { + let mut flag = DOWNLOAD_FLAG_HANDLER_VER; + if offs == 0 { + flag |= DOWNLOAD_FLAG_BEGIN; + } + offs += chunk.len(); + if offs == clm.len() { + flag |= DOWNLOAD_FLAG_END; + } + + let header = DownloadHeader { + flag, + dload_type: DOWNLOAD_TYPE_CLM, + len: chunk.len() as _, + crc: 0, + }; + let mut buf = [0; 8 + 12 + CHUNK_SIZE]; + buf[0..8].copy_from_slice(b"clmload\x00"); + buf[8..20].copy_from_slice(&header.to_bytes()); + buf[20..][..chunk.len()].copy_from_slice(&chunk); + self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..8 + 12 + chunk.len()]) + .await; + } + + // check clmload ok + assert_eq!(self.get_iovar_u32("clmload_status").await, 0); + + debug!("Configuring misc stuff..."); + + // Disable tx gloming which transfers multiple packets in one request. + // 'glom' is short for "conglomerate" which means "gather together into + // a compact mass". + self.set_iovar_u32("bus:txglom", 0).await; + self.set_iovar_u32("apsta", 1).await; + + // read MAC addr. + let mut mac_addr = [0; 6]; + assert_eq!(self.get_iovar("cur_etheraddr", &mut mac_addr).await, 6); + debug!("mac addr: {:02x}", Bytes(&mac_addr)); + + let country = countries::WORLD_WIDE_XX; + let country_info = CountryInfo { + country_abbrev: [country.code[0], country.code[1], 0, 0], + country_code: [country.code[0], country.code[1], 0, 0], + rev: if country.rev == 0 { -1 } else { country.rev as _ }, + }; + self.set_iovar("country", &country_info.to_bytes()).await; + + // set country takes some time, next ioctls fail if we don't wait. + Timer::after(Duration::from_millis(100)).await; + + // Set antenna to chip antenna + self.ioctl_set_u32(IOCTL_CMD_ANTDIV, 0, 0).await; + + self.set_iovar_u32("bus:txglom", 0).await; + Timer::after(Duration::from_millis(100)).await; + //self.set_iovar_u32("apsta", 1).await; // this crashes, also we already did it before...?? + //Timer::after(Duration::from_millis(100)).await; + self.set_iovar_u32("ampdu_ba_wsize", 8).await; + Timer::after(Duration::from_millis(100)).await; + self.set_iovar_u32("ampdu_mpdu", 4).await; + Timer::after(Duration::from_millis(100)).await; + //self.set_iovar_u32("ampdu_rx_factor", 0).await; // this crashes + + //Timer::after(Duration::from_millis(100)).await; + + // evts + let mut evts = EventMask { + iface: 0, + events: [0xFF; 24], + }; + + // Disable spammy uninteresting events. + evts.unset(Event::RADIO); + evts.unset(Event::IF); + evts.unset(Event::PROBREQ_MSG); + evts.unset(Event::PROBREQ_MSG_RX); + evts.unset(Event::PROBRESP_MSG); + evts.unset(Event::PROBRESP_MSG); + evts.unset(Event::ROAM); + + self.set_iovar("bsscfg:event_msgs", &evts.to_bytes()).await; + + Timer::after(Duration::from_millis(100)).await; + + // set wifi up + self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await; + + Timer::after(Duration::from_millis(100)).await; + + self.ioctl_set_u32(110, 0, 1).await; // SET_GMODE = auto + self.ioctl_set_u32(142, 0, 0).await; // SET_BAND = any + + Timer::after(Duration::from_millis(100)).await; + + self.state_ch.set_ethernet_address(mac_addr); + + debug!("INIT DONE"); + } + + pub async fn set_power_management(&mut self, mode: PowerManagementMode) { + // power save mode + let mode_num = mode.mode(); + if mode_num == 2 { + self.set_iovar_u32("pm2_sleep_ret", mode.sleep_ret_ms() as u32).await; + self.set_iovar_u32("bcn_li_bcn", mode.beacon_period() as u32).await; + self.set_iovar_u32("bcn_li_dtim", mode.dtim_period() as u32).await; + self.set_iovar_u32("assoc_listen", mode.assoc() as u32).await; + } + self.ioctl_set_u32(86, 0, mode_num).await; + } + + pub async fn join_open(&mut self, ssid: &str) -> Result<(), Error> { + self.set_iovar_u32("ampdu_ba_wsize", 8).await; + + self.ioctl_set_u32(134, 0, 0).await; // wsec = open + self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 0).await; + self.ioctl_set_u32(20, 0, 1).await; // set_infra = 1 + self.ioctl_set_u32(22, 0, 0).await; // set_auth = open (0) + + let mut i = SsidInfo { + len: ssid.len() as _, + ssid: [0; 32], + }; + i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes()); + + self.wait_for_join(i).await + } + + pub async fn join_wpa2(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { + self.set_iovar_u32("ampdu_ba_wsize", 8).await; + + self.ioctl_set_u32(134, 0, 4).await; // wsec = wpa2 + self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 1).await; + self.set_iovar_u32x2("bsscfg:sup_wpa2_eapver", 0, 0xFFFF_FFFF).await; + self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).await; + + Timer::after(Duration::from_millis(100)).await; + + let mut pfi = PassphraseInfo { + len: passphrase.len() as _, + flags: 1, + passphrase: [0; 64], + }; + pfi.passphrase[..passphrase.len()].copy_from_slice(passphrase.as_bytes()); + self.ioctl(IoctlType::Set, IOCTL_CMD_SET_PASSPHRASE, 0, &mut pfi.to_bytes()) + .await; // WLC_SET_WSEC_PMK + + self.ioctl_set_u32(20, 0, 1).await; // set_infra = 1 + self.ioctl_set_u32(22, 0, 0).await; // set_auth = 0 (open) + self.ioctl_set_u32(165, 0, 0x80).await; // set_wpa_auth + + let mut i = SsidInfo { + len: ssid.len() as _, + ssid: [0; 32], + }; + i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes()); + + self.wait_for_join(i).await + } + + async fn wait_for_join(&mut self, i: SsidInfo) -> Result<(), Error> { + self.events.mask.enable(&[Event::SET_SSID, Event::AUTH]); + let mut subscriber = self.events.queue.subscriber().unwrap(); + // the actual join operation starts here + // we make sure to enable events before so we don't miss any + + // set_ssid + self.ioctl(IoctlType::Set, IOCTL_CMD_SET_SSID, 0, &mut i.to_bytes()) + .await; + + // to complete the join, we wait for a SET_SSID event + // we also save the AUTH status for the user, it may be interesting + let mut auth_status = 0; + let status = loop { + let msg = subscriber.next_message_pure().await; + if msg.header.event_type == Event::AUTH && msg.header.status != EStatus::SUCCESS { + auth_status = msg.header.status; + } else if msg.header.event_type == Event::SET_SSID { + // join operation ends with SET_SSID event + break msg.header.status; + } + }; + + self.events.mask.disable_all(); + if status == EStatus::SUCCESS { + // successful join + self.state_ch.set_link_state(LinkState::Up); + debug!("JOINED"); + Ok(()) + } else { + warn!("JOIN failed with status={} auth={}", status, auth_status); + Err(Error { status }) + } + } + + pub async fn gpio_set(&mut self, gpio_n: u8, gpio_en: bool) { + assert!(gpio_n < 3); + self.set_iovar_u32x2("gpioout", 1 << gpio_n, if gpio_en { 1 << gpio_n } else { 0 }) + .await + } + + pub async fn start_ap_open(&mut self, ssid: &str, channel: u8) { + self.start_ap(ssid, "", Security::OPEN, channel).await; + } + + pub async fn start_ap_wpa2(&mut self, ssid: &str, passphrase: &str, channel: u8) { + self.start_ap(ssid, passphrase, Security::WPA2_AES_PSK, channel).await; + } + + async fn start_ap(&mut self, ssid: &str, passphrase: &str, security: Security, channel: u8) { + if security != Security::OPEN + && (passphrase.as_bytes().len() < MIN_PSK_LEN || passphrase.as_bytes().len() > MAX_PSK_LEN) + { + panic!("Passphrase is too short or too long"); + } + + // Temporarily set wifi down + self.ioctl(IoctlType::Set, IOCTL_CMD_DOWN, 0, &mut []).await; + + // Turn off APSTA mode + self.set_iovar_u32("apsta", 0).await; + + // Set wifi up again + self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await; + + // Turn on AP mode + self.ioctl_set_u32(IOCTL_CMD_SET_AP, 0, 1).await; + + // Set SSID + let mut i = SsidInfoWithIndex { + index: 0, + ssid_info: SsidInfo { + len: ssid.as_bytes().len() as _, + ssid: [0; 32], + }, + }; + i.ssid_info.ssid[..ssid.as_bytes().len()].copy_from_slice(ssid.as_bytes()); + self.set_iovar("bsscfg:ssid", &i.to_bytes()).await; + + // Set channel number + self.ioctl_set_u32(IOCTL_CMD_SET_CHANNEL, 0, channel as u32).await; + + // Set security + self.set_iovar_u32x2("bsscfg:wsec", 0, (security as u32) & 0xFF).await; + + if security != Security::OPEN { + self.set_iovar_u32x2("bsscfg:wpa_auth", 0, 0x0084).await; // wpa_auth = WPA2_AUTH_PSK | WPA_AUTH_PSK + + Timer::after(Duration::from_millis(100)).await; + + // Set passphrase + let mut pfi = PassphraseInfo { + len: passphrase.as_bytes().len() as _, + flags: 1, // WSEC_PASSPHRASE + passphrase: [0; 64], + }; + pfi.passphrase[..passphrase.as_bytes().len()].copy_from_slice(passphrase.as_bytes()); + self.ioctl(IoctlType::Set, IOCTL_CMD_SET_PASSPHRASE, 0, &mut pfi.to_bytes()) + .await; + } + + // Change mutlicast rate from 1 Mbps to 11 Mbps + self.set_iovar_u32("2g_mrate", 11000000 / 500000).await; + + // Start AP + self.set_iovar_u32x2("bss", 0, 1).await; // bss = BSS_UP + } + + async fn set_iovar_u32x2(&mut self, name: &str, val1: u32, val2: u32) { + let mut buf = [0; 8]; + buf[0..4].copy_from_slice(&val1.to_le_bytes()); + buf[4..8].copy_from_slice(&val2.to_le_bytes()); + self.set_iovar(name, &buf).await + } + + async fn set_iovar_u32(&mut self, name: &str, val: u32) { + self.set_iovar(name, &val.to_le_bytes()).await + } + + async fn get_iovar_u32(&mut self, name: &str) -> u32 { + let mut buf = [0; 4]; + let len = self.get_iovar(name, &mut buf).await; + assert_eq!(len, 4); + u32::from_le_bytes(buf) + } + + async fn set_iovar(&mut self, name: &str, val: &[u8]) { + self.set_iovar_v::<64>(name, val).await + } + + async fn set_iovar_v(&mut self, name: &str, val: &[u8]) { + debug!("set {} = {:02x}", name, Bytes(val)); + + let mut buf = [0; BUFSIZE]; + buf[..name.len()].copy_from_slice(name.as_bytes()); + buf[name.len()] = 0; + buf[name.len() + 1..][..val.len()].copy_from_slice(val); + + let total_len = name.len() + 1 + val.len(); + self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..total_len]) + .await; + } + + // TODO this is not really working, it always returns all zeros. + async fn get_iovar(&mut self, name: &str, res: &mut [u8]) -> usize { + debug!("get {}", name); + + let mut buf = [0; 64]; + buf[..name.len()].copy_from_slice(name.as_bytes()); + buf[name.len()] = 0; + + let total_len = max(name.len() + 1, res.len()); + let res_len = self + .ioctl(IoctlType::Get, IOCTL_CMD_GET_VAR, 0, &mut buf[..total_len]) + .await; + + let out_len = min(res.len(), res_len); + res[..out_len].copy_from_slice(&buf[..out_len]); + out_len + } + + async fn ioctl_set_u32(&mut self, cmd: u32, iface: u32, val: u32) { + let mut buf = val.to_le_bytes(); + self.ioctl(IoctlType::Set, cmd, iface, &mut buf).await; + } + + async fn ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize { + struct CancelOnDrop<'a>(&'a IoctlState); + + impl CancelOnDrop<'_> { + fn defuse(self) { + core::mem::forget(self); + } + } + + impl Drop for CancelOnDrop<'_> { + fn drop(&mut self) { + self.0.cancel_ioctl(); + } + } + + let ioctl = CancelOnDrop(self.ioctl_state); + + ioctl.0.do_ioctl(kind, cmd, iface, buf).await; + let resp_len = ioctl.0.wait_complete().await; + + ioctl.defuse(); + + resp_len + } + + /// Start a wifi scan + /// + /// Returns a `Stream` of networks found by the device + /// + /// # Note + /// Device events are currently implemented using a bounded queue. + /// To not miss any events, you should make sure to always await the stream. + pub async fn scan(&mut self) -> Scanner<'_> { + const SCANTYPE_PASSIVE: u8 = 1; + + let scan_params = ScanParams { + version: 1, + action: 1, + sync_id: 1, + ssid_len: 0, + ssid: [0; 32], + bssid: [0xff; 6], + bss_type: 2, + scan_type: SCANTYPE_PASSIVE, + nprobes: !0, + active_time: !0, + passive_time: !0, + home_time: !0, + channel_num: 0, + channel_list: [0; 1], + }; + + self.events.mask.enable(&[Event::ESCAN_RESULT]); + let subscriber = self.events.queue.subscriber().unwrap(); + self.set_iovar_v::<256>("escan", &scan_params.to_bytes()).await; + + Scanner { + subscriber, + events: &self.events, + } + } +} + +pub struct Scanner<'a> { + subscriber: EventSubscriber<'a>, + events: &'a Events, +} + +impl Scanner<'_> { + /// wait for the next found network + pub async fn next(&mut self) -> Option { + let event = self.subscriber.next_message_pure().await; + if event.header.status != EStatus::PARTIAL { + self.events.mask.disable_all(); + return None; + } + + if let events::Payload::BssInfo(bss) = event.payload { + Some(bss) + } else { + None + } + } +} + +impl Drop for Scanner<'_> { + fn drop(&mut self) { + self.events.mask.disable_all(); + } +} diff --git a/cyw43/src/countries.rs b/cyw43/src/countries.rs new file mode 100644 index 000000000..fa1e8cace --- /dev/null +++ b/cyw43/src/countries.rs @@ -0,0 +1,481 @@ +#![allow(unused)] + +pub struct Country { + pub code: [u8; 2], + pub rev: u16, +} + +/// AF Afghanistan +pub const AFGHANISTAN: Country = Country { code: *b"AF", rev: 0 }; +/// AL Albania +pub const ALBANIA: Country = Country { code: *b"AL", rev: 0 }; +/// DZ Algeria +pub const ALGERIA: Country = Country { code: *b"DZ", rev: 0 }; +/// AS American_Samoa +pub const AMERICAN_SAMOA: Country = Country { code: *b"AS", rev: 0 }; +/// AO Angola +pub const ANGOLA: Country = Country { code: *b"AO", rev: 0 }; +/// AI Anguilla +pub const ANGUILLA: Country = Country { code: *b"AI", rev: 0 }; +/// AG Antigua_and_Barbuda +pub const ANTIGUA_AND_BARBUDA: Country = Country { code: *b"AG", rev: 0 }; +/// AR Argentina +pub const ARGENTINA: Country = Country { code: *b"AR", rev: 0 }; +/// AM Armenia +pub const ARMENIA: Country = Country { code: *b"AM", rev: 0 }; +/// AW Aruba +pub const ARUBA: Country = Country { code: *b"AW", rev: 0 }; +/// AU Australia +pub const AUSTRALIA: Country = Country { code: *b"AU", rev: 0 }; +/// AT Austria +pub const AUSTRIA: Country = Country { code: *b"AT", rev: 0 }; +/// AZ Azerbaijan +pub const AZERBAIJAN: Country = Country { code: *b"AZ", rev: 0 }; +/// BS Bahamas +pub const BAHAMAS: Country = Country { code: *b"BS", rev: 0 }; +/// BH Bahrain +pub const BAHRAIN: Country = Country { code: *b"BH", rev: 0 }; +/// 0B Baker_Island +pub const BAKER_ISLAND: Country = Country { code: *b"0B", rev: 0 }; +/// BD Bangladesh +pub const BANGLADESH: Country = Country { code: *b"BD", rev: 0 }; +/// BB Barbados +pub const BARBADOS: Country = Country { code: *b"BB", rev: 0 }; +/// BY Belarus +pub const BELARUS: Country = Country { code: *b"BY", rev: 0 }; +/// BE Belgium +pub const BELGIUM: Country = Country { code: *b"BE", rev: 0 }; +/// BZ Belize +pub const BELIZE: Country = Country { code: *b"BZ", rev: 0 }; +/// BJ Benin +pub const BENIN: Country = Country { code: *b"BJ", rev: 0 }; +/// BM Bermuda +pub const BERMUDA: Country = Country { code: *b"BM", rev: 0 }; +/// BT Bhutan +pub const BHUTAN: Country = Country { code: *b"BT", rev: 0 }; +/// BO Bolivia +pub const BOLIVIA: Country = Country { code: *b"BO", rev: 0 }; +/// BA Bosnia_and_Herzegovina +pub const BOSNIA_AND_HERZEGOVINA: Country = Country { code: *b"BA", rev: 0 }; +/// BW Botswana +pub const BOTSWANA: Country = Country { code: *b"BW", rev: 0 }; +/// BR Brazil +pub const BRAZIL: Country = Country { code: *b"BR", rev: 0 }; +/// IO British_Indian_Ocean_Territory +pub const BRITISH_INDIAN_OCEAN_TERRITORY: Country = Country { code: *b"IO", rev: 0 }; +/// BN Brunei_Darussalam +pub const BRUNEI_DARUSSALAM: Country = Country { code: *b"BN", rev: 0 }; +/// BG Bulgaria +pub const BULGARIA: Country = Country { code: *b"BG", rev: 0 }; +/// BF Burkina_Faso +pub const BURKINA_FASO: Country = Country { code: *b"BF", rev: 0 }; +/// BI Burundi +pub const BURUNDI: Country = Country { code: *b"BI", rev: 0 }; +/// KH Cambodia +pub const CAMBODIA: Country = Country { code: *b"KH", rev: 0 }; +/// CM Cameroon +pub const CAMEROON: Country = Country { code: *b"CM", rev: 0 }; +/// CA Canada +pub const CANADA: Country = Country { code: *b"CA", rev: 0 }; +/// CA Canada Revision 950 +pub const CANADA_REV950: Country = Country { code: *b"CA", rev: 950 }; +/// CV Cape_Verde +pub const CAPE_VERDE: Country = Country { code: *b"CV", rev: 0 }; +/// KY Cayman_Islands +pub const CAYMAN_ISLANDS: Country = Country { code: *b"KY", rev: 0 }; +/// CF Central_African_Republic +pub const CENTRAL_AFRICAN_REPUBLIC: Country = Country { code: *b"CF", rev: 0 }; +/// TD Chad +pub const CHAD: Country = Country { code: *b"TD", rev: 0 }; +/// CL Chile +pub const CHILE: Country = Country { code: *b"CL", rev: 0 }; +/// CN China +pub const CHINA: Country = Country { code: *b"CN", rev: 0 }; +/// CX Christmas_Island +pub const CHRISTMAS_ISLAND: Country = Country { code: *b"CX", rev: 0 }; +/// CO Colombia +pub const COLOMBIA: Country = Country { code: *b"CO", rev: 0 }; +/// KM Comoros +pub const COMOROS: Country = Country { code: *b"KM", rev: 0 }; +/// CG Congo +pub const CONGO: Country = Country { code: *b"CG", rev: 0 }; +/// CD Congo,_The_Democratic_Republic_Of_The +pub const CONGO_THE_DEMOCRATIC_REPUBLIC_OF_THE: Country = Country { code: *b"CD", rev: 0 }; +/// CR Costa_Rica +pub const COSTA_RICA: Country = Country { code: *b"CR", rev: 0 }; +/// CI Cote_D'ivoire +pub const COTE_DIVOIRE: Country = Country { code: *b"CI", rev: 0 }; +/// HR Croatia +pub const CROATIA: Country = Country { code: *b"HR", rev: 0 }; +/// CU Cuba +pub const CUBA: Country = Country { code: *b"CU", rev: 0 }; +/// CY Cyprus +pub const CYPRUS: Country = Country { code: *b"CY", rev: 0 }; +/// CZ Czech_Republic +pub const CZECH_REPUBLIC: Country = Country { code: *b"CZ", rev: 0 }; +/// DK Denmark +pub const DENMARK: Country = Country { code: *b"DK", rev: 0 }; +/// DJ Djibouti +pub const DJIBOUTI: Country = Country { code: *b"DJ", rev: 0 }; +/// DM Dominica +pub const DOMINICA: Country = Country { code: *b"DM", rev: 0 }; +/// DO Dominican_Republic +pub const DOMINICAN_REPUBLIC: Country = Country { code: *b"DO", rev: 0 }; +/// AU G'Day mate! +pub const DOWN_UNDER: Country = Country { code: *b"AU", rev: 0 }; +/// EC Ecuador +pub const ECUADOR: Country = Country { code: *b"EC", rev: 0 }; +/// EG Egypt +pub const EGYPT: Country = Country { code: *b"EG", rev: 0 }; +/// SV El_Salvador +pub const EL_SALVADOR: Country = Country { code: *b"SV", rev: 0 }; +/// GQ Equatorial_Guinea +pub const EQUATORIAL_GUINEA: Country = Country { code: *b"GQ", rev: 0 }; +/// ER Eritrea +pub const ERITREA: Country = Country { code: *b"ER", rev: 0 }; +/// EE Estonia +pub const ESTONIA: Country = Country { code: *b"EE", rev: 0 }; +/// ET Ethiopia +pub const ETHIOPIA: Country = Country { code: *b"ET", rev: 0 }; +/// FK Falkland_Islands_(Malvinas) +pub const FALKLAND_ISLANDS_MALVINAS: Country = Country { code: *b"FK", rev: 0 }; +/// FO Faroe_Islands +pub const FAROE_ISLANDS: Country = Country { code: *b"FO", rev: 0 }; +/// FJ Fiji +pub const FIJI: Country = Country { code: *b"FJ", rev: 0 }; +/// FI Finland +pub const FINLAND: Country = Country { code: *b"FI", rev: 0 }; +/// FR France +pub const FRANCE: Country = Country { code: *b"FR", rev: 0 }; +/// GF French_Guina +pub const FRENCH_GUINA: Country = Country { code: *b"GF", rev: 0 }; +/// PF French_Polynesia +pub const FRENCH_POLYNESIA: Country = Country { code: *b"PF", rev: 0 }; +/// TF French_Southern_Territories +pub const FRENCH_SOUTHERN_TERRITORIES: Country = Country { code: *b"TF", rev: 0 }; +/// GA Gabon +pub const GABON: Country = Country { code: *b"GA", rev: 0 }; +/// GM Gambia +pub const GAMBIA: Country = Country { code: *b"GM", rev: 0 }; +/// GE Georgia +pub const GEORGIA: Country = Country { code: *b"GE", rev: 0 }; +/// DE Germany +pub const GERMANY: Country = Country { code: *b"DE", rev: 0 }; +/// E0 European_Wide Revision 895 +pub const EUROPEAN_WIDE_REV895: Country = Country { code: *b"E0", rev: 895 }; +/// GH Ghana +pub const GHANA: Country = Country { code: *b"GH", rev: 0 }; +/// GI Gibraltar +pub const GIBRALTAR: Country = Country { code: *b"GI", rev: 0 }; +/// GR Greece +pub const GREECE: Country = Country { code: *b"GR", rev: 0 }; +/// GD Grenada +pub const GRENADA: Country = Country { code: *b"GD", rev: 0 }; +/// GP Guadeloupe +pub const GUADELOUPE: Country = Country { code: *b"GP", rev: 0 }; +/// GU Guam +pub const GUAM: Country = Country { code: *b"GU", rev: 0 }; +/// GT Guatemala +pub const GUATEMALA: Country = Country { code: *b"GT", rev: 0 }; +/// GG Guernsey +pub const GUERNSEY: Country = Country { code: *b"GG", rev: 0 }; +/// GN Guinea +pub const GUINEA: Country = Country { code: *b"GN", rev: 0 }; +/// GW Guinea-bissau +pub const GUINEA_BISSAU: Country = Country { code: *b"GW", rev: 0 }; +/// GY Guyana +pub const GUYANA: Country = Country { code: *b"GY", rev: 0 }; +/// HT Haiti +pub const HAITI: Country = Country { code: *b"HT", rev: 0 }; +/// VA Holy_See_(Vatican_City_State) +pub const HOLY_SEE_VATICAN_CITY_STATE: Country = Country { code: *b"VA", rev: 0 }; +/// HN Honduras +pub const HONDURAS: Country = Country { code: *b"HN", rev: 0 }; +/// HK Hong_Kong +pub const HONG_KONG: Country = Country { code: *b"HK", rev: 0 }; +/// HU Hungary +pub const HUNGARY: Country = Country { code: *b"HU", rev: 0 }; +/// IS Iceland +pub const ICELAND: Country = Country { code: *b"IS", rev: 0 }; +/// IN India +pub const INDIA: Country = Country { code: *b"IN", rev: 0 }; +/// ID Indonesia +pub const INDONESIA: Country = Country { code: *b"ID", rev: 0 }; +/// IR Iran,_Islamic_Republic_Of +pub const IRAN_ISLAMIC_REPUBLIC_OF: Country = Country { code: *b"IR", rev: 0 }; +/// IQ Iraq +pub const IRAQ: Country = Country { code: *b"IQ", rev: 0 }; +/// IE Ireland +pub const IRELAND: Country = Country { code: *b"IE", rev: 0 }; +/// IL Israel +pub const ISRAEL: Country = Country { code: *b"IL", rev: 0 }; +/// IT Italy +pub const ITALY: Country = Country { code: *b"IT", rev: 0 }; +/// JM Jamaica +pub const JAMAICA: Country = Country { code: *b"JM", rev: 0 }; +/// JP Japan +pub const JAPAN: Country = Country { code: *b"JP", rev: 0 }; +/// JE Jersey +pub const JERSEY: Country = Country { code: *b"JE", rev: 0 }; +/// JO Jordan +pub const JORDAN: Country = Country { code: *b"JO", rev: 0 }; +/// KZ Kazakhstan +pub const KAZAKHSTAN: Country = Country { code: *b"KZ", rev: 0 }; +/// KE Kenya +pub const KENYA: Country = Country { code: *b"KE", rev: 0 }; +/// KI Kiribati +pub const KIRIBATI: Country = Country { code: *b"KI", rev: 0 }; +/// KR Korea,_Republic_Of +pub const KOREA_REPUBLIC_OF: Country = Country { code: *b"KR", rev: 1 }; +/// 0A Kosovo +pub const KOSOVO: Country = Country { code: *b"0A", rev: 0 }; +/// KW Kuwait +pub const KUWAIT: Country = Country { code: *b"KW", rev: 0 }; +/// KG Kyrgyzstan +pub const KYRGYZSTAN: Country = Country { code: *b"KG", rev: 0 }; +/// LA Lao_People's_Democratic_Repubic +pub const LAO_PEOPLES_DEMOCRATIC_REPUBIC: Country = Country { code: *b"LA", rev: 0 }; +/// LV Latvia +pub const LATVIA: Country = Country { code: *b"LV", rev: 0 }; +/// LB Lebanon +pub const LEBANON: Country = Country { code: *b"LB", rev: 0 }; +/// LS Lesotho +pub const LESOTHO: Country = Country { code: *b"LS", rev: 0 }; +/// LR Liberia +pub const LIBERIA: Country = Country { code: *b"LR", rev: 0 }; +/// LY Libyan_Arab_Jamahiriya +pub const LIBYAN_ARAB_JAMAHIRIYA: Country = Country { code: *b"LY", rev: 0 }; +/// LI Liechtenstein +pub const LIECHTENSTEIN: Country = Country { code: *b"LI", rev: 0 }; +/// LT Lithuania +pub const LITHUANIA: Country = Country { code: *b"LT", rev: 0 }; +/// LU Luxembourg +pub const LUXEMBOURG: Country = Country { code: *b"LU", rev: 0 }; +/// MO Macao +pub const MACAO: Country = Country { code: *b"MO", rev: 0 }; +/// MK Macedonia,_Former_Yugoslav_Republic_Of +pub const MACEDONIA_FORMER_YUGOSLAV_REPUBLIC_OF: Country = Country { code: *b"MK", rev: 0 }; +/// MG Madagascar +pub const MADAGASCAR: Country = Country { code: *b"MG", rev: 0 }; +/// MW Malawi +pub const MALAWI: Country = Country { code: *b"MW", rev: 0 }; +/// MY Malaysia +pub const MALAYSIA: Country = Country { code: *b"MY", rev: 0 }; +/// MV Maldives +pub const MALDIVES: Country = Country { code: *b"MV", rev: 0 }; +/// ML Mali +pub const MALI: Country = Country { code: *b"ML", rev: 0 }; +/// MT Malta +pub const MALTA: Country = Country { code: *b"MT", rev: 0 }; +/// IM Man,_Isle_Of +pub const MAN_ISLE_OF: Country = Country { code: *b"IM", rev: 0 }; +/// MQ Martinique +pub const MARTINIQUE: Country = Country { code: *b"MQ", rev: 0 }; +/// MR Mauritania +pub const MAURITANIA: Country = Country { code: *b"MR", rev: 0 }; +/// MU Mauritius +pub const MAURITIUS: Country = Country { code: *b"MU", rev: 0 }; +/// YT Mayotte +pub const MAYOTTE: Country = Country { code: *b"YT", rev: 0 }; +/// MX Mexico +pub const MEXICO: Country = Country { code: *b"MX", rev: 0 }; +/// FM Micronesia,_Federated_States_Of +pub const MICRONESIA_FEDERATED_STATES_OF: Country = Country { code: *b"FM", rev: 0 }; +/// MD Moldova,_Republic_Of +pub const MOLDOVA_REPUBLIC_OF: Country = Country { code: *b"MD", rev: 0 }; +/// MC Monaco +pub const MONACO: Country = Country { code: *b"MC", rev: 0 }; +/// MN Mongolia +pub const MONGOLIA: Country = Country { code: *b"MN", rev: 0 }; +/// ME Montenegro +pub const MONTENEGRO: Country = Country { code: *b"ME", rev: 0 }; +/// MS Montserrat +pub const MONTSERRAT: Country = Country { code: *b"MS", rev: 0 }; +/// MA Morocco +pub const MOROCCO: Country = Country { code: *b"MA", rev: 0 }; +/// MZ Mozambique +pub const MOZAMBIQUE: Country = Country { code: *b"MZ", rev: 0 }; +/// MM Myanmar +pub const MYANMAR: Country = Country { code: *b"MM", rev: 0 }; +/// NA Namibia +pub const NAMIBIA: Country = Country { code: *b"NA", rev: 0 }; +/// NR Nauru +pub const NAURU: Country = Country { code: *b"NR", rev: 0 }; +/// NP Nepal +pub const NEPAL: Country = Country { code: *b"NP", rev: 0 }; +/// NL Netherlands +pub const NETHERLANDS: Country = Country { code: *b"NL", rev: 0 }; +/// AN Netherlands_Antilles +pub const NETHERLANDS_ANTILLES: Country = Country { code: *b"AN", rev: 0 }; +/// NC New_Caledonia +pub const NEW_CALEDONIA: Country = Country { code: *b"NC", rev: 0 }; +/// NZ New_Zealand +pub const NEW_ZEALAND: Country = Country { code: *b"NZ", rev: 0 }; +/// NI Nicaragua +pub const NICARAGUA: Country = Country { code: *b"NI", rev: 0 }; +/// NE Niger +pub const NIGER: Country = Country { code: *b"NE", rev: 0 }; +/// NG Nigeria +pub const NIGERIA: Country = Country { code: *b"NG", rev: 0 }; +/// NF Norfolk_Island +pub const NORFOLK_ISLAND: Country = Country { code: *b"NF", rev: 0 }; +/// MP Northern_Mariana_Islands +pub const NORTHERN_MARIANA_ISLANDS: Country = Country { code: *b"MP", rev: 0 }; +/// NO Norway +pub const NORWAY: Country = Country { code: *b"NO", rev: 0 }; +/// OM Oman +pub const OMAN: Country = Country { code: *b"OM", rev: 0 }; +/// PK Pakistan +pub const PAKISTAN: Country = Country { code: *b"PK", rev: 0 }; +/// PW Palau +pub const PALAU: Country = Country { code: *b"PW", rev: 0 }; +/// PA Panama +pub const PANAMA: Country = Country { code: *b"PA", rev: 0 }; +/// PG Papua_New_Guinea +pub const PAPUA_NEW_GUINEA: Country = Country { code: *b"PG", rev: 0 }; +/// PY Paraguay +pub const PARAGUAY: Country = Country { code: *b"PY", rev: 0 }; +/// PE Peru +pub const PERU: Country = Country { code: *b"PE", rev: 0 }; +/// PH Philippines +pub const PHILIPPINES: Country = Country { code: *b"PH", rev: 0 }; +/// PL Poland +pub const POLAND: Country = Country { code: *b"PL", rev: 0 }; +/// PT Portugal +pub const PORTUGAL: Country = Country { code: *b"PT", rev: 0 }; +/// PR Pueto_Rico +pub const PUETO_RICO: Country = Country { code: *b"PR", rev: 0 }; +/// QA Qatar +pub const QATAR: Country = Country { code: *b"QA", rev: 0 }; +/// RE Reunion +pub const REUNION: Country = Country { code: *b"RE", rev: 0 }; +/// RO Romania +pub const ROMANIA: Country = Country { code: *b"RO", rev: 0 }; +/// RU Russian_Federation +pub const RUSSIAN_FEDERATION: Country = Country { code: *b"RU", rev: 0 }; +/// RW Rwanda +pub const RWANDA: Country = Country { code: *b"RW", rev: 0 }; +/// KN Saint_Kitts_and_Nevis +pub const SAINT_KITTS_AND_NEVIS: Country = Country { code: *b"KN", rev: 0 }; +/// LC Saint_Lucia +pub const SAINT_LUCIA: Country = Country { code: *b"LC", rev: 0 }; +/// PM Saint_Pierre_and_Miquelon +pub const SAINT_PIERRE_AND_MIQUELON: Country = Country { code: *b"PM", rev: 0 }; +/// VC Saint_Vincent_and_The_Grenadines +pub const SAINT_VINCENT_AND_THE_GRENADINES: Country = Country { code: *b"VC", rev: 0 }; +/// WS Samoa +pub const SAMOA: Country = Country { code: *b"WS", rev: 0 }; +/// MF Sanit_Martin_/_Sint_Marteen +pub const SANIT_MARTIN_SINT_MARTEEN: Country = Country { code: *b"MF", rev: 0 }; +/// ST Sao_Tome_and_Principe +pub const SAO_TOME_AND_PRINCIPE: Country = Country { code: *b"ST", rev: 0 }; +/// SA Saudi_Arabia +pub const SAUDI_ARABIA: Country = Country { code: *b"SA", rev: 0 }; +/// SN Senegal +pub const SENEGAL: Country = Country { code: *b"SN", rev: 0 }; +/// RS Serbia +pub const SERBIA: Country = Country { code: *b"RS", rev: 0 }; +/// SC Seychelles +pub const SEYCHELLES: Country = Country { code: *b"SC", rev: 0 }; +/// SL Sierra_Leone +pub const SIERRA_LEONE: Country = Country { code: *b"SL", rev: 0 }; +/// SG Singapore +pub const SINGAPORE: Country = Country { code: *b"SG", rev: 0 }; +/// SK Slovakia +pub const SLOVAKIA: Country = Country { code: *b"SK", rev: 0 }; +/// SI Slovenia +pub const SLOVENIA: Country = Country { code: *b"SI", rev: 0 }; +/// SB Solomon_Islands +pub const SOLOMON_ISLANDS: Country = Country { code: *b"SB", rev: 0 }; +/// SO Somalia +pub const SOMALIA: Country = Country { code: *b"SO", rev: 0 }; +/// ZA South_Africa +pub const SOUTH_AFRICA: Country = Country { code: *b"ZA", rev: 0 }; +/// ES Spain +pub const SPAIN: Country = Country { code: *b"ES", rev: 0 }; +/// LK Sri_Lanka +pub const SRI_LANKA: Country = Country { code: *b"LK", rev: 0 }; +/// SR Suriname +pub const SURINAME: Country = Country { code: *b"SR", rev: 0 }; +/// SZ Swaziland +pub const SWAZILAND: Country = Country { code: *b"SZ", rev: 0 }; +/// SE Sweden +pub const SWEDEN: Country = Country { code: *b"SE", rev: 0 }; +/// CH Switzerland +pub const SWITZERLAND: Country = Country { code: *b"CH", rev: 0 }; +/// SY Syrian_Arab_Republic +pub const SYRIAN_ARAB_REPUBLIC: Country = Country { code: *b"SY", rev: 0 }; +/// TW Taiwan,_Province_Of_China +pub const TAIWAN_PROVINCE_OF_CHINA: Country = Country { code: *b"TW", rev: 0 }; +/// TJ Tajikistan +pub const TAJIKISTAN: Country = Country { code: *b"TJ", rev: 0 }; +/// TZ Tanzania,_United_Republic_Of +pub const TANZANIA_UNITED_REPUBLIC_OF: Country = Country { code: *b"TZ", rev: 0 }; +/// TH Thailand +pub const THAILAND: Country = Country { code: *b"TH", rev: 0 }; +/// TG Togo +pub const TOGO: Country = Country { code: *b"TG", rev: 0 }; +/// TO Tonga +pub const TONGA: Country = Country { code: *b"TO", rev: 0 }; +/// TT Trinidad_and_Tobago +pub const TRINIDAD_AND_TOBAGO: Country = Country { code: *b"TT", rev: 0 }; +/// TN Tunisia +pub const TUNISIA: Country = Country { code: *b"TN", rev: 0 }; +/// TR Turkey +pub const TURKEY: Country = Country { code: *b"TR", rev: 0 }; +/// TM Turkmenistan +pub const TURKMENISTAN: Country = Country { code: *b"TM", rev: 0 }; +/// TC Turks_and_Caicos_Islands +pub const TURKS_AND_CAICOS_ISLANDS: Country = Country { code: *b"TC", rev: 0 }; +/// TV Tuvalu +pub const TUVALU: Country = Country { code: *b"TV", rev: 0 }; +/// UG Uganda +pub const UGANDA: Country = Country { code: *b"UG", rev: 0 }; +/// UA Ukraine +pub const UKRAINE: Country = Country { code: *b"UA", rev: 0 }; +/// AE United_Arab_Emirates +pub const UNITED_ARAB_EMIRATES: Country = Country { code: *b"AE", rev: 0 }; +/// GB United_Kingdom +pub const UNITED_KINGDOM: Country = Country { code: *b"GB", rev: 0 }; +/// US United_States +pub const UNITED_STATES: Country = Country { code: *b"US", rev: 0 }; +/// US United_States Revision 4 +pub const UNITED_STATES_REV4: Country = Country { code: *b"US", rev: 4 }; +/// Q1 United_States Revision 931 +pub const UNITED_STATES_REV931: Country = Country { code: *b"Q1", rev: 931 }; +/// Q2 United_States_(No_DFS) +pub const UNITED_STATES_NO_DFS: Country = Country { code: *b"Q2", rev: 0 }; +/// UM United_States_Minor_Outlying_Islands +pub const UNITED_STATES_MINOR_OUTLYING_ISLANDS: Country = Country { code: *b"UM", rev: 0 }; +/// UY Uruguay +pub const URUGUAY: Country = Country { code: *b"UY", rev: 0 }; +/// UZ Uzbekistan +pub const UZBEKISTAN: Country = Country { code: *b"UZ", rev: 0 }; +/// VU Vanuatu +pub const VANUATU: Country = Country { code: *b"VU", rev: 0 }; +/// VE Venezuela +pub const VENEZUELA: Country = Country { code: *b"VE", rev: 0 }; +/// VN Viet_Nam +pub const VIET_NAM: Country = Country { code: *b"VN", rev: 0 }; +/// VG Virgin_Islands,_British +pub const VIRGIN_ISLANDS_BRITISH: Country = Country { code: *b"VG", rev: 0 }; +/// VI Virgin_Islands,_U.S. +pub const VIRGIN_ISLANDS_US: Country = Country { code: *b"VI", rev: 0 }; +/// WF Wallis_and_Futuna +pub const WALLIS_AND_FUTUNA: Country = Country { code: *b"WF", rev: 0 }; +/// 0C West_Bank +pub const WEST_BANK: Country = Country { code: *b"0C", rev: 0 }; +/// EH Western_Sahara +pub const WESTERN_SAHARA: Country = Country { code: *b"EH", rev: 0 }; +/// Worldwide Locale Revision 983 +pub const WORLD_WIDE_XV_REV983: Country = Country { code: *b"XV", rev: 983 }; +/// Worldwide Locale (passive Ch12-14) +pub const WORLD_WIDE_XX: Country = Country { code: *b"XX", rev: 0 }; +/// Worldwide Locale (passive Ch12-14) Revision 17 +pub const WORLD_WIDE_XX_REV17: Country = Country { code: *b"XX", rev: 17 }; +/// YE Yemen +pub const YEMEN: Country = Country { code: *b"YE", rev: 0 }; +/// ZM Zambia +pub const ZAMBIA: Country = Country { code: *b"ZM", rev: 0 }; +/// ZW Zimbabwe +pub const ZIMBABWE: Country = Country { code: *b"ZW", rev: 0 }; diff --git a/cyw43/src/events.rs b/cyw43/src/events.rs new file mode 100644 index 000000000..a94c49a0c --- /dev/null +++ b/cyw43/src/events.rs @@ -0,0 +1,400 @@ +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +use core::cell::RefCell; + +use embassy_sync::blocking_mutex::raw::NoopRawMutex; +use embassy_sync::pubsub::{PubSubChannel, Subscriber}; + +use crate::structs::BssInfo; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, num_enum::FromPrimitive)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u8)] +pub enum Event { + #[num_enum(default)] + Unknown = 0xFF, + /// indicates status of set SSID + SET_SSID = 0, + /// differentiates join IBSS from found (START) IBSS + JOIN = 1, + /// STA founded an IBSS or AP started a BSS + START = 2, + /// 802.11 AUTH request + AUTH = 3, + /// 802.11 AUTH indication + AUTH_IND = 4, + /// 802.11 DEAUTH request + DEAUTH = 5, + /// 802.11 DEAUTH indication + DEAUTH_IND = 6, + /// 802.11 ASSOC request + ASSOC = 7, + /// 802.11 ASSOC indication + ASSOC_IND = 8, + /// 802.11 REASSOC request + REASSOC = 9, + /// 802.11 REASSOC indication + REASSOC_IND = 10, + /// 802.11 DISASSOC request + DISASSOC = 11, + /// 802.11 DISASSOC indication + DISASSOC_IND = 12, + /// 802.11h Quiet period started + QUIET_START = 13, + /// 802.11h Quiet period ended + QUIET_END = 14, + /// BEACONS received/lost indication + BEACON_RX = 15, + /// generic link indication + LINK = 16, + /// TKIP MIC error occurred + MIC_ERROR = 17, + /// NDIS style link indication + NDIS_LINK = 18, + /// roam attempt occurred: indicate status & reason + ROAM = 19, + /// change in dot11FailedCount (txfail) + TXFAIL = 20, + /// WPA2 pmkid cache indication + PMKID_CACHE = 21, + /// current AP's TSF value went backward + RETROGRADE_TSF = 22, + /// AP was pruned from join list for reason + PRUNE = 23, + /// report AutoAuth table entry match for join attempt + AUTOAUTH = 24, + /// Event encapsulating an EAPOL message + EAPOL_MSG = 25, + /// Scan results are ready or scan was aborted + SCAN_COMPLETE = 26, + /// indicate to host addts fail/success + ADDTS_IND = 27, + /// indicate to host delts fail/success + DELTS_IND = 28, + /// indicate to host of beacon transmit + BCNSENT_IND = 29, + /// Send the received beacon up to the host + BCNRX_MSG = 30, + /// indicate to host loss of beacon + BCNLOST_MSG = 31, + /// before attempting to roam + ROAM_PREP = 32, + /// PFN network found event + PFN_NET_FOUND = 33, + /// PFN network lost event + PFN_NET_LOST = 34, + RESET_COMPLETE = 35, + JOIN_START = 36, + ROAM_START = 37, + ASSOC_START = 38, + IBSS_ASSOC = 39, + RADIO = 40, + /// PSM microcode watchdog fired + PSM_WATCHDOG = 41, + /// CCX association start + CCX_ASSOC_START = 42, + /// CCX association abort + CCX_ASSOC_ABORT = 43, + /// probe request received + PROBREQ_MSG = 44, + SCAN_CONFIRM_IND = 45, + /// WPA Handshake + PSK_SUP = 46, + COUNTRY_CODE_CHANGED = 47, + /// WMMAC excedded medium time + EXCEEDED_MEDIUM_TIME = 48, + /// WEP ICV error occurred + ICV_ERROR = 49, + /// Unsupported unicast encrypted frame + UNICAST_DECODE_ERROR = 50, + /// Unsupported multicast encrypted frame + MULTICAST_DECODE_ERROR = 51, + TRACE = 52, + /// BT-AMP HCI event + BTA_HCI_EVENT = 53, + /// I/F change (for wlan host notification) + IF = 54, + /// P2P Discovery listen state expires + P2P_DISC_LISTEN_COMPLETE = 55, + /// indicate RSSI change based on configured levels + RSSI = 56, + /// PFN best network batching event + PFN_BEST_BATCHING = 57, + EXTLOG_MSG = 58, + /// Action frame reception + ACTION_FRAME = 59, + /// Action frame Tx complete + ACTION_FRAME_COMPLETE = 60, + /// assoc request received + PRE_ASSOC_IND = 61, + /// re-assoc request received + PRE_REASSOC_IND = 62, + /// channel adopted (xxx: obsoleted) + CHANNEL_ADOPTED = 63, + /// AP started + AP_STARTED = 64, + /// AP stopped due to DFS + DFS_AP_STOP = 65, + /// AP resumed due to DFS + DFS_AP_RESUME = 66, + /// WAI stations event + WAI_STA_EVENT = 67, + /// event encapsulating an WAI message + WAI_MSG = 68, + /// escan result event + ESCAN_RESULT = 69, + /// action frame off channel complete + ACTION_FRAME_OFF_CHAN_COMPLETE = 70, + /// probe response received + PROBRESP_MSG = 71, + /// P2P Probe request received + P2P_PROBREQ_MSG = 72, + DCS_REQUEST = 73, + /// credits for D11 FIFOs. [AC0,AC1,AC2,AC3,BC_MC,ATIM] + FIFO_CREDIT_MAP = 74, + /// Received action frame event WITH wl_event_rx_frame_data_t header + ACTION_FRAME_RX = 75, + /// Wake Event timer fired, used for wake WLAN test mode + WAKE_EVENT = 76, + /// Radio measurement complete + RM_COMPLETE = 77, + /// Synchronize TSF with the host + HTSFSYNC = 78, + /// request an overlay IOCTL/iovar from the host + OVERLAY_REQ = 79, + CSA_COMPLETE_IND = 80, + /// excess PM Wake Event to inform host + EXCESS_PM_WAKE_EVENT = 81, + /// no PFN networks around + PFN_SCAN_NONE = 82, + /// last found PFN network gets lost + PFN_SCAN_ALLGONE = 83, + GTK_PLUMBED = 84, + /// 802.11 ASSOC indication for NDIS only + ASSOC_IND_NDIS = 85, + /// 802.11 REASSOC indication for NDIS only + REASSOC_IND_NDIS = 86, + ASSOC_REQ_IE = 87, + ASSOC_RESP_IE = 88, + /// association recreated on resume + ASSOC_RECREATED = 89, + /// rx action frame event for NDIS only + ACTION_FRAME_RX_NDIS = 90, + /// authentication request received + AUTH_REQ = 91, + /// fast assoc recreation failed + SPEEDY_RECREATE_FAIL = 93, + /// port-specific event and payload (e.g. NDIS) + NATIVE = 94, + /// event for tx pkt delay suddently jump + PKTDELAY_IND = 95, + /// AWDL AW period starts + AWDL_AW = 96, + /// AWDL Master/Slave/NE master role event + AWDL_ROLE = 97, + /// Generic AWDL event + AWDL_EVENT = 98, + /// NIC AF txstatus + NIC_AF_TXS = 99, + /// NAN event + NAN = 100, + BEACON_FRAME_RX = 101, + /// desired service found + SERVICE_FOUND = 102, + /// GAS fragment received + GAS_FRAGMENT_RX = 103, + /// GAS sessions all complete + GAS_COMPLETE = 104, + /// New device found by p2p offload + P2PO_ADD_DEVICE = 105, + /// device has been removed by p2p offload + P2PO_DEL_DEVICE = 106, + /// WNM event to notify STA enter sleep mode + WNM_STA_SLEEP = 107, + /// Indication of MAC tx failures (exhaustion of 802.11 retries) exceeding threshold(s) + TXFAIL_THRESH = 108, + /// Proximity Detection event + PROXD = 109, + /// AWDL RX Probe response + AWDL_RX_PRB_RESP = 111, + /// AWDL RX Action Frames + AWDL_RX_ACT_FRAME = 112, + /// AWDL Wowl nulls + AWDL_WOWL_NULLPKT = 113, + /// AWDL Phycal status + AWDL_PHYCAL_STATUS = 114, + /// AWDL OOB AF status + AWDL_OOB_AF_STATUS = 115, + /// Interleaved Scan status + AWDL_SCAN_STATUS = 116, + /// AWDL AW Start + AWDL_AW_START = 117, + /// AWDL AW End + AWDL_AW_END = 118, + /// AWDL AW Extensions + AWDL_AW_EXT = 119, + AWDL_PEER_CACHE_CONTROL = 120, + CSA_START_IND = 121, + CSA_DONE_IND = 122, + CSA_FAILURE_IND = 123, + /// CCA based channel quality report + CCA_CHAN_QUAL = 124, + /// to report change in BSSID while roaming + BSSID = 125, + /// tx error indication + TX_STAT_ERROR = 126, + /// credit check for BCMC supported + BCMC_CREDIT_SUPPORT = 127, + /// psta primary interface indication + PSTA_PRIMARY_INTF_IND = 128, + /// Handover Request Initiated + BT_WIFI_HANDOVER_REQ = 130, + /// Southpaw TxInhibit notification + SPW_TXINHIBIT = 131, + /// FBT Authentication Request Indication + FBT_AUTH_REQ_IND = 132, + /// Enhancement addition for RSSI + RSSI_LQM = 133, + /// Full probe/beacon (IEs etc) results + PFN_GSCAN_FULL_RESULT = 134, + /// Significant change in rssi of bssids being tracked + PFN_SWC = 135, + /// a STA been authroized for traffic + AUTHORIZED = 136, + /// probe req with wl_event_rx_frame_data_t header + PROBREQ_MSG_RX = 137, + /// PFN completed scan of network list + PFN_SCAN_COMPLETE = 138, + /// RMC Event + RMC_EVENT = 139, + /// DPSTA interface indication + DPSTA_INTF_IND = 140, + /// RRM Event + RRM = 141, + /// ULP entry event + ULP = 146, + /// TCP Keep Alive Offload Event + TKO = 151, + /// authentication request received + EXT_AUTH_REQ = 187, + /// authentication request received + EXT_AUTH_FRAME_RX = 188, + /// mgmt frame Tx complete + MGMT_FRAME_TXSTATUS = 189, + /// highest val + 1 for range checking + LAST = 190, +} + +// TODO this PubSub can probably be replaced with shared memory to make it a bit more efficient. +pub type EventQueue = PubSubChannel; +pub type EventSubscriber<'a> = Subscriber<'a, NoopRawMutex, Message, 2, 1, 1>; + +pub struct Events { + pub queue: EventQueue, + pub mask: SharedEventMask, +} + +impl Events { + pub fn new() -> Self { + Self { + queue: EventQueue::new(), + mask: SharedEventMask::default(), + } + } +} + +#[derive(Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Status { + pub event_type: Event, + pub status: u32, +} + +#[derive(Clone, Copy)] +pub enum Payload { + None, + BssInfo(BssInfo), +} + +#[derive(Clone, Copy)] + +pub struct Message { + pub header: Status, + pub payload: Payload, +} + +impl Message { + pub fn new(status: Status, payload: Payload) -> Self { + Self { + header: status, + payload, + } + } +} + +#[derive(Default)] +struct EventMask { + mask: [u32; Self::WORD_COUNT], +} + +impl EventMask { + const WORD_COUNT: usize = ((Event::LAST as u32 + (u32::BITS - 1)) / u32::BITS) as usize; + + fn enable(&mut self, event: Event) { + let n = event as u32; + let word = n / u32::BITS; + let bit = n % u32::BITS; + + self.mask[word as usize] |= 1 << bit; + } + + fn disable(&mut self, event: Event) { + let n = event as u32; + let word = n / u32::BITS; + let bit = n % u32::BITS; + + self.mask[word as usize] &= !(1 << bit); + } + + fn is_enabled(&self, event: Event) -> bool { + let n = event as u32; + let word = n / u32::BITS; + let bit = n % u32::BITS; + + self.mask[word as usize] & (1 << bit) > 0 + } +} + +#[derive(Default)] + +pub struct SharedEventMask { + mask: RefCell, +} + +impl SharedEventMask { + pub fn enable(&self, events: &[Event]) { + let mut mask = self.mask.borrow_mut(); + for event in events { + mask.enable(*event); + } + } + + #[allow(dead_code)] + pub fn disable(&self, events: &[Event]) { + let mut mask = self.mask.borrow_mut(); + for event in events { + mask.disable(*event); + } + } + + pub fn disable_all(&self) { + let mut mask = self.mask.borrow_mut(); + mask.mask = Default::default(); + } + + pub fn is_enabled(&self, event: Event) -> bool { + let mask = self.mask.borrow(); + mask.is_enabled(event) + } +} diff --git a/cyw43/src/fmt.rs b/cyw43/src/fmt.rs new file mode 100644 index 000000000..5730447b3 --- /dev/null +++ b/cyw43/src/fmt.rs @@ -0,0 +1,257 @@ +#![macro_use] +#![allow(unused_macros)] + +use core::fmt::{Debug, Display, LowerHex}; + +#[cfg(all(feature = "defmt", feature = "log"))] +compile_error!("You may not enable both `defmt` and `log` features."); + +macro_rules! assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert!($($x)*); + } + }; +} + +macro_rules! assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_eq!($($x)*); + } + }; +} + +macro_rules! assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_ne!($($x)*); + } + }; +} + +macro_rules! debug_assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert!($($x)*); + } + }; +} + +macro_rules! debug_assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_eq!($($x)*); + } + }; +} + +macro_rules! debug_assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_ne!($($x)*); + } + }; +} + +macro_rules! todo { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::todo!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::todo!($($x)*); + } + }; +} + +macro_rules! unreachable { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::unreachable!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::unreachable!($($x)*); + } + }; +} + +macro_rules! panic { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::panic!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::panic!($($x)*); + } + }; +} + +macro_rules! trace { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::trace!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::trace!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! debug { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::debug!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::debug!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! info { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::info!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::info!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! warn { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::warn!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::warn!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! error { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::error!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::error!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unwrap { + ($($x:tt)*) => { + ::defmt::unwrap!($($x)*) + }; +} + +#[cfg(not(feature = "defmt"))] +macro_rules! unwrap { + ($arg:expr) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); + } + } + }; + ($arg:expr, $($msg:expr),+ $(,)? ) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); + } + } + } +} + +#[cfg(feature = "defmt-timestamp-uptime")] +defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() } + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct NoneError; + +pub trait Try { + type Ok; + type Error; + fn into_result(self) -> Result; +} + +impl Try for Option { + type Ok = T; + type Error = NoneError; + + #[inline] + fn into_result(self) -> Result { + self.ok_or(NoneError) + } +} + +impl Try for Result { + type Ok = T; + type Error = E; + + #[inline] + fn into_result(self) -> Self { + self + } +} + +pub struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/cyw43/src/ioctl.rs b/cyw43/src/ioctl.rs new file mode 100644 index 000000000..61524c274 --- /dev/null +++ b/cyw43/src/ioctl.rs @@ -0,0 +1,126 @@ +use core::cell::{Cell, RefCell}; +use core::future::poll_fn; +use core::task::{Poll, Waker}; + +use embassy_sync::waitqueue::WakerRegistration; + +use crate::fmt::Bytes; + +#[derive(Clone, Copy)] +pub enum IoctlType { + Get = 0, + Set = 2, +} + +#[derive(Clone, Copy)] +pub struct PendingIoctl { + pub buf: *mut [u8], + pub kind: IoctlType, + pub cmd: u32, + pub iface: u32, +} + +#[derive(Clone, Copy)] +enum IoctlStateInner { + Pending(PendingIoctl), + Sent { buf: *mut [u8] }, + Done { resp_len: usize }, +} + +struct Wakers { + control: WakerRegistration, + runner: WakerRegistration, +} + +impl Default for Wakers { + fn default() -> Self { + Self { + control: WakerRegistration::new(), + runner: WakerRegistration::new(), + } + } +} + +pub struct IoctlState { + state: Cell, + wakers: RefCell, +} + +impl IoctlState { + pub fn new() -> Self { + Self { + state: Cell::new(IoctlStateInner::Done { resp_len: 0 }), + wakers: Default::default(), + } + } + + fn wake_control(&self) { + self.wakers.borrow_mut().control.wake(); + } + + fn register_control(&self, waker: &Waker) { + self.wakers.borrow_mut().control.register(waker); + } + + fn wake_runner(&self) { + self.wakers.borrow_mut().runner.wake(); + } + + fn register_runner(&self, waker: &Waker) { + self.wakers.borrow_mut().runner.register(waker); + } + + pub async fn wait_complete(&self) -> usize { + poll_fn(|cx| { + if let IoctlStateInner::Done { resp_len } = self.state.get() { + Poll::Ready(resp_len) + } else { + self.register_control(cx.waker()); + Poll::Pending + } + }) + .await + } + + pub async fn wait_pending(&self) -> PendingIoctl { + let pending = poll_fn(|cx| { + if let IoctlStateInner::Pending(pending) = self.state.get() { + Poll::Ready(pending) + } else { + self.register_runner(cx.waker()); + Poll::Pending + } + }) + .await; + + self.state.set(IoctlStateInner::Sent { buf: pending.buf }); + pending + } + + pub fn cancel_ioctl(&self) { + self.state.set(IoctlStateInner::Done { resp_len: 0 }); + } + + pub async fn do_ioctl(&self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize { + self.state + .set(IoctlStateInner::Pending(PendingIoctl { buf, kind, cmd, iface })); + self.wake_runner(); + self.wait_complete().await + } + + pub fn ioctl_done(&self, response: &[u8]) { + if let IoctlStateInner::Sent { buf } = self.state.get() { + trace!("IOCTL Response: {:02x}", Bytes(response)); + + // TODO fix this + (unsafe { &mut *buf }[..response.len()]).copy_from_slice(response); + + self.state.set(IoctlStateInner::Done { + resp_len: response.len(), + }); + self.wake_control(); + } else { + warn!("IOCTL Response but no pending Ioctl"); + } + } +} diff --git a/cyw43/src/lib.rs b/cyw43/src/lib.rs new file mode 100644 index 000000000..fd11f3674 --- /dev/null +++ b/cyw43/src/lib.rs @@ -0,0 +1,236 @@ +#![no_std] +#![no_main] +#![allow(incomplete_features)] +#![feature(async_fn_in_trait, type_alias_impl_trait, concat_bytes)] +#![deny(unused_must_use)] + +// This mod MUST go first, so that the others see its macros. +pub(crate) mod fmt; + +mod bus; +mod consts; +mod countries; +mod events; +mod ioctl; +mod structs; + +mod control; +mod nvram; +mod runner; + +use core::slice; + +use embassy_net_driver_channel as ch; +use embedded_hal_1::digital::OutputPin; +use events::Events; +use ioctl::IoctlState; + +use crate::bus::Bus; +pub use crate::bus::SpiBusCyw43; +pub use crate::control::{Control, Error as ControlError}; +pub use crate::runner::Runner; +pub use crate::structs::BssInfo; + +const MTU: usize = 1514; + +#[allow(unused)] +#[derive(Clone, Copy, PartialEq, Eq)] +enum Core { + WLAN = 0, + SOCSRAM = 1, + SDIOD = 2, +} + +impl Core { + fn base_addr(&self) -> u32 { + match self { + Self::WLAN => CHIP.arm_core_base_address, + Self::SOCSRAM => CHIP.socsram_wrapper_base_address, + Self::SDIOD => CHIP.sdiod_core_base_address, + } + } +} + +#[allow(unused)] +struct Chip { + arm_core_base_address: u32, + socsram_base_address: u32, + socsram_wrapper_base_address: u32, + sdiod_core_base_address: u32, + pmu_base_address: u32, + chip_ram_size: u32, + atcm_ram_base_address: u32, + socram_srmem_size: u32, + chanspec_band_mask: u32, + chanspec_band_2g: u32, + chanspec_band_5g: u32, + chanspec_band_shift: u32, + chanspec_bw_10: u32, + chanspec_bw_20: u32, + chanspec_bw_40: u32, + chanspec_bw_mask: u32, + chanspec_bw_shift: u32, + chanspec_ctl_sb_lower: u32, + chanspec_ctl_sb_upper: u32, + chanspec_ctl_sb_none: u32, + chanspec_ctl_sb_mask: u32, +} + +const WRAPPER_REGISTER_OFFSET: u32 = 0x100000; + +// Data for CYW43439 +const CHIP: Chip = Chip { + arm_core_base_address: 0x18003000 + WRAPPER_REGISTER_OFFSET, + socsram_base_address: 0x18004000, + socsram_wrapper_base_address: 0x18004000 + WRAPPER_REGISTER_OFFSET, + sdiod_core_base_address: 0x18002000, + pmu_base_address: 0x18000000, + chip_ram_size: 512 * 1024, + atcm_ram_base_address: 0, + socram_srmem_size: 64 * 1024, + chanspec_band_mask: 0xc000, + chanspec_band_2g: 0x0000, + chanspec_band_5g: 0xc000, + chanspec_band_shift: 14, + chanspec_bw_10: 0x0800, + chanspec_bw_20: 0x1000, + chanspec_bw_40: 0x1800, + chanspec_bw_mask: 0x3800, + chanspec_bw_shift: 11, + chanspec_ctl_sb_lower: 0x0000, + chanspec_ctl_sb_upper: 0x0100, + chanspec_ctl_sb_none: 0x0000, + chanspec_ctl_sb_mask: 0x0700, +}; + +pub struct State { + ioctl_state: IoctlState, + ch: ch::State, + events: Events, +} + +impl State { + pub fn new() -> Self { + Self { + ioctl_state: IoctlState::new(), + ch: ch::State::new(), + events: Events::new(), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PowerManagementMode { + /// Custom, officially unsupported mode. Use at your own risk. + /// All power-saving features set to their max at only a marginal decrease in power consumption + /// as oppposed to `Aggressive`. + SuperSave, + + /// Aggressive power saving mode. + Aggressive, + + /// The default mode. + PowerSave, + + /// Performance is prefered over power consumption but still some power is conserved as opposed to + /// `None`. + Performance, + + /// Unlike all the other PM modes, this lowers the power consumption at all times at the cost of + /// a much lower throughput. + ThroughputThrottling, + + /// No power management is configured. This consumes the most power. + None, +} + +impl Default for PowerManagementMode { + fn default() -> Self { + Self::PowerSave + } +} + +impl PowerManagementMode { + fn sleep_ret_ms(&self) -> u16 { + match self { + PowerManagementMode::SuperSave => 2000, + PowerManagementMode::Aggressive => 2000, + PowerManagementMode::PowerSave => 200, + PowerManagementMode::Performance => 20, + PowerManagementMode::ThroughputThrottling => 0, // value doesn't matter + PowerManagementMode::None => 0, // value doesn't matter + } + } + + fn beacon_period(&self) -> u8 { + match self { + PowerManagementMode::SuperSave => 255, + PowerManagementMode::Aggressive => 1, + PowerManagementMode::PowerSave => 1, + PowerManagementMode::Performance => 1, + PowerManagementMode::ThroughputThrottling => 0, // value doesn't matter + PowerManagementMode::None => 0, // value doesn't matter + } + } + + fn dtim_period(&self) -> u8 { + match self { + PowerManagementMode::SuperSave => 255, + PowerManagementMode::Aggressive => 1, + PowerManagementMode::PowerSave => 1, + PowerManagementMode::Performance => 1, + PowerManagementMode::ThroughputThrottling => 0, // value doesn't matter + PowerManagementMode::None => 0, // value doesn't matter + } + } + + fn assoc(&self) -> u8 { + match self { + PowerManagementMode::SuperSave => 255, + PowerManagementMode::Aggressive => 10, + PowerManagementMode::PowerSave => 10, + PowerManagementMode::Performance => 1, + PowerManagementMode::ThroughputThrottling => 0, // value doesn't matter + PowerManagementMode::None => 0, // value doesn't matter + } + } + + fn mode(&self) -> u32 { + match self { + PowerManagementMode::ThroughputThrottling => 1, + PowerManagementMode::None => 0, + _ => 2, + } + } +} + +pub type NetDriver<'a> = ch::Device<'a, MTU>; + +pub async fn new<'a, PWR, SPI>( + state: &'a mut State, + pwr: PWR, + spi: SPI, + firmware: &[u8], +) -> (NetDriver<'a>, Control<'a>, Runner<'a, PWR, SPI>) +where + PWR: OutputPin, + SPI: SpiBusCyw43, +{ + let (ch_runner, device) = ch::new(&mut state.ch, [0; 6]); + let state_ch = ch_runner.state_runner(); + + let mut runner = Runner::new(ch_runner, Bus::new(pwr, spi), &state.ioctl_state, &state.events); + + runner.init(firmware).await; + + ( + device, + Control::new(state_ch, &state.events, &state.ioctl_state), + runner, + ) +} + +fn slice8_mut(x: &mut [u32]) -> &mut [u8] { + let len = x.len() * 4; + unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) } +} diff --git a/cyw43/src/nvram.rs b/cyw43/src/nvram.rs new file mode 100644 index 000000000..964a3128d --- /dev/null +++ b/cyw43/src/nvram.rs @@ -0,0 +1,54 @@ +macro_rules! nvram { + ($($s:literal,)*) => { + concat_bytes!($($s, b"\x00",)* b"\x00\x00") + }; +} + +pub static NVRAM: &'static [u8] = &*nvram!( + b"NVRAMRev=$Rev$", + b"manfid=0x2d0", + b"prodid=0x0727", + b"vendid=0x14e4", + b"devid=0x43e2", + b"boardtype=0x0887", + b"boardrev=0x1100", + b"boardnum=22", + b"macaddr=00:A0:50:b5:59:5e", + b"sromrev=11", + b"boardflags=0x00404001", + b"boardflags3=0x04000000", + b"xtalfreq=37400", + b"nocrc=1", + b"ag0=255", + b"aa2g=1", + b"ccode=ALL", + b"pa0itssit=0x20", + b"extpagain2g=0", + b"pa2ga0=-168,6649,-778", + b"AvVmid_c0=0x0,0xc8", + b"cckpwroffset0=5", + b"maxp2ga0=84", + b"txpwrbckof=6", + b"cckbw202gpo=0", + b"legofdmbw202gpo=0x66111111", + b"mcsbw202gpo=0x77711111", + b"propbw202gpo=0xdd", + b"ofdmdigfilttype=18", + b"ofdmdigfilttypebe=18", + b"papdmode=1", + b"papdvalidtest=1", + b"pacalidx2g=45", + b"papdepsoffset=-30", + b"papdendidx=58", + b"ltecxmux=0", + b"ltecxpadnum=0x0102", + b"ltecxfnsel=0x44", + b"ltecxgcigpio=0x01", + b"il0macaddr=00:90:4c:c5:12:38", + b"wl0id=0x431b", + b"deadman_to=0xffffffff", + b"muxenab=0x100", + b"spurconfig=0x3", + b"glitch_based_crsmin=1", + b"btc_mode=1", +); diff --git a/cyw43/src/runner.rs b/cyw43/src/runner.rs new file mode 100644 index 000000000..5706696b4 --- /dev/null +++ b/cyw43/src/runner.rs @@ -0,0 +1,575 @@ +use embassy_futures::select::{select3, Either3}; +use embassy_net_driver_channel as ch; +use embassy_sync::pubsub::PubSubBehavior; +use embassy_time::{block_for, Duration, Timer}; +use embedded_hal_1::digital::OutputPin; + +use crate::bus::Bus; +pub use crate::bus::SpiBusCyw43; +use crate::consts::*; +use crate::events::{Event, Events, Status}; +use crate::fmt::Bytes; +use crate::ioctl::{IoctlState, IoctlType, PendingIoctl}; +use crate::nvram::NVRAM; +use crate::structs::*; +use crate::{events, slice8_mut, Core, CHIP, MTU}; + +#[cfg(feature = "firmware-logs")] +struct LogState { + addr: u32, + last_idx: usize, + buf: [u8; 256], + buf_count: usize, +} + +#[cfg(feature = "firmware-logs")] +impl Default for LogState { + fn default() -> Self { + Self { + addr: Default::default(), + last_idx: Default::default(), + buf: [0; 256], + buf_count: Default::default(), + } + } +} + +pub struct Runner<'a, PWR, SPI> { + ch: ch::Runner<'a, MTU>, + bus: Bus, + + ioctl_state: &'a IoctlState, + ioctl_id: u16, + sdpcm_seq: u8, + sdpcm_seq_max: u8, + + events: &'a Events, + + #[cfg(feature = "firmware-logs")] + log: LogState, +} + +impl<'a, PWR, SPI> Runner<'a, PWR, SPI> +where + PWR: OutputPin, + SPI: SpiBusCyw43, +{ + pub(crate) fn new( + ch: ch::Runner<'a, MTU>, + bus: Bus, + ioctl_state: &'a IoctlState, + events: &'a Events, + ) -> Self { + Self { + ch, + bus, + ioctl_state, + ioctl_id: 0, + sdpcm_seq: 0, + sdpcm_seq_max: 1, + events, + #[cfg(feature = "firmware-logs")] + log: LogState::default(), + } + } + + pub(crate) async fn init(&mut self, firmware: &[u8]) { + self.bus.init().await; + + // Init ALP (Active Low Power) clock + self.bus + .write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, BACKPLANE_ALP_AVAIL_REQ) + .await; + debug!("waiting for clock..."); + while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & BACKPLANE_ALP_AVAIL == 0 {} + debug!("clock ok"); + + let chip_id = self.bus.bp_read16(0x1800_0000).await; + debug!("chip ID: {}", chip_id); + + // Upload firmware. + self.core_disable(Core::WLAN).await; + self.core_reset(Core::SOCSRAM).await; + self.bus.bp_write32(CHIP.socsram_base_address + 0x10, 3).await; + self.bus.bp_write32(CHIP.socsram_base_address + 0x44, 0).await; + + let ram_addr = CHIP.atcm_ram_base_address; + + debug!("loading fw"); + self.bus.bp_write(ram_addr, firmware).await; + + debug!("loading nvram"); + // Round up to 4 bytes. + let nvram_len = (NVRAM.len() + 3) / 4 * 4; + self.bus + .bp_write(ram_addr + CHIP.chip_ram_size - 4 - nvram_len as u32, NVRAM) + .await; + + let nvram_len_words = nvram_len as u32 / 4; + let nvram_len_magic = (!nvram_len_words << 16) | nvram_len_words; + self.bus + .bp_write32(ram_addr + CHIP.chip_ram_size - 4, nvram_len_magic) + .await; + + // Start core! + debug!("starting up core..."); + self.core_reset(Core::WLAN).await; + assert!(self.core_is_up(Core::WLAN).await); + + while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {} + + // "Set up the interrupt mask and enable interrupts" + // self.bus.bp_write32(CHIP.sdiod_core_base_address + 0x24, 0xF0).await; + + self.bus + .write16(FUNC_BUS, REG_BUS_INTERRUPT_ENABLE, IRQ_F2_PACKET_AVAILABLE) + .await; + + // "Lower F2 Watermark to avoid DMA Hang in F2 when SD Clock is stopped." + // Sounds scary... + self.bus + .write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, 32) + .await; + + // wait for wifi startup + debug!("waiting for wifi init..."); + while self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await & STATUS_F2_RX_READY == 0 {} + + // Some random configs related to sleep. + // These aren't needed if we don't want to sleep the bus. + // TODO do we need to sleep the bus to read the irq line, due to + // being on the same pin as MOSI/MISO? + + /* + let mut val = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_WAKEUP_CTRL).await; + val |= 0x02; // WAKE_TILL_HT_AVAIL + self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_WAKEUP_CTRL, val).await; + self.bus.write8(FUNC_BUS, 0xF0, 0x08).await; // SDIOD_CCCR_BRCM_CARDCAP.CMD_NODEC = 1 + self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x02).await; // SBSDIO_FORCE_HT + + let mut val = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_SLEEP_CSR).await; + val |= 0x01; // SBSDIO_SLPCSR_KEEP_SDIO_ON + self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_SLEEP_CSR, val).await; + */ + + // clear pulls + self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP, 0).await; + let _ = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP).await; + + // start HT clock + //self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x10).await; + //debug!("waiting for HT clock..."); + //while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {} + //debug!("clock ok"); + + #[cfg(feature = "firmware-logs")] + self.log_init().await; + + debug!("wifi init done"); + } + + #[cfg(feature = "firmware-logs")] + async fn log_init(&mut self) { + // Initialize shared memory for logging. + + let addr = CHIP.atcm_ram_base_address + CHIP.chip_ram_size - 4 - CHIP.socram_srmem_size; + let shared_addr = self.bus.bp_read32(addr).await; + debug!("shared_addr {:08x}", shared_addr); + + let mut shared = [0; SharedMemData::SIZE]; + self.bus.bp_read(shared_addr, &mut shared).await; + let shared = SharedMemData::from_bytes(&shared); + + self.log.addr = shared.console_addr + 8; + } + + #[cfg(feature = "firmware-logs")] + async fn log_read(&mut self) { + // Read log struct + let mut log = [0; SharedMemLog::SIZE]; + self.bus.bp_read(self.log.addr, &mut log).await; + let log = SharedMemLog::from_bytes(&log); + + let idx = log.idx as usize; + + // If pointer hasn't moved, no need to do anything. + if idx == self.log.last_idx { + return; + } + + // Read entire buf for now. We could read only what we need, but then we + // run into annoying alignment issues in `bp_read`. + let mut buf = [0; 0x400]; + self.bus.bp_read(log.buf, &mut buf).await; + + while self.log.last_idx != idx as usize { + let b = buf[self.log.last_idx]; + if b == b'\r' || b == b'\n' { + if self.log.buf_count != 0 { + let s = unsafe { core::str::from_utf8_unchecked(&self.log.buf[..self.log.buf_count]) }; + debug!("LOGS: {}", s); + self.log.buf_count = 0; + } + } else if self.log.buf_count < self.log.buf.len() { + self.log.buf[self.log.buf_count] = b; + self.log.buf_count += 1; + } + + self.log.last_idx += 1; + if self.log.last_idx == 0x400 { + self.log.last_idx = 0; + } + } + } + + pub async fn run(mut self) -> ! { + let mut buf = [0; 512]; + loop { + #[cfg(feature = "firmware-logs")] + self.log_read().await; + + if self.has_credit() { + let ioctl = self.ioctl_state.wait_pending(); + let tx = self.ch.tx_buf(); + let ev = self.bus.wait_for_event(); + + match select3(ioctl, tx, ev).await { + Either3::First(PendingIoctl { + buf: iobuf, + kind, + cmd, + iface, + }) => { + self.send_ioctl(kind, cmd, iface, unsafe { &*iobuf }).await; + self.check_status(&mut buf).await; + } + Either3::Second(packet) => { + trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)])); + + let mut buf = [0; 512]; + let buf8 = slice8_mut(&mut buf); + + // There MUST be 2 bytes of padding between the SDPCM and BDC headers. + // And ONLY for data packets! + // No idea why, but the firmware will append two zero bytes to the tx'd packets + // otherwise. If the packet is exactly 1514 bytes (the max MTU), this makes it + // be oversized and get dropped. + // WHD adds it here https://github.com/Infineon/wifi-host-driver/blob/c04fcbb6b0d049304f376cf483fd7b1b570c8cd5/WiFi_Host_Driver/src/include/whd_sdpcm.h#L90 + // and adds it to the header size her https://github.com/Infineon/wifi-host-driver/blob/c04fcbb6b0d049304f376cf483fd7b1b570c8cd5/WiFi_Host_Driver/src/whd_sdpcm.c#L597 + // ¯\_(ツ)_/¯ + const PADDING_SIZE: usize = 2; + let total_len = SdpcmHeader::SIZE + PADDING_SIZE + BdcHeader::SIZE + packet.len(); + + let seq = self.sdpcm_seq; + self.sdpcm_seq = self.sdpcm_seq.wrapping_add(1); + + let sdpcm_header = SdpcmHeader { + len: total_len as u16, // TODO does this len need to be rounded up to u32? + len_inv: !total_len as u16, + sequence: seq, + channel_and_flags: CHANNEL_TYPE_DATA, + next_length: 0, + header_length: (SdpcmHeader::SIZE + PADDING_SIZE) as _, + wireless_flow_control: 0, + bus_data_credit: 0, + reserved: [0, 0], + }; + + let bdc_header = BdcHeader { + flags: BDC_VERSION << BDC_VERSION_SHIFT, + priority: 0, + flags2: 0, + data_offset: 0, + }; + trace!("tx {:?}", sdpcm_header); + trace!(" {:?}", bdc_header); + + buf8[0..SdpcmHeader::SIZE].copy_from_slice(&sdpcm_header.to_bytes()); + buf8[SdpcmHeader::SIZE + PADDING_SIZE..][..BdcHeader::SIZE] + .copy_from_slice(&bdc_header.to_bytes()); + buf8[SdpcmHeader::SIZE + PADDING_SIZE + BdcHeader::SIZE..][..packet.len()] + .copy_from_slice(packet); + + let total_len = (total_len + 3) & !3; // round up to 4byte + + trace!(" {:02x}", Bytes(&buf8[..total_len.min(48)])); + + self.bus.wlan_write(&buf[..(total_len / 4)]).await; + self.ch.tx_done(); + self.check_status(&mut buf).await; + } + Either3::Third(()) => { + self.handle_irq(&mut buf).await; + } + } + } else { + warn!("TX stalled"); + self.bus.wait_for_event().await; + self.handle_irq(&mut buf).await; + } + } + } + + /// Wait for IRQ on F2 packet available + async fn handle_irq(&mut self, buf: &mut [u32; 512]) { + // Receive stuff + let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await; + trace!("irq{}", FormatInterrupt(irq)); + + if irq & IRQ_F2_PACKET_AVAILABLE != 0 { + self.check_status(buf).await; + } + + if irq & IRQ_DATA_UNAVAILABLE != 0 { + // TODO what should we do here? + warn!("IRQ DATA_UNAVAILABLE, clearing..."); + self.bus.write16(FUNC_BUS, REG_BUS_INTERRUPT, 1).await; + } + } + + /// Handle F2 events while status register is set + async fn check_status(&mut self, buf: &mut [u32; 512]) { + loop { + let status = self.bus.status(); + trace!("check status{}", FormatStatus(status)); + + if status & STATUS_F2_PKT_AVAILABLE != 0 { + let len = (status & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT; + self.bus.wlan_read(buf, len).await; + trace!("rx {:02x}", Bytes(&slice8_mut(buf)[..(len as usize).min(48)])); + self.rx(&mut slice8_mut(buf)[..len as usize]); + } else { + break; + } + } + } + + fn rx(&mut self, packet: &mut [u8]) { + let Some((sdpcm_header, payload)) = SdpcmHeader::parse(packet) else { return }; + + self.update_credit(&sdpcm_header); + + let channel = sdpcm_header.channel_and_flags & 0x0f; + + match channel { + CHANNEL_TYPE_CONTROL => { + let Some((cdc_header, response)) = CdcHeader::parse(payload) else { return; }; + trace!(" {:?}", cdc_header); + + if cdc_header.id == self.ioctl_id { + if cdc_header.status != 0 { + // TODO: propagate error instead + panic!("IOCTL error {}", cdc_header.status as i32); + } + + self.ioctl_state.ioctl_done(response); + } + } + CHANNEL_TYPE_EVENT => { + let Some((_, bdc_packet)) = BdcHeader::parse(payload) else { + warn!("BDC event, incomplete header"); + return; + }; + + let Some((event_packet, evt_data)) = EventPacket::parse(bdc_packet) else { + warn!("BDC event, incomplete data"); + return; + }; + + const ETH_P_LINK_CTL: u16 = 0x886c; // HPNA, wlan link local tunnel, according to linux if_ether.h + if event_packet.eth.ether_type != ETH_P_LINK_CTL { + warn!( + "unexpected ethernet type 0x{:04x}, expected Broadcom ether type 0x{:04x}", + event_packet.eth.ether_type, ETH_P_LINK_CTL + ); + return; + } + const BROADCOM_OUI: &[u8] = &[0x00, 0x10, 0x18]; + if event_packet.hdr.oui != BROADCOM_OUI { + warn!( + "unexpected ethernet OUI {:02x}, expected Broadcom OUI {:02x}", + Bytes(&event_packet.hdr.oui), + Bytes(BROADCOM_OUI) + ); + return; + } + const BCMILCP_SUBTYPE_VENDOR_LONG: u16 = 32769; + if event_packet.hdr.subtype != BCMILCP_SUBTYPE_VENDOR_LONG { + warn!("unexpected subtype {}", event_packet.hdr.subtype); + return; + } + + const BCMILCP_BCM_SUBTYPE_EVENT: u16 = 1; + if event_packet.hdr.user_subtype != BCMILCP_BCM_SUBTYPE_EVENT { + warn!("unexpected user_subtype {}", event_packet.hdr.subtype); + return; + } + + let evt_type = events::Event::from(event_packet.msg.event_type as u8); + debug!( + "=== EVENT {:?}: {:?} {:02x}", + evt_type, + event_packet.msg, + Bytes(evt_data) + ); + + if self.events.mask.is_enabled(evt_type) { + let status = event_packet.msg.status; + let event_payload = match evt_type { + Event::ESCAN_RESULT if status == EStatus::PARTIAL => { + let Some((_, bss_info)) = ScanResults::parse(evt_data) else { return }; + let Some(bss_info) = BssInfo::parse(bss_info) else { return }; + events::Payload::BssInfo(*bss_info) + } + Event::ESCAN_RESULT => events::Payload::None, + _ => events::Payload::None, + }; + + // this intentionally uses the non-blocking publish immediate + // publish() is a deadlock risk in the current design as awaiting here prevents ioctls + // The `Runner` always yields when accessing the device, so consumers always have a chance to receive the event + // (if they are actively awaiting the queue) + self.events.queue.publish_immediate(events::Message::new( + Status { + event_type: evt_type, + status, + }, + event_payload, + )); + } + } + CHANNEL_TYPE_DATA => { + let Some((_, packet)) = BdcHeader::parse(payload) else { return }; + trace!("rx pkt {:02x}", Bytes(&packet[..packet.len().min(48)])); + + match self.ch.try_rx_buf() { + Some(buf) => { + buf[..packet.len()].copy_from_slice(packet); + self.ch.rx_done(packet.len()) + } + None => warn!("failed to push rxd packet to the channel."), + } + } + _ => {} + } + } + + fn update_credit(&mut self, sdpcm_header: &SdpcmHeader) { + if sdpcm_header.channel_and_flags & 0xf < 3 { + let mut sdpcm_seq_max = sdpcm_header.bus_data_credit; + if sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) > 0x40 { + sdpcm_seq_max = self.sdpcm_seq + 2; + } + self.sdpcm_seq_max = sdpcm_seq_max; + } + } + + fn has_credit(&self) -> bool { + self.sdpcm_seq != self.sdpcm_seq_max && self.sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) & 0x80 == 0 + } + + async fn send_ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, data: &[u8]) { + let mut buf = [0; 512]; + let buf8 = slice8_mut(&mut buf); + + let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len(); + + let sdpcm_seq = self.sdpcm_seq; + self.sdpcm_seq = self.sdpcm_seq.wrapping_add(1); + self.ioctl_id = self.ioctl_id.wrapping_add(1); + + let sdpcm_header = SdpcmHeader { + len: total_len as u16, // TODO does this len need to be rounded up to u32? + len_inv: !total_len as u16, + sequence: sdpcm_seq, + channel_and_flags: CHANNEL_TYPE_CONTROL, + next_length: 0, + header_length: SdpcmHeader::SIZE as _, + wireless_flow_control: 0, + bus_data_credit: 0, + reserved: [0, 0], + }; + + let cdc_header = CdcHeader { + cmd: cmd, + len: data.len() as _, + flags: kind as u16 | (iface as u16) << 12, + id: self.ioctl_id, + status: 0, + }; + trace!("tx {:?}", sdpcm_header); + trace!(" {:?}", cdc_header); + + buf8[0..SdpcmHeader::SIZE].copy_from_slice(&sdpcm_header.to_bytes()); + buf8[SdpcmHeader::SIZE..][..CdcHeader::SIZE].copy_from_slice(&cdc_header.to_bytes()); + buf8[SdpcmHeader::SIZE + CdcHeader::SIZE..][..data.len()].copy_from_slice(data); + + let total_len = (total_len + 3) & !3; // round up to 4byte + + trace!(" {:02x}", Bytes(&buf8[..total_len.min(48)])); + + self.bus.wlan_write(&buf[..total_len / 4]).await; + } + + async fn core_disable(&mut self, core: Core) { + let base = core.base_addr(); + + // Dummy read? + let _ = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await; + + // Check it isn't already reset + let r = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await; + if r & AI_RESETCTRL_BIT_RESET != 0 { + return; + } + + self.bus.bp_write8(base + AI_IOCTRL_OFFSET, 0).await; + let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await; + + block_for(Duration::from_millis(1)); + + self.bus + .bp_write8(base + AI_RESETCTRL_OFFSET, AI_RESETCTRL_BIT_RESET) + .await; + let _ = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await; + } + + async fn core_reset(&mut self, core: Core) { + self.core_disable(core).await; + + let base = core.base_addr(); + self.bus + .bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_FGC | AI_IOCTRL_BIT_CLOCK_EN) + .await; + let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await; + + self.bus.bp_write8(base + AI_RESETCTRL_OFFSET, 0).await; + + Timer::after(Duration::from_millis(1)).await; + + self.bus + .bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_CLOCK_EN) + .await; + let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await; + + Timer::after(Duration::from_millis(1)).await; + } + + async fn core_is_up(&mut self, core: Core) -> bool { + let base = core.base_addr(); + + let io = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await; + if io & (AI_IOCTRL_BIT_FGC | AI_IOCTRL_BIT_CLOCK_EN) != AI_IOCTRL_BIT_CLOCK_EN { + debug!("core_is_up: returning false due to bad ioctrl {:02x}", io); + return false; + } + + let r = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await; + if r & (AI_RESETCTRL_BIT_RESET) != 0 { + debug!("core_is_up: returning false due to bad resetctrl {:02x}", r); + return false; + } + + true + } +} diff --git a/cyw43/src/structs.rs b/cyw43/src/structs.rs new file mode 100644 index 000000000..5ba633c74 --- /dev/null +++ b/cyw43/src/structs.rs @@ -0,0 +1,496 @@ +use crate::events::Event; +use crate::fmt::Bytes; + +macro_rules! impl_bytes { + ($t:ident) => { + impl $t { + pub const SIZE: usize = core::mem::size_of::(); + + #[allow(unused)] + pub fn to_bytes(&self) -> [u8; Self::SIZE] { + unsafe { core::mem::transmute(*self) } + } + + #[allow(unused)] + pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> &Self { + let alignment = core::mem::align_of::(); + assert_eq!( + bytes.as_ptr().align_offset(alignment), + 0, + "{} is not aligned", + core::any::type_name::() + ); + unsafe { core::mem::transmute(bytes) } + } + + #[allow(unused)] + pub fn from_bytes_mut(bytes: &mut [u8; Self::SIZE]) -> &mut Self { + let alignment = core::mem::align_of::(); + assert_eq!( + bytes.as_ptr().align_offset(alignment), + 0, + "{} is not aligned", + core::any::type_name::() + ); + + unsafe { core::mem::transmute(bytes) } + } + } + }; +} + +#[derive(Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(C)] +pub struct SharedMemData { + pub flags: u32, + pub trap_addr: u32, + pub assert_exp_addr: u32, + pub assert_file_addr: u32, + pub assert_line: u32, + pub console_addr: u32, + pub msgtrace_addr: u32, + pub fwid: u32, +} +impl_bytes!(SharedMemData); + +#[derive(Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(C)] +pub struct SharedMemLog { + pub buf: u32, + pub buf_size: u32, + pub idx: u32, + pub out_idx: u32, +} +impl_bytes!(SharedMemLog); + +#[derive(Debug, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(C)] +pub struct SdpcmHeader { + pub len: u16, + pub len_inv: u16, + /// Rx/Tx sequence number + pub sequence: u8, + /// 4 MSB Channel number, 4 LSB arbitrary flag + pub channel_and_flags: u8, + /// Length of next data frame, reserved for Tx + pub next_length: u8, + /// Data offset + pub header_length: u8, + /// Flow control bits, reserved for Tx + pub wireless_flow_control: u8, + /// Maximum Sequence number allowed by firmware for Tx + pub bus_data_credit: u8, + /// Reserved + pub reserved: [u8; 2], +} +impl_bytes!(SdpcmHeader); + +impl SdpcmHeader { + pub fn parse(packet: &mut [u8]) -> Option<(&mut Self, &mut [u8])> { + let packet_len = packet.len(); + if packet_len < Self::SIZE { + warn!("packet too short, len={}", packet.len()); + return None; + } + let (sdpcm_header, sdpcm_packet) = packet.split_at_mut(Self::SIZE); + let sdpcm_header = Self::from_bytes_mut(sdpcm_header.try_into().unwrap()); + trace!("rx {:?}", sdpcm_header); + + if sdpcm_header.len != !sdpcm_header.len_inv { + warn!("len inv mismatch"); + return None; + } + + if sdpcm_header.len as usize != packet_len { + warn!("len from header doesn't match len from spi"); + return None; + } + + let sdpcm_packet = &mut sdpcm_packet[(sdpcm_header.header_length as usize - Self::SIZE)..]; + Some((sdpcm_header, sdpcm_packet)) + } +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed(2))] +pub struct CdcHeader { + pub cmd: u32, + pub len: u32, + pub flags: u16, + pub id: u16, + pub status: u32, +} +impl_bytes!(CdcHeader); + +#[cfg(feature = "defmt")] +impl defmt::Format for CdcHeader { + fn format(&self, fmt: defmt::Formatter) { + fn copy(t: T) -> T { + t + } + + defmt::write!( + fmt, + "CdcHeader{{cmd: {=u32:08x}, len: {=u32:08x}, flags: {=u16:04x}, id: {=u16:04x}, status: {=u32:08x}}}", + copy(self.cmd), + copy(self.len), + copy(self.flags), + copy(self.id), + copy(self.status), + ) + } +} + +impl CdcHeader { + pub fn parse(packet: &mut [u8]) -> Option<(&mut Self, &mut [u8])> { + if packet.len() < Self::SIZE { + warn!("payload too short, len={}", packet.len()); + return None; + } + + let (cdc_header, payload) = packet.split_at_mut(Self::SIZE); + let cdc_header = Self::from_bytes_mut(cdc_header.try_into().unwrap()); + + let payload = &mut payload[..cdc_header.len as usize]; + Some((cdc_header, payload)) + } +} + +pub const BDC_VERSION: u8 = 2; +pub const BDC_VERSION_SHIFT: u8 = 4; + +#[derive(Debug, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(C)] +pub struct BdcHeader { + pub flags: u8, + /// 802.1d Priority (low 3 bits) + pub priority: u8, + pub flags2: u8, + /// Offset from end of BDC header to packet data, in 4-uint8_t words. Leaves room for optional headers. + pub data_offset: u8, +} +impl_bytes!(BdcHeader); + +impl BdcHeader { + pub fn parse(packet: &mut [u8]) -> Option<(&mut Self, &mut [u8])> { + if packet.len() < Self::SIZE { + return None; + } + + let (bdc_header, bdc_packet) = packet.split_at_mut(Self::SIZE); + let bdc_header = Self::from_bytes_mut(bdc_header.try_into().unwrap()); + trace!(" {:?}", bdc_header); + + let packet_start = 4 * bdc_header.data_offset as usize; + + let bdc_packet = bdc_packet.get_mut(packet_start..)?; + trace!(" {:02x}", Bytes(&bdc_packet[..bdc_packet.len().min(36)])); + + Some((bdc_header, bdc_packet)) + } +} + +#[derive(Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(C)] +pub struct EthernetHeader { + pub destination_mac: [u8; 6], + pub source_mac: [u8; 6], + pub ether_type: u16, +} + +impl EthernetHeader { + pub fn byteswap(&mut self) { + self.ether_type = self.ether_type.to_be(); + } +} + +#[derive(Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(C)] +pub struct EventHeader { + pub subtype: u16, + pub length: u16, + pub version: u8, + pub oui: [u8; 3], + pub user_subtype: u16, +} + +impl EventHeader { + pub fn byteswap(&mut self) { + self.subtype = self.subtype.to_be(); + self.length = self.length.to_be(); + self.user_subtype = self.user_subtype.to_be(); + } +} + +#[derive(Debug, Clone, Copy)] +// #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(C, packed(2))] +pub struct EventMessage { + /// version + pub version: u16, + /// see flags below + pub flags: u16, + /// Message (see below) + pub event_type: u32, + /// Status code (see below) + pub status: u32, + /// Reason code (if applicable) + pub reason: u32, + /// WLC_E_AUTH + pub auth_type: u32, + /// data buf + pub datalen: u32, + /// Station address (if applicable) + pub addr: [u8; 6], + /// name of the incoming packet interface + pub ifname: [u8; 16], + /// destination OS i/f index + pub ifidx: u8, + /// source bsscfg index + pub bsscfgidx: u8, +} +impl_bytes!(EventMessage); + +#[cfg(feature = "defmt")] +impl defmt::Format for EventMessage { + fn format(&self, fmt: defmt::Formatter) { + let event_type = self.event_type; + let status = self.status; + let reason = self.reason; + let auth_type = self.auth_type; + let datalen = self.datalen; + + defmt::write!( + fmt, + "EventMessage {{ \ + version: {=u16}, \ + flags: {=u16}, \ + event_type: {=u32}, \ + status: {=u32}, \ + reason: {=u32}, \ + auth_type: {=u32}, \ + datalen: {=u32}, \ + addr: {=[u8; 6]:x}, \ + ifname: {=[u8; 16]:x}, \ + ifidx: {=u8}, \ + bsscfgidx: {=u8}, \ + }} ", + self.version, + self.flags, + event_type, + status, + reason, + auth_type, + datalen, + self.addr, + self.ifname, + self.ifidx, + self.bsscfgidx + ); + } +} + +impl EventMessage { + pub fn byteswap(&mut self) { + self.version = self.version.to_be(); + self.flags = self.flags.to_be(); + self.event_type = self.event_type.to_be(); + self.status = self.status.to_be(); + self.reason = self.reason.to_be(); + self.auth_type = self.auth_type.to_be(); + self.datalen = self.datalen.to_be(); + } +} + +#[derive(Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(C, packed(2))] +pub struct EventPacket { + pub eth: EthernetHeader, + pub hdr: EventHeader, + pub msg: EventMessage, +} +impl_bytes!(EventPacket); + +impl EventPacket { + pub fn parse(packet: &mut [u8]) -> Option<(&mut Self, &mut [u8])> { + if packet.len() < Self::SIZE { + return None; + } + + let (event_header, event_packet) = packet.split_at_mut(Self::SIZE); + let event_header = Self::from_bytes_mut(event_header.try_into().unwrap()); + // warn!("event_header {:x}", event_header as *const _); + event_header.byteswap(); + + let event_packet = event_packet.get_mut(..event_header.msg.datalen as usize)?; + + Some((event_header, event_packet)) + } + + pub fn byteswap(&mut self) { + self.eth.byteswap(); + self.hdr.byteswap(); + self.msg.byteswap(); + } +} + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct DownloadHeader { + pub flag: u16, // + pub dload_type: u16, + pub len: u32, + pub crc: u32, +} +impl_bytes!(DownloadHeader); + +#[allow(unused)] +pub const DOWNLOAD_FLAG_NO_CRC: u16 = 0x0001; +pub const DOWNLOAD_FLAG_BEGIN: u16 = 0x0002; +pub const DOWNLOAD_FLAG_END: u16 = 0x0004; +pub const DOWNLOAD_FLAG_HANDLER_VER: u16 = 0x1000; + +// Country Locale Matrix (CLM) +pub const DOWNLOAD_TYPE_CLM: u16 = 2; + +#[derive(Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(C)] +pub struct CountryInfo { + pub country_abbrev: [u8; 4], + pub rev: i32, + pub country_code: [u8; 4], +} +impl_bytes!(CountryInfo); + +#[derive(Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(C)] +pub struct SsidInfo { + pub len: u32, + pub ssid: [u8; 32], +} +impl_bytes!(SsidInfo); + +#[derive(Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(C)] +pub struct PassphraseInfo { + pub len: u16, + pub flags: u16, + pub passphrase: [u8; 64], +} +impl_bytes!(PassphraseInfo); + +#[derive(Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(C)] +pub struct SsidInfoWithIndex { + pub index: u32, + pub ssid_info: SsidInfo, +} +impl_bytes!(SsidInfoWithIndex); + +#[derive(Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(C)] +pub struct EventMask { + pub iface: u32, + pub events: [u8; 24], +} +impl_bytes!(EventMask); + +impl EventMask { + pub fn unset(&mut self, evt: Event) { + let evt = evt as u8 as usize; + self.events[evt / 8] &= !(1 << (evt % 8)); + } +} + +/// Parameters for a wifi scan +#[derive(Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(C)] +pub struct ScanParams { + pub version: u32, + pub action: u16, + pub sync_id: u16, + pub ssid_len: u32, + pub ssid: [u8; 32], + pub bssid: [u8; 6], + pub bss_type: u8, + pub scan_type: u8, + pub nprobes: u32, + pub active_time: u32, + pub passive_time: u32, + pub home_time: u32, + pub channel_num: u32, + pub channel_list: [u16; 1], +} +impl_bytes!(ScanParams); + +/// Wifi Scan Results Header, followed by `bss_count` `BssInfo` +#[derive(Clone, Copy)] +// #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(C, packed(2))] +pub struct ScanResults { + pub buflen: u32, + pub version: u32, + pub sync_id: u16, + pub bss_count: u16, +} +impl_bytes!(ScanResults); + +impl ScanResults { + pub fn parse(packet: &mut [u8]) -> Option<(&mut ScanResults, &mut [u8])> { + if packet.len() < ScanResults::SIZE { + return None; + } + + let (scan_results, bssinfo) = packet.split_at_mut(ScanResults::SIZE); + let scan_results = ScanResults::from_bytes_mut(scan_results.try_into().unwrap()); + + if scan_results.bss_count > 0 && bssinfo.len() < BssInfo::SIZE { + warn!("Scan result, incomplete BssInfo"); + return None; + } + + Some((scan_results, bssinfo)) + } +} + +/// Wifi Scan Result +#[derive(Clone, Copy)] +// #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(C, packed(2))] +#[non_exhaustive] +pub struct BssInfo { + pub version: u32, + pub length: u32, + pub bssid: [u8; 6], + pub beacon_period: u16, + pub capability: u16, + pub ssid_len: u8, + pub ssid: [u8; 32], + // there will be more stuff here +} +impl_bytes!(BssInfo); + +impl BssInfo { + pub fn parse(packet: &mut [u8]) -> Option<&mut Self> { + if packet.len() < BssInfo::SIZE { + return None; + } + + Some(BssInfo::from_bytes_mut( + packet[..BssInfo::SIZE].as_mut().try_into().unwrap(), + )) + } +} diff --git a/examples/rpi-pico-w/Cargo.lock b/examples/rpi-pico-w/Cargo.lock new file mode 100644 index 000000000..16095835b --- /dev/null +++ b/examples/rpi-pico-w/Cargo.lock @@ -0,0 +1,1707 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +dependencies = [ + "memchr", +] + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "as-slice" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45403b49e3954a4b8428a0ac21a4b7afadccf92bfd96273f1a58cd4812496ae0" +dependencies = [ + "generic-array 0.12.4", + "generic-array 0.13.3", + "generic-array 0.14.7", + "stable_deref_trait", +] + +[[package]] +name = "as-slice" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "ascii-canvas" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] + +[[package]] +name = "atomic-polyfill" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28" +dependencies = [ + "critical-section 1.1.1", +] + +[[package]] +name = "atomic-polyfill" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c314e70d181aa6053b26e3f7fbf86d1dfff84f816a6175b967666b3506ef7289" +dependencies = [ + "critical-section 1.1.1", +] + +[[package]] +name = "atomic-pool" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c5fc22e05ec2884db458bf307dc7b278c9428888d2b6e6fad9c0ae7804f5f6" +dependencies = [ + "as-slice 0.1.5", + "as-slice 0.2.1", + "atomic-polyfill 1.0.2", + "stable_deref_trait", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "az" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" + +[[package]] +name = "bare-metal" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" +dependencies = [ + "rustc_version 0.2.3", +] + +[[package]] +name = "bare-metal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603" + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bytemuck" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "cortex-m" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" +dependencies = [ + "bare-metal 0.2.5", + "bitfield", + "critical-section 1.1.1", + "embedded-hal 0.2.7", + "volatile-register", +] + +[[package]] +name = "cortex-m-rt" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee84e813d593101b1723e13ec38b6ab6abbdbaaa4546553f5395ed274079ddb1" +dependencies = [ + "cortex-m-rt-macros", +] + +[[package]] +name = "cortex-m-rt-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f6f3e36f203cfedbc78b357fb28730aa2c6dc1ab060ee5c2405e843988d3c7" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "crc-any" +version = "2.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "774646b687f63643eb0f4bf13dc263cb581c8c9e57973b6ddf78bda3994d88df" +dependencies = [ + "debug-helper", +] + +[[package]] +name = "critical-section" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1706d332edc22aef4d9f23a6bb1c92360a403013c291af51247a737472dcae6" +dependencies = [ + "bare-metal 1.0.0", + "critical-section 1.1.1", +] + +[[package]] +name = "critical-section" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6548a0ad5d2549e111e1f6a11a6c2e2d00ce6a3dafe22948d67c2b443f775e52" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "cyw43" +version = "0.1.0" +dependencies = [ + "atomic-polyfill 0.1.11", + "cortex-m", + "cortex-m-rt", + "defmt", + "embassy-futures", + "embassy-net-driver-channel", + "embassy-sync", + "embassy-time", + "embedded-hal 1.0.0-alpha.10", + "futures", + "num_enum", +] + +[[package]] +name = "cyw43-example-rpi-pico-w" +version = "0.1.0" +dependencies = [ + "atomic-polyfill 0.1.11", + "cortex-m", + "cortex-m-rt", + "cyw43", + "cyw43-pio", + "defmt", + "defmt-rtt", + "embassy-executor", + "embassy-net", + "embassy-rp", + "embassy-time", + "embedded-io", + "futures", + "heapless", + "panic-probe", + "static_cell", +] + +[[package]] +name = "cyw43-pio" +version = "0.1.0" +dependencies = [ + "cyw43", + "defmt", + "embassy-rp", + "fixed", + "pio", + "pio-proc", +] + +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "debug-helper" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f578e8e2c440e7297e008bb5486a3a8a194775224bbc23729b0dbdfaeebf162e" + +[[package]] +name = "defmt" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956673bd3cb347512bf988d1e8d89ac9a82b64f6eec54d3c01c3529dac019882" +dependencies = [ + "bitflags", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4abc4821bd84d3d8f49945ddb24d029be9385ed9b77c99bf2f6296847a6a9f0" +dependencies = [ + "defmt-parser", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "defmt-parser" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "269924c02afd7f94bc4cecbfa5c379f6ffcf9766b3408fe63d22c728654eccd0" +dependencies = [ + "thiserror", +] + +[[package]] +name = "defmt-rtt" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2cbbbd58847d508d97629b32cd9730a2d28532f71e219714614406029f18b1" +dependencies = [ + "critical-section 0.2.8", + "defmt", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "embassy-cortex-m" +version = "0.1.0" +source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" +dependencies = [ + "atomic-polyfill 1.0.2", + "cfg-if", + "cortex-m", + "critical-section 1.1.1", + "embassy-executor", + "embassy-hal-common", + "embassy-macros", + "embassy-sync", +] + +[[package]] +name = "embassy-embedded-hal" +version = "0.1.0" +source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" +dependencies = [ + "embassy-sync", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0-alpha.10", + "embedded-hal-async", + "embedded-storage", + "embedded-storage-async", + "nb 1.1.0", +] + +[[package]] +name = "embassy-executor" +version = "0.2.0" +source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" +dependencies = [ + "atomic-polyfill 1.0.2", + "cortex-m", + "critical-section 1.1.1", + "defmt", + "embassy-macros", + "embassy-time", + "futures-util", + "static_cell", +] + +[[package]] +name = "embassy-futures" +version = "0.1.0" +source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" + +[[package]] +name = "embassy-hal-common" +version = "0.1.0" +source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" +dependencies = [ + "defmt", + "num-traits", +] + +[[package]] +name = "embassy-macros" +version = "0.2.0" +source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "embassy-net" +version = "0.1.0" +source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" +dependencies = [ + "as-slice 0.2.1", + "atomic-polyfill 1.0.2", + "atomic-pool", + "defmt", + "embassy-hal-common", + "embassy-net-driver", + "embassy-sync", + "embassy-time", + "embedded-io", + "embedded-nal-async", + "futures", + "generic-array 0.14.7", + "heapless", + "managed", + "smoltcp", + "stable_deref_trait", +] + +[[package]] +name = "embassy-net-driver" +version = "0.1.0" +source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" +dependencies = [ + "defmt", +] + +[[package]] +name = "embassy-net-driver-channel" +version = "0.1.0" +source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" +dependencies = [ + "embassy-futures", + "embassy-net-driver", + "embassy-sync", +] + +[[package]] +name = "embassy-rp" +version = "0.1.0" +source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" +dependencies = [ + "atomic-polyfill 1.0.2", + "cfg-if", + "cortex-m", + "cortex-m-rt", + "critical-section 1.1.1", + "defmt", + "embassy-cortex-m", + "embassy-embedded-hal", + "embassy-executor", + "embassy-futures", + "embassy-hal-common", + "embassy-sync", + "embassy-time", + "embassy-usb-driver", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0-alpha.10", + "embedded-hal-async", + "embedded-hal-nb", + "embedded-io", + "embedded-storage", + "fixed", + "futures", + "nb 1.1.0", + "paste", + "pio", + "pio-proc", + "rand_core", + "rp-pac", + "rp2040-boot2", +] + +[[package]] +name = "embassy-sync" +version = "0.2.0" +source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" +dependencies = [ + "cfg-if", + "critical-section 1.1.1", + "embedded-io", + "futures-util", + "heapless", +] + +[[package]] +name = "embassy-time" +version = "0.1.1" +source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" +dependencies = [ + "atomic-polyfill 1.0.2", + "cfg-if", + "critical-section 1.1.1", + "defmt", + "embedded-hal 0.2.7", + "futures-util", + "heapless", +] + +[[package]] +name = "embassy-usb-driver" +version = "0.1.0" +source = "git+https://github.com/embassy-rs/embassy?rev=82f7e104d90a6628d1873017ea5ef6a7afb3b3f7#82f7e104d90a6628d1873017ea5ef6a7afb3b3f7" +dependencies = [ + "defmt", +] + +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "embedded-hal" +version = "1.0.0-alpha.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f65c4d073f5d91c66e629b216818a4c9747eeda0debedf2deda9a0a947e4e93b" + +[[package]] +name = "embedded-hal-async" +version = "0.2.0-alpha.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8042370aa7af48de36d5312cda14c18ed8ca6b7ce64f5a07832fedc9dc83063f" +dependencies = [ + "embedded-hal 1.0.0-alpha.10", +] + +[[package]] +name = "embedded-hal-nb" +version = "1.0.0-alpha.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465fffd56a95bbc105c17965bca1c1d5815027b1cc6bb183bc05d04563d065c" +dependencies = [ + "embedded-hal 1.0.0-alpha.10", + "nb 1.1.0", +] + +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" +dependencies = [ + "defmt", +] + +[[package]] +name = "embedded-nal" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db9efecb57ab54fa918730f2874d7d37647169c50fa1357fecb81abee840b113" +dependencies = [ + "heapless", + "nb 1.1.0", + "no-std-net 0.5.0", +] + +[[package]] +name = "embedded-nal-async" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27ce84f518ca912777ec143db235f4d615e3bf8d4e46d507d6ef12daf5b1df98" +dependencies = [ + "embedded-io", + "embedded-nal", + "heapless", + "no-std-net 0.6.0", +] + +[[package]] +name = "embedded-storage" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "156d7a2fdd98ebbf9ae579cbceca3058cff946e13f8e17b90e3511db0508c723" + +[[package]] +name = "embedded-storage-async" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052997a894670d0cde873faa7405bc98e2fd29f569d2acd568561bc1c396b35a" +dependencies = [ + "embedded-storage", +] + +[[package]] +name = "ena" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +dependencies = [ + "log", +] + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fixed" +version = "1.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79386fdcec5e0fde91b1a6a5bcd89677d1f9304f7f986b154a1b9109038854d9" +dependencies = [ + "az", + "bytemuck", + "half", + "typenum", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-core", + "futures-macro", + "futures-sink", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f797e67af32588215eaaab8327027ee8e71b9dd0b2b26996aedf20c030fce309" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "half" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0" +dependencies = [ + "crunchy", +] + +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "heapless" +version = "0.7.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743" +dependencies = [ + "atomic-polyfill 0.1.11", + "defmt", + "hash32", + "rustc_version 0.4.0", + "spin", + "stable_deref_trait", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "is-terminal" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +dependencies = [ + "hermit-abi", + "io-lifetimes", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "lalrpop" +version = "0.19.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a1cbf952127589f2851ab2046af368fd20645491bb4b376f04b7f94d7a9837b" +dependencies = [ + "ascii-canvas", + "bit-set", + "diff", + "ena", + "is-terminal", + "itertools", + "lalrpop-util", + "petgraph", + "regex", + "regex-syntax 0.6.29", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "lalrpop-util" +version = "0.19.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3c48237b9604c5a4702de6b824e02006c3214327564636aef27c1028a8fa0ed" +dependencies = [ + "regex", +] + +[[package]] +name = "libc" +version = "0.2.144" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" + +[[package]] +name = "managed" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + +[[package]] +name = "no-std-net" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bcece43b12349917e096cddfa66107277f123e6c96a5aea78711dc601a47152" + +[[package]] +name = "no-std-net" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "once_cell" +version = "1.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" + +[[package]] +name = "panic-probe" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa6fa5645ef5a760cd340eaa92af9c1ce131c8c09e7f8926d8a24b59d26652b9" +dependencies = [ + "cortex-m", + "defmt", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys 0.45.0", +] + +[[package]] +name = "paste" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" + +[[package]] +name = "petgraph" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pio" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76e09694b50f89f302ed531c1f2a7569f0be5867aee4ab4f8f729bbeec0078e3" +dependencies = [ + "arrayvec", + "num_enum", + "paste", +] + +[[package]] +name = "pio-parser" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77532c2b8279aef98dfc7207ef15298a5a3d6b6cc76ccc8b65913d69f3a8dd6b" +dependencies = [ + "lalrpop", + "lalrpop-util", + "pio", + "regex-syntax 0.6.29", +] + +[[package]] +name = "pio-proc" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b04dc870fb3a4fd8b3e4ca8c61b53bc8ac4eb78b66805d2b3c2e5c4829e0d7a" +dependencies = [ + "codespan-reporting", + "lalrpop-util", + "pio", + "pio-parser", + "proc-macro-error", + "proc-macro2", + "quote", + "regex-syntax 0.6.29", + "syn 1.0.109", +] + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.7.2", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" + +[[package]] +name = "rp-pac" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76e426cd8377db668fba1fe885028788b126b7cef91059cd478de8b076c2915" +dependencies = [ + "cortex-m", + "cortex-m-rt", +] + +[[package]] +name = "rp2040-boot2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c92f344f63f950ee36cf4080050e4dce850839b9175da38f9d2ffb69b4dbb21" +dependencies = [ + "crc-any", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.17", +] + +[[package]] +name = "rustix" +version = "0.37.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustversion" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "smoltcp" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e9786ac45091b96f946693e05bfa4d8ca93e2d3341237d97a380107a6b38dea" +dependencies = [ + "bitflags", + "byteorder", + "cfg-if", + "defmt", + "heapless", + "managed", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_cell" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c37c250d21f53fa7165e76e5401d7e6539c211a8d2cf449e3962956a5cc2ce" +dependencies = [ + "atomic-polyfill 1.0.2", +] + +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared", + "precomputed-hash", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "unicode-ident" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "vcell" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "volatile-register" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6" +dependencies = [ + "vcell", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" diff --git a/examples/rpi-pico-w/Cargo.toml b/examples/rpi-pico-w/Cargo.toml index 525e934f4..d3ce3085e 100644 --- a/examples/rpi-pico-w/Cargo.toml +++ b/examples/rpi-pico-w/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] -cyw43 = { path = "../../", features = ["defmt", "firmware-logs"] } +cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] } embassy-executor = { version = "0.2.0", features = ["defmt", "integrated-timers", "executor-thread", "arch-cortex-m"] } embassy-time = { version = "0.1.0", features = ["defmt", "defmt-timestamp-uptime"] } diff --git a/examples/rpi-pico-w/src/bin/tcp_server.rs b/examples/rpi-pico-w/src/bin/tcp_server.rs index 8accc469f..6a87e7c53 100644 --- a/examples/rpi-pico-w/src/bin/tcp_server.rs +++ b/examples/rpi-pico-w/src/bin/tcp_server.rs @@ -28,7 +28,11 @@ macro_rules! singleton { #[embassy_executor::task] async fn wifi_task( - runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, + runner: cyw43::Runner< + 'static, + Output<'static, PIN_23>, + PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>, + >, ) -> ! { runner.run().await } @@ -44,8 +48,8 @@ async fn main(spawner: Spawner) { let p = embassy_rp::init(Default::default()); - let fw = include_bytes!("../../../../firmware/43439A0.bin"); - let clm = include_bytes!("../../../../firmware/43439A0_clm.bin"); + let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin"); + let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin"); // To make flashing faster for development, you may want to flash the firmwares independently // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: @@ -57,7 +61,15 @@ async fn main(spawner: Spawner) { let pwr = Output::new(p.PIN_23, Level::Low); let cs = Output::new(p.PIN_25, Level::High); let mut pio = Pio::new(p.PIO0); - let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); + let spi = PioSpi::new( + &mut pio.common, + pio.sm0, + pio.irq0, + cs, + p.PIN_24, + p.PIN_29, + p.DMA_CH0, + ); let state = singleton!(cyw43::State::new()); let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; @@ -90,7 +102,10 @@ async fn main(spawner: Spawner) { loop { //control.join_open(env!("WIFI_NETWORK")).await; - match control.join_wpa2(env!("WIFI_NETWORK"), env!("WIFI_PASSWORD")).await { + match control + .join_wpa2(env!("WIFI_NETWORK"), env!("WIFI_PASSWORD")) + .await + { Ok(_) => break, Err(err) => { info!("join failed with status={}", err.status); diff --git a/examples/rpi-pico-w/src/bin/tcp_server_ap.rs b/examples/rpi-pico-w/src/bin/tcp_server_ap.rs index ee2c32379..24ff7767f 100644 --- a/examples/rpi-pico-w/src/bin/tcp_server_ap.rs +++ b/examples/rpi-pico-w/src/bin/tcp_server_ap.rs @@ -28,7 +28,11 @@ macro_rules! singleton { #[embassy_executor::task] async fn wifi_task( - runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, + runner: cyw43::Runner< + 'static, + Output<'static, PIN_23>, + PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>, + >, ) -> ! { runner.run().await } @@ -44,8 +48,8 @@ async fn main(spawner: Spawner) { let p = embassy_rp::init(Default::default()); - let fw = include_bytes!("../../../../firmware/43439A0.bin"); - let clm = include_bytes!("../../../../firmware/43439A0_clm.bin"); + let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin"); + let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin"); // To make flashing faster for development, you may want to flash the firmwares independently // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: @@ -57,7 +61,15 @@ async fn main(spawner: Spawner) { let pwr = Output::new(p.PIN_23, Level::Low); let cs = Output::new(p.PIN_25, Level::High); let mut pio = Pio::new(p.PIO0); - let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); + let spi = PioSpi::new( + &mut pio.common, + pio.sm0, + pio.irq0, + cs, + p.PIN_24, + p.PIN_29, + p.DMA_CH0, + ); let state = singleton!(cyw43::State::new()); let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; diff --git a/examples/rpi-pico-w/src/bin/wifi_scan.rs b/examples/rpi-pico-w/src/bin/wifi_scan.rs index a2a44f99d..8fb6c65aa 100644 --- a/examples/rpi-pico-w/src/bin/wifi_scan.rs +++ b/examples/rpi-pico-w/src/bin/wifi_scan.rs @@ -26,7 +26,11 @@ macro_rules! singleton { #[embassy_executor::task] async fn wifi_task( - runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>, + runner: cyw43::Runner< + 'static, + Output<'static, PIN_23>, + PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>, + >, ) -> ! { runner.run().await } @@ -42,8 +46,8 @@ async fn main(spawner: Spawner) { let p = embassy_rp::init(Default::default()); - let fw = include_bytes!("../../../../firmware/43439A0.bin"); - let clm = include_bytes!("../../../../firmware/43439A0_clm.bin"); + let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin"); + let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin"); // To make flashing faster for development, you may want to flash the firmwares independently // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: @@ -55,7 +59,15 @@ async fn main(spawner: Spawner) { let pwr = Output::new(p.PIN_23, Level::Low); let cs = Output::new(p.PIN_25, Level::High); let mut pio = Pio::new(p.PIO0); - let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); + let spi = PioSpi::new( + &mut pio.common, + pio.sm0, + pio.irq0, + cs, + p.PIN_24, + p.PIN_29, + p.DMA_CH0, + ); let state = singleton!(cyw43::State::new()); let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; diff --git a/firmware/43439A0.bin b/firmware/43439A0.bin deleted file mode 100755 index b46b3beff..000000000 Binary files a/firmware/43439A0.bin and /dev/null differ diff --git a/firmware/43439A0_clm.bin b/firmware/43439A0_clm.bin deleted file mode 100755 index 6e3ba786b..000000000 Binary files a/firmware/43439A0_clm.bin and /dev/null differ diff --git a/firmware/LICENSE-permissive-binary-license-1.0.txt b/firmware/LICENSE-permissive-binary-license-1.0.txt deleted file mode 100644 index cbb51f9c9..000000000 --- a/firmware/LICENSE-permissive-binary-license-1.0.txt +++ /dev/null @@ -1,49 +0,0 @@ -Permissive Binary License - -Version 1.0, July 2019 - -Redistribution. Redistribution and use in binary form, without -modification, are permitted provided that the following conditions are -met: - -1) Redistributions must reproduce the above copyright notice and the - following disclaimer in the documentation and/or other materials - provided with the distribution. - -2) Unless to the extent explicitly permitted by law, no reverse - engineering, decompilation, or disassembly of this software is - permitted. - -3) Redistribution as part of a software development kit must include the - accompanying file named �DEPENDENCIES� and any dependencies listed in - that file. - -4) Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -Limited patent license. The copyright holders (and contributors) grant a -worldwide, non-exclusive, no-charge, royalty-free patent license to -make, have made, use, offer to sell, sell, import, and otherwise -transfer this software, where such license applies only to those patent -claims licensable by the copyright holders (and contributors) that are -necessarily infringed by this software. This patent license shall not -apply to any combinations that include this software. No hardware is -licensed hereunder. - -If you institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the software -itself infringes your patent(s), then your rights granted under this -license shall terminate as of the date such litigation is filed. - -DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -CONTRIBUTORS "AS IS." ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT -NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/firmware/README.md b/firmware/README.md deleted file mode 100644 index 7381fdc56..000000000 --- a/firmware/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# WiFi firmware - -Firmware obtained from https://github.com/Infineon/wifi-host-driver/tree/master/WiFi_Host_Driver/resources/firmware/COMPONENT_43439 - -Licensed under the [Infineon Permissive Binary License](./LICENSE-permissive-binary-license-1.0.txt) \ No newline at end of file diff --git a/rust-toolchain.toml b/rust-toolchain.toml deleted file mode 100644 index 2582e88f5..000000000 --- a/rust-toolchain.toml +++ /dev/null @@ -1,8 +0,0 @@ -# Before upgrading check that everything is available on all tier1 targets here: -# https://rust-lang.github.io/rustup-components-history -[toolchain] -channel = "nightly-2023-04-18" -components = [ "rust-src", "rustfmt" ] -targets = [ - "thumbv6m-none-eabi", -] diff --git a/rustfmt.toml b/rustfmt.toml deleted file mode 100644 index 3639f4386..000000000 --- a/rustfmt.toml +++ /dev/null @@ -1,3 +0,0 @@ -group_imports = "StdExternalCrate" -imports_granularity = "Module" -max_width=120 \ No newline at end of file diff --git a/src/bus.rs b/src/bus.rs deleted file mode 100644 index e26f11120..000000000 --- a/src/bus.rs +++ /dev/null @@ -1,328 +0,0 @@ -use embassy_futures::yield_now; -use embassy_time::{Duration, Timer}; -use embedded_hal_1::digital::OutputPin; -use futures::FutureExt; - -use crate::consts::*; -use crate::slice8_mut; - -/// Custom Spi Trait that _only_ supports the bus operation of the cyw43 -/// Implementors are expected to hold the CS pin low during an operation. -pub trait SpiBusCyw43 { - /// Issues a write command on the bus - /// First 32 bits of `word` are expected to be a cmd word - async fn cmd_write(&mut self, write: &[u32]) -> u32; - - /// Issues a read command on the bus - /// `write` is expected to be a 32 bit cmd word - /// `read` will contain the response of the device - /// Backplane reads have a response delay that produces one extra unspecified word at the beginning of `read`. - /// Callers that want to read `n` word from the backplane, have to provide a slice that is `n+1` words long. - async fn cmd_read(&mut self, write: u32, read: &mut [u32]) -> u32; - - /// Wait for events from the Device. A typical implementation would wait for the IRQ pin to be high. - /// The default implementation always reports ready, resulting in active polling of the device. - async fn wait_for_event(&mut self) { - yield_now().await; - } -} - -pub(crate) struct Bus { - backplane_window: u32, - pwr: PWR, - spi: SPI, - status: u32, -} - -impl Bus -where - PWR: OutputPin, - SPI: SpiBusCyw43, -{ - pub(crate) fn new(pwr: PWR, spi: SPI) -> Self { - Self { - backplane_window: 0xAAAA_AAAA, - pwr, - spi, - status: 0, - } - } - - pub async fn init(&mut self) { - // Reset - self.pwr.set_low().unwrap(); - Timer::after(Duration::from_millis(20)).await; - self.pwr.set_high().unwrap(); - Timer::after(Duration::from_millis(250)).await; - - while self - .read32_swapped(REG_BUS_TEST_RO) - .inspect(|v| trace!("{:#x}", v)) - .await - != FEEDBEAD - {} - - self.write32_swapped(REG_BUS_TEST_RW, TEST_PATTERN).await; - let val = self.read32_swapped(REG_BUS_TEST_RW).await; - trace!("{:#x}", val); - assert_eq!(val, TEST_PATTERN); - - let val = self.read32_swapped(REG_BUS_CTRL).await; - trace!("{:#010b}", (val & 0xff)); - - // 32-bit word length, little endian (which is the default endianess). - self.write32_swapped( - REG_BUS_CTRL, - WORD_LENGTH_32 | HIGH_SPEED | INTERRUPT_HIGH | WAKE_UP | STATUS_ENABLE | INTERRUPT_WITH_STATUS, - ) - .await; - - let val = self.read8(FUNC_BUS, REG_BUS_CTRL).await; - trace!("{:#b}", val); - - let val = self.read32(FUNC_BUS, REG_BUS_TEST_RO).await; - trace!("{:#x}", val); - assert_eq!(val, FEEDBEAD); - let val = self.read32(FUNC_BUS, REG_BUS_TEST_RW).await; - trace!("{:#x}", val); - assert_eq!(val, TEST_PATTERN); - } - - pub async fn wlan_read(&mut self, buf: &mut [u32], len_in_u8: u32) { - let cmd = cmd_word(READ, INC_ADDR, FUNC_WLAN, 0, len_in_u8); - let len_in_u32 = (len_in_u8 as usize + 3) / 4; - - self.status = self.spi.cmd_read(cmd, &mut buf[..len_in_u32]).await; - } - - pub async fn wlan_write(&mut self, buf: &[u32]) { - let cmd = cmd_word(WRITE, INC_ADDR, FUNC_WLAN, 0, buf.len() as u32 * 4); - //TODO try to remove copy? - let mut cmd_buf = [0_u32; 513]; - cmd_buf[0] = cmd; - cmd_buf[1..][..buf.len()].copy_from_slice(buf); - - self.status = self.spi.cmd_write(&cmd_buf).await; - } - - #[allow(unused)] - pub async fn bp_read(&mut self, mut addr: u32, mut data: &mut [u8]) { - // It seems the HW force-aligns the addr - // to 2 if data.len() >= 2 - // to 4 if data.len() >= 4 - // To simplify, enforce 4-align for now. - assert!(addr % 4 == 0); - - // Backplane read buffer has one extra word for the response delay. - let mut buf = [0u32; BACKPLANE_MAX_TRANSFER_SIZE / 4 + 1]; - - while !data.is_empty() { - // Ensure transfer doesn't cross a window boundary. - let window_offs = addr & BACKPLANE_ADDRESS_MASK; - let window_remaining = BACKPLANE_WINDOW_SIZE - window_offs as usize; - - let len = data.len().min(BACKPLANE_MAX_TRANSFER_SIZE).min(window_remaining); - - self.backplane_set_window(addr).await; - - let cmd = cmd_word(READ, INC_ADDR, FUNC_BACKPLANE, window_offs, len as u32); - - // round `buf` to word boundary, add one extra word for the response delay - self.status = self.spi.cmd_read(cmd, &mut buf[..(len + 3) / 4 + 1]).await; - - // when writing out the data, we skip the response-delay byte - data[..len].copy_from_slice(&slice8_mut(&mut buf[1..])[..len]); - - // Advance ptr. - addr += len as u32; - data = &mut data[len..]; - } - } - - pub async fn bp_write(&mut self, mut addr: u32, mut data: &[u8]) { - // It seems the HW force-aligns the addr - // to 2 if data.len() >= 2 - // to 4 if data.len() >= 4 - // To simplify, enforce 4-align for now. - assert!(addr % 4 == 0); - - let mut buf = [0u32; BACKPLANE_MAX_TRANSFER_SIZE / 4 + 1]; - - while !data.is_empty() { - // Ensure transfer doesn't cross a window boundary. - let window_offs = addr & BACKPLANE_ADDRESS_MASK; - let window_remaining = BACKPLANE_WINDOW_SIZE - window_offs as usize; - - let len = data.len().min(BACKPLANE_MAX_TRANSFER_SIZE).min(window_remaining); - slice8_mut(&mut buf[1..])[..len].copy_from_slice(&data[..len]); - - self.backplane_set_window(addr).await; - - let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BACKPLANE, window_offs, len as u32); - buf[0] = cmd; - - self.status = self.spi.cmd_write(&buf[..(len + 3) / 4 + 1]).await; - - // Advance ptr. - addr += len as u32; - data = &data[len..]; - } - } - - pub async fn bp_read8(&mut self, addr: u32) -> u8 { - self.backplane_readn(addr, 1).await as u8 - } - - pub async fn bp_write8(&mut self, addr: u32, val: u8) { - self.backplane_writen(addr, val as u32, 1).await - } - - pub async fn bp_read16(&mut self, addr: u32) -> u16 { - self.backplane_readn(addr, 2).await as u16 - } - - #[allow(unused)] - pub async fn bp_write16(&mut self, addr: u32, val: u16) { - self.backplane_writen(addr, val as u32, 2).await - } - - #[allow(unused)] - pub async fn bp_read32(&mut self, addr: u32) -> u32 { - self.backplane_readn(addr, 4).await - } - - pub async fn bp_write32(&mut self, addr: u32, val: u32) { - self.backplane_writen(addr, val, 4).await - } - - async fn backplane_readn(&mut self, addr: u32, len: u32) -> u32 { - self.backplane_set_window(addr).await; - - let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK; - if len == 4 { - bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG - } - self.readn(FUNC_BACKPLANE, bus_addr, len).await - } - - async fn backplane_writen(&mut self, addr: u32, val: u32, len: u32) { - self.backplane_set_window(addr).await; - - let mut bus_addr = addr & BACKPLANE_ADDRESS_MASK; - if len == 4 { - bus_addr |= BACKPLANE_ADDRESS_32BIT_FLAG - } - self.writen(FUNC_BACKPLANE, bus_addr, val, len).await - } - - async fn backplane_set_window(&mut self, addr: u32) { - let new_window = addr & !BACKPLANE_ADDRESS_MASK; - - if (new_window >> 24) as u8 != (self.backplane_window >> 24) as u8 { - self.write8( - FUNC_BACKPLANE, - REG_BACKPLANE_BACKPLANE_ADDRESS_HIGH, - (new_window >> 24) as u8, - ) - .await; - } - if (new_window >> 16) as u8 != (self.backplane_window >> 16) as u8 { - self.write8( - FUNC_BACKPLANE, - REG_BACKPLANE_BACKPLANE_ADDRESS_MID, - (new_window >> 16) as u8, - ) - .await; - } - if (new_window >> 8) as u8 != (self.backplane_window >> 8) as u8 { - self.write8( - FUNC_BACKPLANE, - REG_BACKPLANE_BACKPLANE_ADDRESS_LOW, - (new_window >> 8) as u8, - ) - .await; - } - self.backplane_window = new_window; - } - - pub async fn read8(&mut self, func: u32, addr: u32) -> u8 { - self.readn(func, addr, 1).await as u8 - } - - pub async fn write8(&mut self, func: u32, addr: u32, val: u8) { - self.writen(func, addr, val as u32, 1).await - } - - pub async fn read16(&mut self, func: u32, addr: u32) -> u16 { - self.readn(func, addr, 2).await as u16 - } - - #[allow(unused)] - pub async fn write16(&mut self, func: u32, addr: u32, val: u16) { - self.writen(func, addr, val as u32, 2).await - } - - pub async fn read32(&mut self, func: u32, addr: u32) -> u32 { - self.readn(func, addr, 4).await - } - - #[allow(unused)] - pub async fn write32(&mut self, func: u32, addr: u32, val: u32) { - self.writen(func, addr, val, 4).await - } - - async fn readn(&mut self, func: u32, addr: u32, len: u32) -> u32 { - let cmd = cmd_word(READ, INC_ADDR, func, addr, len); - let mut buf = [0; 2]; - // if we are reading from the backplane, we need an extra word for the response delay - let len = if func == FUNC_BACKPLANE { 2 } else { 1 }; - - self.status = self.spi.cmd_read(cmd, &mut buf[..len]).await; - - // if we read from the backplane, the result is in the second word, after the response delay - if func == FUNC_BACKPLANE { - buf[1] - } else { - buf[0] - } - } - - async fn writen(&mut self, func: u32, addr: u32, val: u32, len: u32) { - let cmd = cmd_word(WRITE, INC_ADDR, func, addr, len); - - self.status = self.spi.cmd_write(&[cmd, val]).await; - } - - async fn read32_swapped(&mut self, addr: u32) -> u32 { - let cmd = cmd_word(READ, INC_ADDR, FUNC_BUS, addr, 4); - let cmd = swap16(cmd); - let mut buf = [0; 1]; - - self.status = self.spi.cmd_read(cmd, &mut buf).await; - - swap16(buf[0]) - } - - async fn write32_swapped(&mut self, addr: u32, val: u32) { - let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BUS, addr, 4); - let buf = [swap16(cmd), swap16(val)]; - - self.status = self.spi.cmd_write(&buf).await; - } - - pub async fn wait_for_event(&mut self) { - self.spi.wait_for_event().await; - } - - pub fn status(&self) -> u32 { - self.status - } -} - -fn swap16(x: u32) -> u32 { - x.rotate_left(16) -} - -fn cmd_word(write: bool, incr: bool, func: u32, addr: u32, len: u32) -> u32 { - (write as u32) << 31 | (incr as u32) << 30 | (func & 0b11) << 28 | (addr & 0x1FFFF) << 11 | (len & 0x7FF) -} diff --git a/src/consts.rs b/src/consts.rs deleted file mode 100644 index 1f6551589..000000000 --- a/src/consts.rs +++ /dev/null @@ -1,318 +0,0 @@ -#![allow(unused)] - -pub(crate) const FUNC_BUS: u32 = 0; -pub(crate) const FUNC_BACKPLANE: u32 = 1; -pub(crate) const FUNC_WLAN: u32 = 2; -pub(crate) const FUNC_BT: u32 = 3; - -pub(crate) const REG_BUS_CTRL: u32 = 0x0; -pub(crate) const REG_BUS_INTERRUPT: u32 = 0x04; // 16 bits - Interrupt status -pub(crate) const REG_BUS_INTERRUPT_ENABLE: u32 = 0x06; // 16 bits - Interrupt mask -pub(crate) const REG_BUS_STATUS: u32 = 0x8; -pub(crate) const REG_BUS_TEST_RO: u32 = 0x14; -pub(crate) const REG_BUS_TEST_RW: u32 = 0x18; -pub(crate) const REG_BUS_RESP_DELAY: u32 = 0x1c; -pub(crate) const WORD_LENGTH_32: u32 = 0x1; -pub(crate) const HIGH_SPEED: u32 = 0x10; -pub(crate) const INTERRUPT_HIGH: u32 = 1 << 5; -pub(crate) const WAKE_UP: u32 = 1 << 7; -pub(crate) const STATUS_ENABLE: u32 = 1 << 16; -pub(crate) const INTERRUPT_WITH_STATUS: u32 = 1 << 17; - -// SPI_STATUS_REGISTER bits -pub(crate) const STATUS_DATA_NOT_AVAILABLE: u32 = 0x00000001; -pub(crate) const STATUS_UNDERFLOW: u32 = 0x00000002; -pub(crate) const STATUS_OVERFLOW: u32 = 0x00000004; -pub(crate) const STATUS_F2_INTR: u32 = 0x00000008; -pub(crate) const STATUS_F3_INTR: u32 = 0x00000010; -pub(crate) const STATUS_F2_RX_READY: u32 = 0x00000020; -pub(crate) const STATUS_F3_RX_READY: u32 = 0x00000040; -pub(crate) const STATUS_HOST_CMD_DATA_ERR: u32 = 0x00000080; -pub(crate) const STATUS_F2_PKT_AVAILABLE: u32 = 0x00000100; -pub(crate) const STATUS_F2_PKT_LEN_MASK: u32 = 0x000FFE00; -pub(crate) const STATUS_F2_PKT_LEN_SHIFT: u32 = 9; -pub(crate) const STATUS_F3_PKT_AVAILABLE: u32 = 0x00100000; -pub(crate) const STATUS_F3_PKT_LEN_MASK: u32 = 0xFFE00000; -pub(crate) const STATUS_F3_PKT_LEN_SHIFT: u32 = 21; - -pub(crate) const REG_BACKPLANE_GPIO_SELECT: u32 = 0x10005; -pub(crate) const REG_BACKPLANE_GPIO_OUTPUT: u32 = 0x10006; -pub(crate) const REG_BACKPLANE_GPIO_ENABLE: u32 = 0x10007; -pub(crate) const REG_BACKPLANE_FUNCTION2_WATERMARK: u32 = 0x10008; -pub(crate) const REG_BACKPLANE_DEVICE_CONTROL: u32 = 0x10009; -pub(crate) const REG_BACKPLANE_BACKPLANE_ADDRESS_LOW: u32 = 0x1000A; -pub(crate) const REG_BACKPLANE_BACKPLANE_ADDRESS_MID: u32 = 0x1000B; -pub(crate) const REG_BACKPLANE_BACKPLANE_ADDRESS_HIGH: u32 = 0x1000C; -pub(crate) const REG_BACKPLANE_FRAME_CONTROL: u32 = 0x1000D; -pub(crate) const REG_BACKPLANE_CHIP_CLOCK_CSR: u32 = 0x1000E; -pub(crate) const REG_BACKPLANE_PULL_UP: u32 = 0x1000F; -pub(crate) const REG_BACKPLANE_READ_FRAME_BC_LOW: u32 = 0x1001B; -pub(crate) const REG_BACKPLANE_READ_FRAME_BC_HIGH: u32 = 0x1001C; -pub(crate) const REG_BACKPLANE_WAKEUP_CTRL: u32 = 0x1001E; -pub(crate) const REG_BACKPLANE_SLEEP_CSR: u32 = 0x1001F; - -pub(crate) const BACKPLANE_WINDOW_SIZE: usize = 0x8000; -pub(crate) const BACKPLANE_ADDRESS_MASK: u32 = 0x7FFF; -pub(crate) const BACKPLANE_ADDRESS_32BIT_FLAG: u32 = 0x08000; -pub(crate) const BACKPLANE_MAX_TRANSFER_SIZE: usize = 64; -// Active Low Power (ALP) clock constants -pub(crate) const BACKPLANE_ALP_AVAIL_REQ: u8 = 0x08; -pub(crate) const BACKPLANE_ALP_AVAIL: u8 = 0x40; - -// Broadcom AMBA (Advanced Microcontroller Bus Architecture) Interconnect -// (AI) pub (crate) constants -pub(crate) const AI_IOCTRL_OFFSET: u32 = 0x408; -pub(crate) const AI_IOCTRL_BIT_FGC: u8 = 0x0002; -pub(crate) const AI_IOCTRL_BIT_CLOCK_EN: u8 = 0x0001; -pub(crate) const AI_IOCTRL_BIT_CPUHALT: u8 = 0x0020; - -pub(crate) const AI_RESETCTRL_OFFSET: u32 = 0x800; -pub(crate) const AI_RESETCTRL_BIT_RESET: u8 = 1; - -pub(crate) const AI_RESETSTATUS_OFFSET: u32 = 0x804; - -pub(crate) const TEST_PATTERN: u32 = 0x12345678; -pub(crate) const FEEDBEAD: u32 = 0xFEEDBEAD; - -// SPI_INTERRUPT_REGISTER and SPI_INTERRUPT_ENABLE_REGISTER Bits -pub(crate) const IRQ_DATA_UNAVAILABLE: u16 = 0x0001; // Requested data not available; Clear by writing a "1" -pub(crate) const IRQ_F2_F3_FIFO_RD_UNDERFLOW: u16 = 0x0002; -pub(crate) const IRQ_F2_F3_FIFO_WR_OVERFLOW: u16 = 0x0004; -pub(crate) const IRQ_COMMAND_ERROR: u16 = 0x0008; // Cleared by writing 1 -pub(crate) const IRQ_DATA_ERROR: u16 = 0x0010; // Cleared by writing 1 -pub(crate) const IRQ_F2_PACKET_AVAILABLE: u16 = 0x0020; -pub(crate) const IRQ_F3_PACKET_AVAILABLE: u16 = 0x0040; -pub(crate) const IRQ_F1_OVERFLOW: u16 = 0x0080; // Due to last write. Bkplane has pending write requests -pub(crate) const IRQ_MISC_INTR0: u16 = 0x0100; -pub(crate) const IRQ_MISC_INTR1: u16 = 0x0200; -pub(crate) const IRQ_MISC_INTR2: u16 = 0x0400; -pub(crate) const IRQ_MISC_INTR3: u16 = 0x0800; -pub(crate) const IRQ_MISC_INTR4: u16 = 0x1000; -pub(crate) const IRQ_F1_INTR: u16 = 0x2000; -pub(crate) const IRQ_F2_INTR: u16 = 0x4000; -pub(crate) const IRQ_F3_INTR: u16 = 0x8000; - -pub(crate) const IOCTL_CMD_UP: u32 = 2; -pub(crate) const IOCTL_CMD_DOWN: u32 = 3; -pub(crate) const IOCTL_CMD_SET_SSID: u32 = 26; -pub(crate) const IOCTL_CMD_SET_CHANNEL: u32 = 30; -pub(crate) const IOCTL_CMD_ANTDIV: u32 = 64; -pub(crate) const IOCTL_CMD_SET_AP: u32 = 118; -pub(crate) const IOCTL_CMD_SET_VAR: u32 = 263; -pub(crate) const IOCTL_CMD_GET_VAR: u32 = 262; -pub(crate) const IOCTL_CMD_SET_PASSPHRASE: u32 = 268; - -pub(crate) const CHANNEL_TYPE_CONTROL: u8 = 0; -pub(crate) const CHANNEL_TYPE_EVENT: u8 = 1; -pub(crate) const CHANNEL_TYPE_DATA: u8 = 2; - -// CYW_SPID command structure constants. -pub(crate) const WRITE: bool = true; -pub(crate) const READ: bool = false; -pub(crate) const INC_ADDR: bool = true; -pub(crate) const FIXED_ADDR: bool = false; - -pub(crate) const AES_ENABLED: u32 = 0x0004; -pub(crate) const WPA2_SECURITY: u32 = 0x00400000; - -pub(crate) const MIN_PSK_LEN: usize = 8; -pub(crate) const MAX_PSK_LEN: usize = 64; - -// Security type (authentication and encryption types are combined using bit mask) -#[allow(non_camel_case_types)] -#[derive(Copy, Clone, PartialEq)] -#[repr(u32)] -pub(crate) enum Security { - OPEN = 0, - WPA2_AES_PSK = WPA2_SECURITY | AES_ENABLED, -} - -#[allow(non_camel_case_types)] -#[derive(Copy, Clone)] -#[repr(u8)] -pub enum EStatus { - /// operation was successful - SUCCESS = 0, - /// operation failed - FAIL = 1, - /// operation timed out - TIMEOUT = 2, - /// failed due to no matching network found - NO_NETWORKS = 3, - /// operation was aborted - ABORT = 4, - /// protocol failure: packet not ack'd - NO_ACK = 5, - /// AUTH or ASSOC packet was unsolicited - UNSOLICITED = 6, - /// attempt to assoc to an auto auth configuration - ATTEMPT = 7, - /// scan results are incomplete - PARTIAL = 8, - /// scan aborted by another scan - NEWSCAN = 9, - /// scan aborted due to assoc in progress - NEWASSOC = 10, - /// 802.11h quiet period started - _11HQUIET = 11, - /// user disabled scanning (WLC_SET_SCANSUPPRESS) - SUPPRESS = 12, - /// no allowable channels to scan - NOCHANS = 13, - /// scan aborted due to CCX fast roam - CCXFASTRM = 14, - /// abort channel select - CS_ABORT = 15, -} - -impl PartialEq for u32 { - fn eq(&self, other: &EStatus) -> bool { - *self == *other as Self - } -} - -#[allow(dead_code)] -pub(crate) struct FormatStatus(pub u32); - -#[cfg(feature = "defmt")] -impl defmt::Format for FormatStatus { - fn format(&self, fmt: defmt::Formatter) { - macro_rules! implm { - ($($name:ident),*) => { - $( - if self.0 & $name > 0 { - defmt::write!(fmt, " | {}", &stringify!($name)[7..]); - } - )* - }; - } - - implm!( - STATUS_DATA_NOT_AVAILABLE, - STATUS_UNDERFLOW, - STATUS_OVERFLOW, - STATUS_F2_INTR, - STATUS_F3_INTR, - STATUS_F2_RX_READY, - STATUS_F3_RX_READY, - STATUS_HOST_CMD_DATA_ERR, - STATUS_F2_PKT_AVAILABLE, - STATUS_F3_PKT_AVAILABLE - ); - } -} - -#[cfg(feature = "log")] -impl core::fmt::Debug for FormatStatus { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - macro_rules! implm { - ($($name:ident),*) => { - $( - if self.0 & $name > 0 { - core::write!(fmt, " | {}", &stringify!($name)[7..])?; - } - )* - }; - } - - implm!( - STATUS_DATA_NOT_AVAILABLE, - STATUS_UNDERFLOW, - STATUS_OVERFLOW, - STATUS_F2_INTR, - STATUS_F3_INTR, - STATUS_F2_RX_READY, - STATUS_F3_RX_READY, - STATUS_HOST_CMD_DATA_ERR, - STATUS_F2_PKT_AVAILABLE, - STATUS_F3_PKT_AVAILABLE - ); - Ok(()) - } -} - -#[cfg(feature = "log")] -impl core::fmt::Display for FormatStatus { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - core::fmt::Debug::fmt(self, f) - } -} - -#[allow(dead_code)] -pub(crate) struct FormatInterrupt(pub u16); - -#[cfg(feature = "defmt")] -impl defmt::Format for FormatInterrupt { - fn format(&self, fmt: defmt::Formatter) { - macro_rules! implm { - ($($name:ident),*) => { - $( - if self.0 & $name > 0 { - defmt::write!(fmt, " | {}", &stringify!($name)[4..]); - } - )* - }; - } - - implm!( - IRQ_DATA_UNAVAILABLE, - IRQ_F2_F3_FIFO_RD_UNDERFLOW, - IRQ_F2_F3_FIFO_WR_OVERFLOW, - IRQ_COMMAND_ERROR, - IRQ_DATA_ERROR, - IRQ_F2_PACKET_AVAILABLE, - IRQ_F3_PACKET_AVAILABLE, - IRQ_F1_OVERFLOW, - IRQ_MISC_INTR0, - IRQ_MISC_INTR1, - IRQ_MISC_INTR2, - IRQ_MISC_INTR3, - IRQ_MISC_INTR4, - IRQ_F1_INTR, - IRQ_F2_INTR, - IRQ_F3_INTR - ); - } -} - -#[cfg(feature = "log")] -impl core::fmt::Debug for FormatInterrupt { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - macro_rules! implm { - ($($name:ident),*) => { - $( - if self.0 & $name > 0 { - core::write!(fmt, " | {}", &stringify!($name)[7..])?; - } - )* - }; - } - - implm!( - IRQ_DATA_UNAVAILABLE, - IRQ_F2_F3_FIFO_RD_UNDERFLOW, - IRQ_F2_F3_FIFO_WR_OVERFLOW, - IRQ_COMMAND_ERROR, - IRQ_DATA_ERROR, - IRQ_F2_PACKET_AVAILABLE, - IRQ_F3_PACKET_AVAILABLE, - IRQ_F1_OVERFLOW, - IRQ_MISC_INTR0, - IRQ_MISC_INTR1, - IRQ_MISC_INTR2, - IRQ_MISC_INTR3, - IRQ_MISC_INTR4, - IRQ_F1_INTR, - IRQ_F2_INTR, - IRQ_F3_INTR - ); - Ok(()) - } -} - -#[cfg(feature = "log")] -impl core::fmt::Display for FormatInterrupt { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - core::fmt::Debug::fmt(self, f) - } -} diff --git a/src/control.rs b/src/control.rs deleted file mode 100644 index 6919d569e..000000000 --- a/src/control.rs +++ /dev/null @@ -1,457 +0,0 @@ -use core::cmp::{max, min}; - -use ch::driver::LinkState; -use embassy_net_driver_channel as ch; -use embassy_time::{Duration, Timer}; - -pub use crate::bus::SpiBusCyw43; -use crate::consts::*; -use crate::events::{Event, EventSubscriber, Events}; -use crate::fmt::Bytes; -use crate::ioctl::{IoctlState, IoctlType}; -use crate::structs::*; -use crate::{countries, events, PowerManagementMode}; - -#[derive(Debug)] -pub struct Error { - pub status: u32, -} - -pub struct Control<'a> { - state_ch: ch::StateRunner<'a>, - events: &'a Events, - ioctl_state: &'a IoctlState, -} - -impl<'a> Control<'a> { - pub(crate) fn new(state_ch: ch::StateRunner<'a>, event_sub: &'a Events, ioctl_state: &'a IoctlState) -> Self { - Self { - state_ch, - events: event_sub, - ioctl_state, - } - } - - pub async fn init(&mut self, clm: &[u8]) { - const CHUNK_SIZE: usize = 1024; - - debug!("Downloading CLM..."); - - let mut offs = 0; - for chunk in clm.chunks(CHUNK_SIZE) { - let mut flag = DOWNLOAD_FLAG_HANDLER_VER; - if offs == 0 { - flag |= DOWNLOAD_FLAG_BEGIN; - } - offs += chunk.len(); - if offs == clm.len() { - flag |= DOWNLOAD_FLAG_END; - } - - let header = DownloadHeader { - flag, - dload_type: DOWNLOAD_TYPE_CLM, - len: chunk.len() as _, - crc: 0, - }; - let mut buf = [0; 8 + 12 + CHUNK_SIZE]; - buf[0..8].copy_from_slice(b"clmload\x00"); - buf[8..20].copy_from_slice(&header.to_bytes()); - buf[20..][..chunk.len()].copy_from_slice(&chunk); - self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..8 + 12 + chunk.len()]) - .await; - } - - // check clmload ok - assert_eq!(self.get_iovar_u32("clmload_status").await, 0); - - debug!("Configuring misc stuff..."); - - // Disable tx gloming which transfers multiple packets in one request. - // 'glom' is short for "conglomerate" which means "gather together into - // a compact mass". - self.set_iovar_u32("bus:txglom", 0).await; - self.set_iovar_u32("apsta", 1).await; - - // read MAC addr. - let mut mac_addr = [0; 6]; - assert_eq!(self.get_iovar("cur_etheraddr", &mut mac_addr).await, 6); - debug!("mac addr: {:02x}", Bytes(&mac_addr)); - - let country = countries::WORLD_WIDE_XX; - let country_info = CountryInfo { - country_abbrev: [country.code[0], country.code[1], 0, 0], - country_code: [country.code[0], country.code[1], 0, 0], - rev: if country.rev == 0 { -1 } else { country.rev as _ }, - }; - self.set_iovar("country", &country_info.to_bytes()).await; - - // set country takes some time, next ioctls fail if we don't wait. - Timer::after(Duration::from_millis(100)).await; - - // Set antenna to chip antenna - self.ioctl_set_u32(IOCTL_CMD_ANTDIV, 0, 0).await; - - self.set_iovar_u32("bus:txglom", 0).await; - Timer::after(Duration::from_millis(100)).await; - //self.set_iovar_u32("apsta", 1).await; // this crashes, also we already did it before...?? - //Timer::after(Duration::from_millis(100)).await; - self.set_iovar_u32("ampdu_ba_wsize", 8).await; - Timer::after(Duration::from_millis(100)).await; - self.set_iovar_u32("ampdu_mpdu", 4).await; - Timer::after(Duration::from_millis(100)).await; - //self.set_iovar_u32("ampdu_rx_factor", 0).await; // this crashes - - //Timer::after(Duration::from_millis(100)).await; - - // evts - let mut evts = EventMask { - iface: 0, - events: [0xFF; 24], - }; - - // Disable spammy uninteresting events. - evts.unset(Event::RADIO); - evts.unset(Event::IF); - evts.unset(Event::PROBREQ_MSG); - evts.unset(Event::PROBREQ_MSG_RX); - evts.unset(Event::PROBRESP_MSG); - evts.unset(Event::PROBRESP_MSG); - evts.unset(Event::ROAM); - - self.set_iovar("bsscfg:event_msgs", &evts.to_bytes()).await; - - Timer::after(Duration::from_millis(100)).await; - - // set wifi up - self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await; - - Timer::after(Duration::from_millis(100)).await; - - self.ioctl_set_u32(110, 0, 1).await; // SET_GMODE = auto - self.ioctl_set_u32(142, 0, 0).await; // SET_BAND = any - - Timer::after(Duration::from_millis(100)).await; - - self.state_ch.set_ethernet_address(mac_addr); - - debug!("INIT DONE"); - } - - pub async fn set_power_management(&mut self, mode: PowerManagementMode) { - // power save mode - let mode_num = mode.mode(); - if mode_num == 2 { - self.set_iovar_u32("pm2_sleep_ret", mode.sleep_ret_ms() as u32).await; - self.set_iovar_u32("bcn_li_bcn", mode.beacon_period() as u32).await; - self.set_iovar_u32("bcn_li_dtim", mode.dtim_period() as u32).await; - self.set_iovar_u32("assoc_listen", mode.assoc() as u32).await; - } - self.ioctl_set_u32(86, 0, mode_num).await; - } - - pub async fn join_open(&mut self, ssid: &str) -> Result<(), Error> { - self.set_iovar_u32("ampdu_ba_wsize", 8).await; - - self.ioctl_set_u32(134, 0, 0).await; // wsec = open - self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 0).await; - self.ioctl_set_u32(20, 0, 1).await; // set_infra = 1 - self.ioctl_set_u32(22, 0, 0).await; // set_auth = open (0) - - let mut i = SsidInfo { - len: ssid.len() as _, - ssid: [0; 32], - }; - i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes()); - - self.wait_for_join(i).await - } - - pub async fn join_wpa2(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { - self.set_iovar_u32("ampdu_ba_wsize", 8).await; - - self.ioctl_set_u32(134, 0, 4).await; // wsec = wpa2 - self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 1).await; - self.set_iovar_u32x2("bsscfg:sup_wpa2_eapver", 0, 0xFFFF_FFFF).await; - self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).await; - - Timer::after(Duration::from_millis(100)).await; - - let mut pfi = PassphraseInfo { - len: passphrase.len() as _, - flags: 1, - passphrase: [0; 64], - }; - pfi.passphrase[..passphrase.len()].copy_from_slice(passphrase.as_bytes()); - self.ioctl(IoctlType::Set, IOCTL_CMD_SET_PASSPHRASE, 0, &mut pfi.to_bytes()) - .await; // WLC_SET_WSEC_PMK - - self.ioctl_set_u32(20, 0, 1).await; // set_infra = 1 - self.ioctl_set_u32(22, 0, 0).await; // set_auth = 0 (open) - self.ioctl_set_u32(165, 0, 0x80).await; // set_wpa_auth - - let mut i = SsidInfo { - len: ssid.len() as _, - ssid: [0; 32], - }; - i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes()); - - self.wait_for_join(i).await - } - - async fn wait_for_join(&mut self, i: SsidInfo) -> Result<(), Error> { - self.events.mask.enable(&[Event::SET_SSID, Event::AUTH]); - let mut subscriber = self.events.queue.subscriber().unwrap(); - // the actual join operation starts here - // we make sure to enable events before so we don't miss any - - // set_ssid - self.ioctl(IoctlType::Set, IOCTL_CMD_SET_SSID, 0, &mut i.to_bytes()) - .await; - - // to complete the join, we wait for a SET_SSID event - // we also save the AUTH status for the user, it may be interesting - let mut auth_status = 0; - let status = loop { - let msg = subscriber.next_message_pure().await; - if msg.header.event_type == Event::AUTH && msg.header.status != EStatus::SUCCESS { - auth_status = msg.header.status; - } else if msg.header.event_type == Event::SET_SSID { - // join operation ends with SET_SSID event - break msg.header.status; - } - }; - - self.events.mask.disable_all(); - if status == EStatus::SUCCESS { - // successful join - self.state_ch.set_link_state(LinkState::Up); - debug!("JOINED"); - Ok(()) - } else { - warn!("JOIN failed with status={} auth={}", status, auth_status); - Err(Error { status }) - } - } - - pub async fn gpio_set(&mut self, gpio_n: u8, gpio_en: bool) { - assert!(gpio_n < 3); - self.set_iovar_u32x2("gpioout", 1 << gpio_n, if gpio_en { 1 << gpio_n } else { 0 }) - .await - } - - pub async fn start_ap_open(&mut self, ssid: &str, channel: u8) { - self.start_ap(ssid, "", Security::OPEN, channel).await; - } - - pub async fn start_ap_wpa2(&mut self, ssid: &str, passphrase: &str, channel: u8) { - self.start_ap(ssid, passphrase, Security::WPA2_AES_PSK, channel).await; - } - - async fn start_ap(&mut self, ssid: &str, passphrase: &str, security: Security, channel: u8) { - if security != Security::OPEN - && (passphrase.as_bytes().len() < MIN_PSK_LEN || passphrase.as_bytes().len() > MAX_PSK_LEN) - { - panic!("Passphrase is too short or too long"); - } - - // Temporarily set wifi down - self.ioctl(IoctlType::Set, IOCTL_CMD_DOWN, 0, &mut []).await; - - // Turn off APSTA mode - self.set_iovar_u32("apsta", 0).await; - - // Set wifi up again - self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await; - - // Turn on AP mode - self.ioctl_set_u32(IOCTL_CMD_SET_AP, 0, 1).await; - - // Set SSID - let mut i = SsidInfoWithIndex { - index: 0, - ssid_info: SsidInfo { - len: ssid.as_bytes().len() as _, - ssid: [0; 32], - }, - }; - i.ssid_info.ssid[..ssid.as_bytes().len()].copy_from_slice(ssid.as_bytes()); - self.set_iovar("bsscfg:ssid", &i.to_bytes()).await; - - // Set channel number - self.ioctl_set_u32(IOCTL_CMD_SET_CHANNEL, 0, channel as u32).await; - - // Set security - self.set_iovar_u32x2("bsscfg:wsec", 0, (security as u32) & 0xFF).await; - - if security != Security::OPEN { - self.set_iovar_u32x2("bsscfg:wpa_auth", 0, 0x0084).await; // wpa_auth = WPA2_AUTH_PSK | WPA_AUTH_PSK - - Timer::after(Duration::from_millis(100)).await; - - // Set passphrase - let mut pfi = PassphraseInfo { - len: passphrase.as_bytes().len() as _, - flags: 1, // WSEC_PASSPHRASE - passphrase: [0; 64], - }; - pfi.passphrase[..passphrase.as_bytes().len()].copy_from_slice(passphrase.as_bytes()); - self.ioctl(IoctlType::Set, IOCTL_CMD_SET_PASSPHRASE, 0, &mut pfi.to_bytes()) - .await; - } - - // Change mutlicast rate from 1 Mbps to 11 Mbps - self.set_iovar_u32("2g_mrate", 11000000 / 500000).await; - - // Start AP - self.set_iovar_u32x2("bss", 0, 1).await; // bss = BSS_UP - } - - async fn set_iovar_u32x2(&mut self, name: &str, val1: u32, val2: u32) { - let mut buf = [0; 8]; - buf[0..4].copy_from_slice(&val1.to_le_bytes()); - buf[4..8].copy_from_slice(&val2.to_le_bytes()); - self.set_iovar(name, &buf).await - } - - async fn set_iovar_u32(&mut self, name: &str, val: u32) { - self.set_iovar(name, &val.to_le_bytes()).await - } - - async fn get_iovar_u32(&mut self, name: &str) -> u32 { - let mut buf = [0; 4]; - let len = self.get_iovar(name, &mut buf).await; - assert_eq!(len, 4); - u32::from_le_bytes(buf) - } - - async fn set_iovar(&mut self, name: &str, val: &[u8]) { - self.set_iovar_v::<64>(name, val).await - } - - async fn set_iovar_v(&mut self, name: &str, val: &[u8]) { - debug!("set {} = {:02x}", name, Bytes(val)); - - let mut buf = [0; BUFSIZE]; - buf[..name.len()].copy_from_slice(name.as_bytes()); - buf[name.len()] = 0; - buf[name.len() + 1..][..val.len()].copy_from_slice(val); - - let total_len = name.len() + 1 + val.len(); - self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..total_len]) - .await; - } - - // TODO this is not really working, it always returns all zeros. - async fn get_iovar(&mut self, name: &str, res: &mut [u8]) -> usize { - debug!("get {}", name); - - let mut buf = [0; 64]; - buf[..name.len()].copy_from_slice(name.as_bytes()); - buf[name.len()] = 0; - - let total_len = max(name.len() + 1, res.len()); - let res_len = self - .ioctl(IoctlType::Get, IOCTL_CMD_GET_VAR, 0, &mut buf[..total_len]) - .await; - - let out_len = min(res.len(), res_len); - res[..out_len].copy_from_slice(&buf[..out_len]); - out_len - } - - async fn ioctl_set_u32(&mut self, cmd: u32, iface: u32, val: u32) { - let mut buf = val.to_le_bytes(); - self.ioctl(IoctlType::Set, cmd, iface, &mut buf).await; - } - - async fn ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize { - struct CancelOnDrop<'a>(&'a IoctlState); - - impl CancelOnDrop<'_> { - fn defuse(self) { - core::mem::forget(self); - } - } - - impl Drop for CancelOnDrop<'_> { - fn drop(&mut self) { - self.0.cancel_ioctl(); - } - } - - let ioctl = CancelOnDrop(self.ioctl_state); - - ioctl.0.do_ioctl(kind, cmd, iface, buf).await; - let resp_len = ioctl.0.wait_complete().await; - - ioctl.defuse(); - - resp_len - } - - /// Start a wifi scan - /// - /// Returns a `Stream` of networks found by the device - /// - /// # Note - /// Device events are currently implemented using a bounded queue. - /// To not miss any events, you should make sure to always await the stream. - pub async fn scan(&mut self) -> Scanner<'_> { - const SCANTYPE_PASSIVE: u8 = 1; - - let scan_params = ScanParams { - version: 1, - action: 1, - sync_id: 1, - ssid_len: 0, - ssid: [0; 32], - bssid: [0xff; 6], - bss_type: 2, - scan_type: SCANTYPE_PASSIVE, - nprobes: !0, - active_time: !0, - passive_time: !0, - home_time: !0, - channel_num: 0, - channel_list: [0; 1], - }; - - self.events.mask.enable(&[Event::ESCAN_RESULT]); - let subscriber = self.events.queue.subscriber().unwrap(); - self.set_iovar_v::<256>("escan", &scan_params.to_bytes()).await; - - Scanner { - subscriber, - events: &self.events, - } - } -} - -pub struct Scanner<'a> { - subscriber: EventSubscriber<'a>, - events: &'a Events, -} - -impl Scanner<'_> { - /// wait for the next found network - pub async fn next(&mut self) -> Option { - let event = self.subscriber.next_message_pure().await; - if event.header.status != EStatus::PARTIAL { - self.events.mask.disable_all(); - return None; - } - - if let events::Payload::BssInfo(bss) = event.payload { - Some(bss) - } else { - None - } - } -} - -impl Drop for Scanner<'_> { - fn drop(&mut self) { - self.events.mask.disable_all(); - } -} diff --git a/src/countries.rs b/src/countries.rs deleted file mode 100644 index fa1e8cace..000000000 --- a/src/countries.rs +++ /dev/null @@ -1,481 +0,0 @@ -#![allow(unused)] - -pub struct Country { - pub code: [u8; 2], - pub rev: u16, -} - -/// AF Afghanistan -pub const AFGHANISTAN: Country = Country { code: *b"AF", rev: 0 }; -/// AL Albania -pub const ALBANIA: Country = Country { code: *b"AL", rev: 0 }; -/// DZ Algeria -pub const ALGERIA: Country = Country { code: *b"DZ", rev: 0 }; -/// AS American_Samoa -pub const AMERICAN_SAMOA: Country = Country { code: *b"AS", rev: 0 }; -/// AO Angola -pub const ANGOLA: Country = Country { code: *b"AO", rev: 0 }; -/// AI Anguilla -pub const ANGUILLA: Country = Country { code: *b"AI", rev: 0 }; -/// AG Antigua_and_Barbuda -pub const ANTIGUA_AND_BARBUDA: Country = Country { code: *b"AG", rev: 0 }; -/// AR Argentina -pub const ARGENTINA: Country = Country { code: *b"AR", rev: 0 }; -/// AM Armenia -pub const ARMENIA: Country = Country { code: *b"AM", rev: 0 }; -/// AW Aruba -pub const ARUBA: Country = Country { code: *b"AW", rev: 0 }; -/// AU Australia -pub const AUSTRALIA: Country = Country { code: *b"AU", rev: 0 }; -/// AT Austria -pub const AUSTRIA: Country = Country { code: *b"AT", rev: 0 }; -/// AZ Azerbaijan -pub const AZERBAIJAN: Country = Country { code: *b"AZ", rev: 0 }; -/// BS Bahamas -pub const BAHAMAS: Country = Country { code: *b"BS", rev: 0 }; -/// BH Bahrain -pub const BAHRAIN: Country = Country { code: *b"BH", rev: 0 }; -/// 0B Baker_Island -pub const BAKER_ISLAND: Country = Country { code: *b"0B", rev: 0 }; -/// BD Bangladesh -pub const BANGLADESH: Country = Country { code: *b"BD", rev: 0 }; -/// BB Barbados -pub const BARBADOS: Country = Country { code: *b"BB", rev: 0 }; -/// BY Belarus -pub const BELARUS: Country = Country { code: *b"BY", rev: 0 }; -/// BE Belgium -pub const BELGIUM: Country = Country { code: *b"BE", rev: 0 }; -/// BZ Belize -pub const BELIZE: Country = Country { code: *b"BZ", rev: 0 }; -/// BJ Benin -pub const BENIN: Country = Country { code: *b"BJ", rev: 0 }; -/// BM Bermuda -pub const BERMUDA: Country = Country { code: *b"BM", rev: 0 }; -/// BT Bhutan -pub const BHUTAN: Country = Country { code: *b"BT", rev: 0 }; -/// BO Bolivia -pub const BOLIVIA: Country = Country { code: *b"BO", rev: 0 }; -/// BA Bosnia_and_Herzegovina -pub const BOSNIA_AND_HERZEGOVINA: Country = Country { code: *b"BA", rev: 0 }; -/// BW Botswana -pub const BOTSWANA: Country = Country { code: *b"BW", rev: 0 }; -/// BR Brazil -pub const BRAZIL: Country = Country { code: *b"BR", rev: 0 }; -/// IO British_Indian_Ocean_Territory -pub const BRITISH_INDIAN_OCEAN_TERRITORY: Country = Country { code: *b"IO", rev: 0 }; -/// BN Brunei_Darussalam -pub const BRUNEI_DARUSSALAM: Country = Country { code: *b"BN", rev: 0 }; -/// BG Bulgaria -pub const BULGARIA: Country = Country { code: *b"BG", rev: 0 }; -/// BF Burkina_Faso -pub const BURKINA_FASO: Country = Country { code: *b"BF", rev: 0 }; -/// BI Burundi -pub const BURUNDI: Country = Country { code: *b"BI", rev: 0 }; -/// KH Cambodia -pub const CAMBODIA: Country = Country { code: *b"KH", rev: 0 }; -/// CM Cameroon -pub const CAMEROON: Country = Country { code: *b"CM", rev: 0 }; -/// CA Canada -pub const CANADA: Country = Country { code: *b"CA", rev: 0 }; -/// CA Canada Revision 950 -pub const CANADA_REV950: Country = Country { code: *b"CA", rev: 950 }; -/// CV Cape_Verde -pub const CAPE_VERDE: Country = Country { code: *b"CV", rev: 0 }; -/// KY Cayman_Islands -pub const CAYMAN_ISLANDS: Country = Country { code: *b"KY", rev: 0 }; -/// CF Central_African_Republic -pub const CENTRAL_AFRICAN_REPUBLIC: Country = Country { code: *b"CF", rev: 0 }; -/// TD Chad -pub const CHAD: Country = Country { code: *b"TD", rev: 0 }; -/// CL Chile -pub const CHILE: Country = Country { code: *b"CL", rev: 0 }; -/// CN China -pub const CHINA: Country = Country { code: *b"CN", rev: 0 }; -/// CX Christmas_Island -pub const CHRISTMAS_ISLAND: Country = Country { code: *b"CX", rev: 0 }; -/// CO Colombia -pub const COLOMBIA: Country = Country { code: *b"CO", rev: 0 }; -/// KM Comoros -pub const COMOROS: Country = Country { code: *b"KM", rev: 0 }; -/// CG Congo -pub const CONGO: Country = Country { code: *b"CG", rev: 0 }; -/// CD Congo,_The_Democratic_Republic_Of_The -pub const CONGO_THE_DEMOCRATIC_REPUBLIC_OF_THE: Country = Country { code: *b"CD", rev: 0 }; -/// CR Costa_Rica -pub const COSTA_RICA: Country = Country { code: *b"CR", rev: 0 }; -/// CI Cote_D'ivoire -pub const COTE_DIVOIRE: Country = Country { code: *b"CI", rev: 0 }; -/// HR Croatia -pub const CROATIA: Country = Country { code: *b"HR", rev: 0 }; -/// CU Cuba -pub const CUBA: Country = Country { code: *b"CU", rev: 0 }; -/// CY Cyprus -pub const CYPRUS: Country = Country { code: *b"CY", rev: 0 }; -/// CZ Czech_Republic -pub const CZECH_REPUBLIC: Country = Country { code: *b"CZ", rev: 0 }; -/// DK Denmark -pub const DENMARK: Country = Country { code: *b"DK", rev: 0 }; -/// DJ Djibouti -pub const DJIBOUTI: Country = Country { code: *b"DJ", rev: 0 }; -/// DM Dominica -pub const DOMINICA: Country = Country { code: *b"DM", rev: 0 }; -/// DO Dominican_Republic -pub const DOMINICAN_REPUBLIC: Country = Country { code: *b"DO", rev: 0 }; -/// AU G'Day mate! -pub const DOWN_UNDER: Country = Country { code: *b"AU", rev: 0 }; -/// EC Ecuador -pub const ECUADOR: Country = Country { code: *b"EC", rev: 0 }; -/// EG Egypt -pub const EGYPT: Country = Country { code: *b"EG", rev: 0 }; -/// SV El_Salvador -pub const EL_SALVADOR: Country = Country { code: *b"SV", rev: 0 }; -/// GQ Equatorial_Guinea -pub const EQUATORIAL_GUINEA: Country = Country { code: *b"GQ", rev: 0 }; -/// ER Eritrea -pub const ERITREA: Country = Country { code: *b"ER", rev: 0 }; -/// EE Estonia -pub const ESTONIA: Country = Country { code: *b"EE", rev: 0 }; -/// ET Ethiopia -pub const ETHIOPIA: Country = Country { code: *b"ET", rev: 0 }; -/// FK Falkland_Islands_(Malvinas) -pub const FALKLAND_ISLANDS_MALVINAS: Country = Country { code: *b"FK", rev: 0 }; -/// FO Faroe_Islands -pub const FAROE_ISLANDS: Country = Country { code: *b"FO", rev: 0 }; -/// FJ Fiji -pub const FIJI: Country = Country { code: *b"FJ", rev: 0 }; -/// FI Finland -pub const FINLAND: Country = Country { code: *b"FI", rev: 0 }; -/// FR France -pub const FRANCE: Country = Country { code: *b"FR", rev: 0 }; -/// GF French_Guina -pub const FRENCH_GUINA: Country = Country { code: *b"GF", rev: 0 }; -/// PF French_Polynesia -pub const FRENCH_POLYNESIA: Country = Country { code: *b"PF", rev: 0 }; -/// TF French_Southern_Territories -pub const FRENCH_SOUTHERN_TERRITORIES: Country = Country { code: *b"TF", rev: 0 }; -/// GA Gabon -pub const GABON: Country = Country { code: *b"GA", rev: 0 }; -/// GM Gambia -pub const GAMBIA: Country = Country { code: *b"GM", rev: 0 }; -/// GE Georgia -pub const GEORGIA: Country = Country { code: *b"GE", rev: 0 }; -/// DE Germany -pub const GERMANY: Country = Country { code: *b"DE", rev: 0 }; -/// E0 European_Wide Revision 895 -pub const EUROPEAN_WIDE_REV895: Country = Country { code: *b"E0", rev: 895 }; -/// GH Ghana -pub const GHANA: Country = Country { code: *b"GH", rev: 0 }; -/// GI Gibraltar -pub const GIBRALTAR: Country = Country { code: *b"GI", rev: 0 }; -/// GR Greece -pub const GREECE: Country = Country { code: *b"GR", rev: 0 }; -/// GD Grenada -pub const GRENADA: Country = Country { code: *b"GD", rev: 0 }; -/// GP Guadeloupe -pub const GUADELOUPE: Country = Country { code: *b"GP", rev: 0 }; -/// GU Guam -pub const GUAM: Country = Country { code: *b"GU", rev: 0 }; -/// GT Guatemala -pub const GUATEMALA: Country = Country { code: *b"GT", rev: 0 }; -/// GG Guernsey -pub const GUERNSEY: Country = Country { code: *b"GG", rev: 0 }; -/// GN Guinea -pub const GUINEA: Country = Country { code: *b"GN", rev: 0 }; -/// GW Guinea-bissau -pub const GUINEA_BISSAU: Country = Country { code: *b"GW", rev: 0 }; -/// GY Guyana -pub const GUYANA: Country = Country { code: *b"GY", rev: 0 }; -/// HT Haiti -pub const HAITI: Country = Country { code: *b"HT", rev: 0 }; -/// VA Holy_See_(Vatican_City_State) -pub const HOLY_SEE_VATICAN_CITY_STATE: Country = Country { code: *b"VA", rev: 0 }; -/// HN Honduras -pub const HONDURAS: Country = Country { code: *b"HN", rev: 0 }; -/// HK Hong_Kong -pub const HONG_KONG: Country = Country { code: *b"HK", rev: 0 }; -/// HU Hungary -pub const HUNGARY: Country = Country { code: *b"HU", rev: 0 }; -/// IS Iceland -pub const ICELAND: Country = Country { code: *b"IS", rev: 0 }; -/// IN India -pub const INDIA: Country = Country { code: *b"IN", rev: 0 }; -/// ID Indonesia -pub const INDONESIA: Country = Country { code: *b"ID", rev: 0 }; -/// IR Iran,_Islamic_Republic_Of -pub const IRAN_ISLAMIC_REPUBLIC_OF: Country = Country { code: *b"IR", rev: 0 }; -/// IQ Iraq -pub const IRAQ: Country = Country { code: *b"IQ", rev: 0 }; -/// IE Ireland -pub const IRELAND: Country = Country { code: *b"IE", rev: 0 }; -/// IL Israel -pub const ISRAEL: Country = Country { code: *b"IL", rev: 0 }; -/// IT Italy -pub const ITALY: Country = Country { code: *b"IT", rev: 0 }; -/// JM Jamaica -pub const JAMAICA: Country = Country { code: *b"JM", rev: 0 }; -/// JP Japan -pub const JAPAN: Country = Country { code: *b"JP", rev: 0 }; -/// JE Jersey -pub const JERSEY: Country = Country { code: *b"JE", rev: 0 }; -/// JO Jordan -pub const JORDAN: Country = Country { code: *b"JO", rev: 0 }; -/// KZ Kazakhstan -pub const KAZAKHSTAN: Country = Country { code: *b"KZ", rev: 0 }; -/// KE Kenya -pub const KENYA: Country = Country { code: *b"KE", rev: 0 }; -/// KI Kiribati -pub const KIRIBATI: Country = Country { code: *b"KI", rev: 0 }; -/// KR Korea,_Republic_Of -pub const KOREA_REPUBLIC_OF: Country = Country { code: *b"KR", rev: 1 }; -/// 0A Kosovo -pub const KOSOVO: Country = Country { code: *b"0A", rev: 0 }; -/// KW Kuwait -pub const KUWAIT: Country = Country { code: *b"KW", rev: 0 }; -/// KG Kyrgyzstan -pub const KYRGYZSTAN: Country = Country { code: *b"KG", rev: 0 }; -/// LA Lao_People's_Democratic_Repubic -pub const LAO_PEOPLES_DEMOCRATIC_REPUBIC: Country = Country { code: *b"LA", rev: 0 }; -/// LV Latvia -pub const LATVIA: Country = Country { code: *b"LV", rev: 0 }; -/// LB Lebanon -pub const LEBANON: Country = Country { code: *b"LB", rev: 0 }; -/// LS Lesotho -pub const LESOTHO: Country = Country { code: *b"LS", rev: 0 }; -/// LR Liberia -pub const LIBERIA: Country = Country { code: *b"LR", rev: 0 }; -/// LY Libyan_Arab_Jamahiriya -pub const LIBYAN_ARAB_JAMAHIRIYA: Country = Country { code: *b"LY", rev: 0 }; -/// LI Liechtenstein -pub const LIECHTENSTEIN: Country = Country { code: *b"LI", rev: 0 }; -/// LT Lithuania -pub const LITHUANIA: Country = Country { code: *b"LT", rev: 0 }; -/// LU Luxembourg -pub const LUXEMBOURG: Country = Country { code: *b"LU", rev: 0 }; -/// MO Macao -pub const MACAO: Country = Country { code: *b"MO", rev: 0 }; -/// MK Macedonia,_Former_Yugoslav_Republic_Of -pub const MACEDONIA_FORMER_YUGOSLAV_REPUBLIC_OF: Country = Country { code: *b"MK", rev: 0 }; -/// MG Madagascar -pub const MADAGASCAR: Country = Country { code: *b"MG", rev: 0 }; -/// MW Malawi -pub const MALAWI: Country = Country { code: *b"MW", rev: 0 }; -/// MY Malaysia -pub const MALAYSIA: Country = Country { code: *b"MY", rev: 0 }; -/// MV Maldives -pub const MALDIVES: Country = Country { code: *b"MV", rev: 0 }; -/// ML Mali -pub const MALI: Country = Country { code: *b"ML", rev: 0 }; -/// MT Malta -pub const MALTA: Country = Country { code: *b"MT", rev: 0 }; -/// IM Man,_Isle_Of -pub const MAN_ISLE_OF: Country = Country { code: *b"IM", rev: 0 }; -/// MQ Martinique -pub const MARTINIQUE: Country = Country { code: *b"MQ", rev: 0 }; -/// MR Mauritania -pub const MAURITANIA: Country = Country { code: *b"MR", rev: 0 }; -/// MU Mauritius -pub const MAURITIUS: Country = Country { code: *b"MU", rev: 0 }; -/// YT Mayotte -pub const MAYOTTE: Country = Country { code: *b"YT", rev: 0 }; -/// MX Mexico -pub const MEXICO: Country = Country { code: *b"MX", rev: 0 }; -/// FM Micronesia,_Federated_States_Of -pub const MICRONESIA_FEDERATED_STATES_OF: Country = Country { code: *b"FM", rev: 0 }; -/// MD Moldova,_Republic_Of -pub const MOLDOVA_REPUBLIC_OF: Country = Country { code: *b"MD", rev: 0 }; -/// MC Monaco -pub const MONACO: Country = Country { code: *b"MC", rev: 0 }; -/// MN Mongolia -pub const MONGOLIA: Country = Country { code: *b"MN", rev: 0 }; -/// ME Montenegro -pub const MONTENEGRO: Country = Country { code: *b"ME", rev: 0 }; -/// MS Montserrat -pub const MONTSERRAT: Country = Country { code: *b"MS", rev: 0 }; -/// MA Morocco -pub const MOROCCO: Country = Country { code: *b"MA", rev: 0 }; -/// MZ Mozambique -pub const MOZAMBIQUE: Country = Country { code: *b"MZ", rev: 0 }; -/// MM Myanmar -pub const MYANMAR: Country = Country { code: *b"MM", rev: 0 }; -/// NA Namibia -pub const NAMIBIA: Country = Country { code: *b"NA", rev: 0 }; -/// NR Nauru -pub const NAURU: Country = Country { code: *b"NR", rev: 0 }; -/// NP Nepal -pub const NEPAL: Country = Country { code: *b"NP", rev: 0 }; -/// NL Netherlands -pub const NETHERLANDS: Country = Country { code: *b"NL", rev: 0 }; -/// AN Netherlands_Antilles -pub const NETHERLANDS_ANTILLES: Country = Country { code: *b"AN", rev: 0 }; -/// NC New_Caledonia -pub const NEW_CALEDONIA: Country = Country { code: *b"NC", rev: 0 }; -/// NZ New_Zealand -pub const NEW_ZEALAND: Country = Country { code: *b"NZ", rev: 0 }; -/// NI Nicaragua -pub const NICARAGUA: Country = Country { code: *b"NI", rev: 0 }; -/// NE Niger -pub const NIGER: Country = Country { code: *b"NE", rev: 0 }; -/// NG Nigeria -pub const NIGERIA: Country = Country { code: *b"NG", rev: 0 }; -/// NF Norfolk_Island -pub const NORFOLK_ISLAND: Country = Country { code: *b"NF", rev: 0 }; -/// MP Northern_Mariana_Islands -pub const NORTHERN_MARIANA_ISLANDS: Country = Country { code: *b"MP", rev: 0 }; -/// NO Norway -pub const NORWAY: Country = Country { code: *b"NO", rev: 0 }; -/// OM Oman -pub const OMAN: Country = Country { code: *b"OM", rev: 0 }; -/// PK Pakistan -pub const PAKISTAN: Country = Country { code: *b"PK", rev: 0 }; -/// PW Palau -pub const PALAU: Country = Country { code: *b"PW", rev: 0 }; -/// PA Panama -pub const PANAMA: Country = Country { code: *b"PA", rev: 0 }; -/// PG Papua_New_Guinea -pub const PAPUA_NEW_GUINEA: Country = Country { code: *b"PG", rev: 0 }; -/// PY Paraguay -pub const PARAGUAY: Country = Country { code: *b"PY", rev: 0 }; -/// PE Peru -pub const PERU: Country = Country { code: *b"PE", rev: 0 }; -/// PH Philippines -pub const PHILIPPINES: Country = Country { code: *b"PH", rev: 0 }; -/// PL Poland -pub const POLAND: Country = Country { code: *b"PL", rev: 0 }; -/// PT Portugal -pub const PORTUGAL: Country = Country { code: *b"PT", rev: 0 }; -/// PR Pueto_Rico -pub const PUETO_RICO: Country = Country { code: *b"PR", rev: 0 }; -/// QA Qatar -pub const QATAR: Country = Country { code: *b"QA", rev: 0 }; -/// RE Reunion -pub const REUNION: Country = Country { code: *b"RE", rev: 0 }; -/// RO Romania -pub const ROMANIA: Country = Country { code: *b"RO", rev: 0 }; -/// RU Russian_Federation -pub const RUSSIAN_FEDERATION: Country = Country { code: *b"RU", rev: 0 }; -/// RW Rwanda -pub const RWANDA: Country = Country { code: *b"RW", rev: 0 }; -/// KN Saint_Kitts_and_Nevis -pub const SAINT_KITTS_AND_NEVIS: Country = Country { code: *b"KN", rev: 0 }; -/// LC Saint_Lucia -pub const SAINT_LUCIA: Country = Country { code: *b"LC", rev: 0 }; -/// PM Saint_Pierre_and_Miquelon -pub const SAINT_PIERRE_AND_MIQUELON: Country = Country { code: *b"PM", rev: 0 }; -/// VC Saint_Vincent_and_The_Grenadines -pub const SAINT_VINCENT_AND_THE_GRENADINES: Country = Country { code: *b"VC", rev: 0 }; -/// WS Samoa -pub const SAMOA: Country = Country { code: *b"WS", rev: 0 }; -/// MF Sanit_Martin_/_Sint_Marteen -pub const SANIT_MARTIN_SINT_MARTEEN: Country = Country { code: *b"MF", rev: 0 }; -/// ST Sao_Tome_and_Principe -pub const SAO_TOME_AND_PRINCIPE: Country = Country { code: *b"ST", rev: 0 }; -/// SA Saudi_Arabia -pub const SAUDI_ARABIA: Country = Country { code: *b"SA", rev: 0 }; -/// SN Senegal -pub const SENEGAL: Country = Country { code: *b"SN", rev: 0 }; -/// RS Serbia -pub const SERBIA: Country = Country { code: *b"RS", rev: 0 }; -/// SC Seychelles -pub const SEYCHELLES: Country = Country { code: *b"SC", rev: 0 }; -/// SL Sierra_Leone -pub const SIERRA_LEONE: Country = Country { code: *b"SL", rev: 0 }; -/// SG Singapore -pub const SINGAPORE: Country = Country { code: *b"SG", rev: 0 }; -/// SK Slovakia -pub const SLOVAKIA: Country = Country { code: *b"SK", rev: 0 }; -/// SI Slovenia -pub const SLOVENIA: Country = Country { code: *b"SI", rev: 0 }; -/// SB Solomon_Islands -pub const SOLOMON_ISLANDS: Country = Country { code: *b"SB", rev: 0 }; -/// SO Somalia -pub const SOMALIA: Country = Country { code: *b"SO", rev: 0 }; -/// ZA South_Africa -pub const SOUTH_AFRICA: Country = Country { code: *b"ZA", rev: 0 }; -/// ES Spain -pub const SPAIN: Country = Country { code: *b"ES", rev: 0 }; -/// LK Sri_Lanka -pub const SRI_LANKA: Country = Country { code: *b"LK", rev: 0 }; -/// SR Suriname -pub const SURINAME: Country = Country { code: *b"SR", rev: 0 }; -/// SZ Swaziland -pub const SWAZILAND: Country = Country { code: *b"SZ", rev: 0 }; -/// SE Sweden -pub const SWEDEN: Country = Country { code: *b"SE", rev: 0 }; -/// CH Switzerland -pub const SWITZERLAND: Country = Country { code: *b"CH", rev: 0 }; -/// SY Syrian_Arab_Republic -pub const SYRIAN_ARAB_REPUBLIC: Country = Country { code: *b"SY", rev: 0 }; -/// TW Taiwan,_Province_Of_China -pub const TAIWAN_PROVINCE_OF_CHINA: Country = Country { code: *b"TW", rev: 0 }; -/// TJ Tajikistan -pub const TAJIKISTAN: Country = Country { code: *b"TJ", rev: 0 }; -/// TZ Tanzania,_United_Republic_Of -pub const TANZANIA_UNITED_REPUBLIC_OF: Country = Country { code: *b"TZ", rev: 0 }; -/// TH Thailand -pub const THAILAND: Country = Country { code: *b"TH", rev: 0 }; -/// TG Togo -pub const TOGO: Country = Country { code: *b"TG", rev: 0 }; -/// TO Tonga -pub const TONGA: Country = Country { code: *b"TO", rev: 0 }; -/// TT Trinidad_and_Tobago -pub const TRINIDAD_AND_TOBAGO: Country = Country { code: *b"TT", rev: 0 }; -/// TN Tunisia -pub const TUNISIA: Country = Country { code: *b"TN", rev: 0 }; -/// TR Turkey -pub const TURKEY: Country = Country { code: *b"TR", rev: 0 }; -/// TM Turkmenistan -pub const TURKMENISTAN: Country = Country { code: *b"TM", rev: 0 }; -/// TC Turks_and_Caicos_Islands -pub const TURKS_AND_CAICOS_ISLANDS: Country = Country { code: *b"TC", rev: 0 }; -/// TV Tuvalu -pub const TUVALU: Country = Country { code: *b"TV", rev: 0 }; -/// UG Uganda -pub const UGANDA: Country = Country { code: *b"UG", rev: 0 }; -/// UA Ukraine -pub const UKRAINE: Country = Country { code: *b"UA", rev: 0 }; -/// AE United_Arab_Emirates -pub const UNITED_ARAB_EMIRATES: Country = Country { code: *b"AE", rev: 0 }; -/// GB United_Kingdom -pub const UNITED_KINGDOM: Country = Country { code: *b"GB", rev: 0 }; -/// US United_States -pub const UNITED_STATES: Country = Country { code: *b"US", rev: 0 }; -/// US United_States Revision 4 -pub const UNITED_STATES_REV4: Country = Country { code: *b"US", rev: 4 }; -/// Q1 United_States Revision 931 -pub const UNITED_STATES_REV931: Country = Country { code: *b"Q1", rev: 931 }; -/// Q2 United_States_(No_DFS) -pub const UNITED_STATES_NO_DFS: Country = Country { code: *b"Q2", rev: 0 }; -/// UM United_States_Minor_Outlying_Islands -pub const UNITED_STATES_MINOR_OUTLYING_ISLANDS: Country = Country { code: *b"UM", rev: 0 }; -/// UY Uruguay -pub const URUGUAY: Country = Country { code: *b"UY", rev: 0 }; -/// UZ Uzbekistan -pub const UZBEKISTAN: Country = Country { code: *b"UZ", rev: 0 }; -/// VU Vanuatu -pub const VANUATU: Country = Country { code: *b"VU", rev: 0 }; -/// VE Venezuela -pub const VENEZUELA: Country = Country { code: *b"VE", rev: 0 }; -/// VN Viet_Nam -pub const VIET_NAM: Country = Country { code: *b"VN", rev: 0 }; -/// VG Virgin_Islands,_British -pub const VIRGIN_ISLANDS_BRITISH: Country = Country { code: *b"VG", rev: 0 }; -/// VI Virgin_Islands,_U.S. -pub const VIRGIN_ISLANDS_US: Country = Country { code: *b"VI", rev: 0 }; -/// WF Wallis_and_Futuna -pub const WALLIS_AND_FUTUNA: Country = Country { code: *b"WF", rev: 0 }; -/// 0C West_Bank -pub const WEST_BANK: Country = Country { code: *b"0C", rev: 0 }; -/// EH Western_Sahara -pub const WESTERN_SAHARA: Country = Country { code: *b"EH", rev: 0 }; -/// Worldwide Locale Revision 983 -pub const WORLD_WIDE_XV_REV983: Country = Country { code: *b"XV", rev: 983 }; -/// Worldwide Locale (passive Ch12-14) -pub const WORLD_WIDE_XX: Country = Country { code: *b"XX", rev: 0 }; -/// Worldwide Locale (passive Ch12-14) Revision 17 -pub const WORLD_WIDE_XX_REV17: Country = Country { code: *b"XX", rev: 17 }; -/// YE Yemen -pub const YEMEN: Country = Country { code: *b"YE", rev: 0 }; -/// ZM Zambia -pub const ZAMBIA: Country = Country { code: *b"ZM", rev: 0 }; -/// ZW Zimbabwe -pub const ZIMBABWE: Country = Country { code: *b"ZW", rev: 0 }; diff --git a/src/events.rs b/src/events.rs deleted file mode 100644 index a94c49a0c..000000000 --- a/src/events.rs +++ /dev/null @@ -1,400 +0,0 @@ -#![allow(dead_code)] -#![allow(non_camel_case_types)] - -use core::cell::RefCell; - -use embassy_sync::blocking_mutex::raw::NoopRawMutex; -use embassy_sync::pubsub::{PubSubChannel, Subscriber}; - -use crate::structs::BssInfo; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, num_enum::FromPrimitive)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(u8)] -pub enum Event { - #[num_enum(default)] - Unknown = 0xFF, - /// indicates status of set SSID - SET_SSID = 0, - /// differentiates join IBSS from found (START) IBSS - JOIN = 1, - /// STA founded an IBSS or AP started a BSS - START = 2, - /// 802.11 AUTH request - AUTH = 3, - /// 802.11 AUTH indication - AUTH_IND = 4, - /// 802.11 DEAUTH request - DEAUTH = 5, - /// 802.11 DEAUTH indication - DEAUTH_IND = 6, - /// 802.11 ASSOC request - ASSOC = 7, - /// 802.11 ASSOC indication - ASSOC_IND = 8, - /// 802.11 REASSOC request - REASSOC = 9, - /// 802.11 REASSOC indication - REASSOC_IND = 10, - /// 802.11 DISASSOC request - DISASSOC = 11, - /// 802.11 DISASSOC indication - DISASSOC_IND = 12, - /// 802.11h Quiet period started - QUIET_START = 13, - /// 802.11h Quiet period ended - QUIET_END = 14, - /// BEACONS received/lost indication - BEACON_RX = 15, - /// generic link indication - LINK = 16, - /// TKIP MIC error occurred - MIC_ERROR = 17, - /// NDIS style link indication - NDIS_LINK = 18, - /// roam attempt occurred: indicate status & reason - ROAM = 19, - /// change in dot11FailedCount (txfail) - TXFAIL = 20, - /// WPA2 pmkid cache indication - PMKID_CACHE = 21, - /// current AP's TSF value went backward - RETROGRADE_TSF = 22, - /// AP was pruned from join list for reason - PRUNE = 23, - /// report AutoAuth table entry match for join attempt - AUTOAUTH = 24, - /// Event encapsulating an EAPOL message - EAPOL_MSG = 25, - /// Scan results are ready or scan was aborted - SCAN_COMPLETE = 26, - /// indicate to host addts fail/success - ADDTS_IND = 27, - /// indicate to host delts fail/success - DELTS_IND = 28, - /// indicate to host of beacon transmit - BCNSENT_IND = 29, - /// Send the received beacon up to the host - BCNRX_MSG = 30, - /// indicate to host loss of beacon - BCNLOST_MSG = 31, - /// before attempting to roam - ROAM_PREP = 32, - /// PFN network found event - PFN_NET_FOUND = 33, - /// PFN network lost event - PFN_NET_LOST = 34, - RESET_COMPLETE = 35, - JOIN_START = 36, - ROAM_START = 37, - ASSOC_START = 38, - IBSS_ASSOC = 39, - RADIO = 40, - /// PSM microcode watchdog fired - PSM_WATCHDOG = 41, - /// CCX association start - CCX_ASSOC_START = 42, - /// CCX association abort - CCX_ASSOC_ABORT = 43, - /// probe request received - PROBREQ_MSG = 44, - SCAN_CONFIRM_IND = 45, - /// WPA Handshake - PSK_SUP = 46, - COUNTRY_CODE_CHANGED = 47, - /// WMMAC excedded medium time - EXCEEDED_MEDIUM_TIME = 48, - /// WEP ICV error occurred - ICV_ERROR = 49, - /// Unsupported unicast encrypted frame - UNICAST_DECODE_ERROR = 50, - /// Unsupported multicast encrypted frame - MULTICAST_DECODE_ERROR = 51, - TRACE = 52, - /// BT-AMP HCI event - BTA_HCI_EVENT = 53, - /// I/F change (for wlan host notification) - IF = 54, - /// P2P Discovery listen state expires - P2P_DISC_LISTEN_COMPLETE = 55, - /// indicate RSSI change based on configured levels - RSSI = 56, - /// PFN best network batching event - PFN_BEST_BATCHING = 57, - EXTLOG_MSG = 58, - /// Action frame reception - ACTION_FRAME = 59, - /// Action frame Tx complete - ACTION_FRAME_COMPLETE = 60, - /// assoc request received - PRE_ASSOC_IND = 61, - /// re-assoc request received - PRE_REASSOC_IND = 62, - /// channel adopted (xxx: obsoleted) - CHANNEL_ADOPTED = 63, - /// AP started - AP_STARTED = 64, - /// AP stopped due to DFS - DFS_AP_STOP = 65, - /// AP resumed due to DFS - DFS_AP_RESUME = 66, - /// WAI stations event - WAI_STA_EVENT = 67, - /// event encapsulating an WAI message - WAI_MSG = 68, - /// escan result event - ESCAN_RESULT = 69, - /// action frame off channel complete - ACTION_FRAME_OFF_CHAN_COMPLETE = 70, - /// probe response received - PROBRESP_MSG = 71, - /// P2P Probe request received - P2P_PROBREQ_MSG = 72, - DCS_REQUEST = 73, - /// credits for D11 FIFOs. [AC0,AC1,AC2,AC3,BC_MC,ATIM] - FIFO_CREDIT_MAP = 74, - /// Received action frame event WITH wl_event_rx_frame_data_t header - ACTION_FRAME_RX = 75, - /// Wake Event timer fired, used for wake WLAN test mode - WAKE_EVENT = 76, - /// Radio measurement complete - RM_COMPLETE = 77, - /// Synchronize TSF with the host - HTSFSYNC = 78, - /// request an overlay IOCTL/iovar from the host - OVERLAY_REQ = 79, - CSA_COMPLETE_IND = 80, - /// excess PM Wake Event to inform host - EXCESS_PM_WAKE_EVENT = 81, - /// no PFN networks around - PFN_SCAN_NONE = 82, - /// last found PFN network gets lost - PFN_SCAN_ALLGONE = 83, - GTK_PLUMBED = 84, - /// 802.11 ASSOC indication for NDIS only - ASSOC_IND_NDIS = 85, - /// 802.11 REASSOC indication for NDIS only - REASSOC_IND_NDIS = 86, - ASSOC_REQ_IE = 87, - ASSOC_RESP_IE = 88, - /// association recreated on resume - ASSOC_RECREATED = 89, - /// rx action frame event for NDIS only - ACTION_FRAME_RX_NDIS = 90, - /// authentication request received - AUTH_REQ = 91, - /// fast assoc recreation failed - SPEEDY_RECREATE_FAIL = 93, - /// port-specific event and payload (e.g. NDIS) - NATIVE = 94, - /// event for tx pkt delay suddently jump - PKTDELAY_IND = 95, - /// AWDL AW period starts - AWDL_AW = 96, - /// AWDL Master/Slave/NE master role event - AWDL_ROLE = 97, - /// Generic AWDL event - AWDL_EVENT = 98, - /// NIC AF txstatus - NIC_AF_TXS = 99, - /// NAN event - NAN = 100, - BEACON_FRAME_RX = 101, - /// desired service found - SERVICE_FOUND = 102, - /// GAS fragment received - GAS_FRAGMENT_RX = 103, - /// GAS sessions all complete - GAS_COMPLETE = 104, - /// New device found by p2p offload - P2PO_ADD_DEVICE = 105, - /// device has been removed by p2p offload - P2PO_DEL_DEVICE = 106, - /// WNM event to notify STA enter sleep mode - WNM_STA_SLEEP = 107, - /// Indication of MAC tx failures (exhaustion of 802.11 retries) exceeding threshold(s) - TXFAIL_THRESH = 108, - /// Proximity Detection event - PROXD = 109, - /// AWDL RX Probe response - AWDL_RX_PRB_RESP = 111, - /// AWDL RX Action Frames - AWDL_RX_ACT_FRAME = 112, - /// AWDL Wowl nulls - AWDL_WOWL_NULLPKT = 113, - /// AWDL Phycal status - AWDL_PHYCAL_STATUS = 114, - /// AWDL OOB AF status - AWDL_OOB_AF_STATUS = 115, - /// Interleaved Scan status - AWDL_SCAN_STATUS = 116, - /// AWDL AW Start - AWDL_AW_START = 117, - /// AWDL AW End - AWDL_AW_END = 118, - /// AWDL AW Extensions - AWDL_AW_EXT = 119, - AWDL_PEER_CACHE_CONTROL = 120, - CSA_START_IND = 121, - CSA_DONE_IND = 122, - CSA_FAILURE_IND = 123, - /// CCA based channel quality report - CCA_CHAN_QUAL = 124, - /// to report change in BSSID while roaming - BSSID = 125, - /// tx error indication - TX_STAT_ERROR = 126, - /// credit check for BCMC supported - BCMC_CREDIT_SUPPORT = 127, - /// psta primary interface indication - PSTA_PRIMARY_INTF_IND = 128, - /// Handover Request Initiated - BT_WIFI_HANDOVER_REQ = 130, - /// Southpaw TxInhibit notification - SPW_TXINHIBIT = 131, - /// FBT Authentication Request Indication - FBT_AUTH_REQ_IND = 132, - /// Enhancement addition for RSSI - RSSI_LQM = 133, - /// Full probe/beacon (IEs etc) results - PFN_GSCAN_FULL_RESULT = 134, - /// Significant change in rssi of bssids being tracked - PFN_SWC = 135, - /// a STA been authroized for traffic - AUTHORIZED = 136, - /// probe req with wl_event_rx_frame_data_t header - PROBREQ_MSG_RX = 137, - /// PFN completed scan of network list - PFN_SCAN_COMPLETE = 138, - /// RMC Event - RMC_EVENT = 139, - /// DPSTA interface indication - DPSTA_INTF_IND = 140, - /// RRM Event - RRM = 141, - /// ULP entry event - ULP = 146, - /// TCP Keep Alive Offload Event - TKO = 151, - /// authentication request received - EXT_AUTH_REQ = 187, - /// authentication request received - EXT_AUTH_FRAME_RX = 188, - /// mgmt frame Tx complete - MGMT_FRAME_TXSTATUS = 189, - /// highest val + 1 for range checking - LAST = 190, -} - -// TODO this PubSub can probably be replaced with shared memory to make it a bit more efficient. -pub type EventQueue = PubSubChannel; -pub type EventSubscriber<'a> = Subscriber<'a, NoopRawMutex, Message, 2, 1, 1>; - -pub struct Events { - pub queue: EventQueue, - pub mask: SharedEventMask, -} - -impl Events { - pub fn new() -> Self { - Self { - queue: EventQueue::new(), - mask: SharedEventMask::default(), - } - } -} - -#[derive(Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Status { - pub event_type: Event, - pub status: u32, -} - -#[derive(Clone, Copy)] -pub enum Payload { - None, - BssInfo(BssInfo), -} - -#[derive(Clone, Copy)] - -pub struct Message { - pub header: Status, - pub payload: Payload, -} - -impl Message { - pub fn new(status: Status, payload: Payload) -> Self { - Self { - header: status, - payload, - } - } -} - -#[derive(Default)] -struct EventMask { - mask: [u32; Self::WORD_COUNT], -} - -impl EventMask { - const WORD_COUNT: usize = ((Event::LAST as u32 + (u32::BITS - 1)) / u32::BITS) as usize; - - fn enable(&mut self, event: Event) { - let n = event as u32; - let word = n / u32::BITS; - let bit = n % u32::BITS; - - self.mask[word as usize] |= 1 << bit; - } - - fn disable(&mut self, event: Event) { - let n = event as u32; - let word = n / u32::BITS; - let bit = n % u32::BITS; - - self.mask[word as usize] &= !(1 << bit); - } - - fn is_enabled(&self, event: Event) -> bool { - let n = event as u32; - let word = n / u32::BITS; - let bit = n % u32::BITS; - - self.mask[word as usize] & (1 << bit) > 0 - } -} - -#[derive(Default)] - -pub struct SharedEventMask { - mask: RefCell, -} - -impl SharedEventMask { - pub fn enable(&self, events: &[Event]) { - let mut mask = self.mask.borrow_mut(); - for event in events { - mask.enable(*event); - } - } - - #[allow(dead_code)] - pub fn disable(&self, events: &[Event]) { - let mut mask = self.mask.borrow_mut(); - for event in events { - mask.disable(*event); - } - } - - pub fn disable_all(&self) { - let mut mask = self.mask.borrow_mut(); - mask.mask = Default::default(); - } - - pub fn is_enabled(&self, event: Event) -> bool { - let mask = self.mask.borrow(); - mask.is_enabled(event) - } -} diff --git a/src/fmt.rs b/src/fmt.rs deleted file mode 100644 index 5730447b3..000000000 --- a/src/fmt.rs +++ /dev/null @@ -1,257 +0,0 @@ -#![macro_use] -#![allow(unused_macros)] - -use core::fmt::{Debug, Display, LowerHex}; - -#[cfg(all(feature = "defmt", feature = "log"))] -compile_error!("You may not enable both `defmt` and `log` features."); - -macro_rules! assert { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::assert!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::assert!($($x)*); - } - }; -} - -macro_rules! assert_eq { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::assert_eq!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::assert_eq!($($x)*); - } - }; -} - -macro_rules! assert_ne { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::assert_ne!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::assert_ne!($($x)*); - } - }; -} - -macro_rules! debug_assert { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::debug_assert!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::debug_assert!($($x)*); - } - }; -} - -macro_rules! debug_assert_eq { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::debug_assert_eq!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::debug_assert_eq!($($x)*); - } - }; -} - -macro_rules! debug_assert_ne { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::debug_assert_ne!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::debug_assert_ne!($($x)*); - } - }; -} - -macro_rules! todo { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::todo!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::todo!($($x)*); - } - }; -} - -macro_rules! unreachable { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::unreachable!($($x)*); - } - }; -} - -macro_rules! panic { - ($($x:tt)*) => { - { - #[cfg(not(feature = "defmt"))] - ::core::panic!($($x)*); - #[cfg(feature = "defmt")] - ::defmt::panic!($($x)*); - } - }; -} - -macro_rules! trace { - ($s:literal $(, $x:expr)* $(,)?) => { - { - #[cfg(feature = "log")] - ::log::trace!($s $(, $x)*); - #[cfg(feature = "defmt")] - ::defmt::trace!($s $(, $x)*); - #[cfg(not(any(feature = "log", feature="defmt")))] - let _ = ($( & $x ),*); - } - }; -} - -macro_rules! debug { - ($s:literal $(, $x:expr)* $(,)?) => { - { - #[cfg(feature = "log")] - ::log::debug!($s $(, $x)*); - #[cfg(feature = "defmt")] - ::defmt::debug!($s $(, $x)*); - #[cfg(not(any(feature = "log", feature="defmt")))] - let _ = ($( & $x ),*); - } - }; -} - -macro_rules! info { - ($s:literal $(, $x:expr)* $(,)?) => { - { - #[cfg(feature = "log")] - ::log::info!($s $(, $x)*); - #[cfg(feature = "defmt")] - ::defmt::info!($s $(, $x)*); - #[cfg(not(any(feature = "log", feature="defmt")))] - let _ = ($( & $x ),*); - } - }; -} - -macro_rules! warn { - ($s:literal $(, $x:expr)* $(,)?) => { - { - #[cfg(feature = "log")] - ::log::warn!($s $(, $x)*); - #[cfg(feature = "defmt")] - ::defmt::warn!($s $(, $x)*); - #[cfg(not(any(feature = "log", feature="defmt")))] - let _ = ($( & $x ),*); - } - }; -} - -macro_rules! error { - ($s:literal $(, $x:expr)* $(,)?) => { - { - #[cfg(feature = "log")] - ::log::error!($s $(, $x)*); - #[cfg(feature = "defmt")] - ::defmt::error!($s $(, $x)*); - #[cfg(not(any(feature = "log", feature="defmt")))] - let _ = ($( & $x ),*); - } - }; -} - -#[cfg(feature = "defmt")] -macro_rules! unwrap { - ($($x:tt)*) => { - ::defmt::unwrap!($($x)*) - }; -} - -#[cfg(not(feature = "defmt"))] -macro_rules! unwrap { - ($arg:expr) => { - match $crate::fmt::Try::into_result($arg) { - ::core::result::Result::Ok(t) => t, - ::core::result::Result::Err(e) => { - ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); - } - } - }; - ($arg:expr, $($msg:expr),+ $(,)? ) => { - match $crate::fmt::Try::into_result($arg) { - ::core::result::Result::Ok(t) => t, - ::core::result::Result::Err(e) => { - ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); - } - } - } -} - -#[cfg(feature = "defmt-timestamp-uptime")] -defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() } - -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub struct NoneError; - -pub trait Try { - type Ok; - type Error; - fn into_result(self) -> Result; -} - -impl Try for Option { - type Ok = T; - type Error = NoneError; - - #[inline] - fn into_result(self) -> Result { - self.ok_or(NoneError) - } -} - -impl Try for Result { - type Ok = T; - type Error = E; - - #[inline] - fn into_result(self) -> Self { - self - } -} - -pub struct Bytes<'a>(pub &'a [u8]); - -impl<'a> Debug for Bytes<'a> { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{:#02x?}", self.0) - } -} - -impl<'a> Display for Bytes<'a> { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{:#02x?}", self.0) - } -} - -impl<'a> LowerHex for Bytes<'a> { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{:#02x?}", self.0) - } -} - -#[cfg(feature = "defmt")] -impl<'a> defmt::Format for Bytes<'a> { - fn format(&self, fmt: defmt::Formatter) { - defmt::write!(fmt, "{:02x}", self.0) - } -} diff --git a/src/ioctl.rs b/src/ioctl.rs deleted file mode 100644 index 61524c274..000000000 --- a/src/ioctl.rs +++ /dev/null @@ -1,126 +0,0 @@ -use core::cell::{Cell, RefCell}; -use core::future::poll_fn; -use core::task::{Poll, Waker}; - -use embassy_sync::waitqueue::WakerRegistration; - -use crate::fmt::Bytes; - -#[derive(Clone, Copy)] -pub enum IoctlType { - Get = 0, - Set = 2, -} - -#[derive(Clone, Copy)] -pub struct PendingIoctl { - pub buf: *mut [u8], - pub kind: IoctlType, - pub cmd: u32, - pub iface: u32, -} - -#[derive(Clone, Copy)] -enum IoctlStateInner { - Pending(PendingIoctl), - Sent { buf: *mut [u8] }, - Done { resp_len: usize }, -} - -struct Wakers { - control: WakerRegistration, - runner: WakerRegistration, -} - -impl Default for Wakers { - fn default() -> Self { - Self { - control: WakerRegistration::new(), - runner: WakerRegistration::new(), - } - } -} - -pub struct IoctlState { - state: Cell, - wakers: RefCell, -} - -impl IoctlState { - pub fn new() -> Self { - Self { - state: Cell::new(IoctlStateInner::Done { resp_len: 0 }), - wakers: Default::default(), - } - } - - fn wake_control(&self) { - self.wakers.borrow_mut().control.wake(); - } - - fn register_control(&self, waker: &Waker) { - self.wakers.borrow_mut().control.register(waker); - } - - fn wake_runner(&self) { - self.wakers.borrow_mut().runner.wake(); - } - - fn register_runner(&self, waker: &Waker) { - self.wakers.borrow_mut().runner.register(waker); - } - - pub async fn wait_complete(&self) -> usize { - poll_fn(|cx| { - if let IoctlStateInner::Done { resp_len } = self.state.get() { - Poll::Ready(resp_len) - } else { - self.register_control(cx.waker()); - Poll::Pending - } - }) - .await - } - - pub async fn wait_pending(&self) -> PendingIoctl { - let pending = poll_fn(|cx| { - if let IoctlStateInner::Pending(pending) = self.state.get() { - Poll::Ready(pending) - } else { - self.register_runner(cx.waker()); - Poll::Pending - } - }) - .await; - - self.state.set(IoctlStateInner::Sent { buf: pending.buf }); - pending - } - - pub fn cancel_ioctl(&self) { - self.state.set(IoctlStateInner::Done { resp_len: 0 }); - } - - pub async fn do_ioctl(&self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize { - self.state - .set(IoctlStateInner::Pending(PendingIoctl { buf, kind, cmd, iface })); - self.wake_runner(); - self.wait_complete().await - } - - pub fn ioctl_done(&self, response: &[u8]) { - if let IoctlStateInner::Sent { buf } = self.state.get() { - trace!("IOCTL Response: {:02x}", Bytes(response)); - - // TODO fix this - (unsafe { &mut *buf }[..response.len()]).copy_from_slice(response); - - self.state.set(IoctlStateInner::Done { - resp_len: response.len(), - }); - self.wake_control(); - } else { - warn!("IOCTL Response but no pending Ioctl"); - } - } -} diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index fd11f3674..000000000 --- a/src/lib.rs +++ /dev/null @@ -1,236 +0,0 @@ -#![no_std] -#![no_main] -#![allow(incomplete_features)] -#![feature(async_fn_in_trait, type_alias_impl_trait, concat_bytes)] -#![deny(unused_must_use)] - -// This mod MUST go first, so that the others see its macros. -pub(crate) mod fmt; - -mod bus; -mod consts; -mod countries; -mod events; -mod ioctl; -mod structs; - -mod control; -mod nvram; -mod runner; - -use core::slice; - -use embassy_net_driver_channel as ch; -use embedded_hal_1::digital::OutputPin; -use events::Events; -use ioctl::IoctlState; - -use crate::bus::Bus; -pub use crate::bus::SpiBusCyw43; -pub use crate::control::{Control, Error as ControlError}; -pub use crate::runner::Runner; -pub use crate::structs::BssInfo; - -const MTU: usize = 1514; - -#[allow(unused)] -#[derive(Clone, Copy, PartialEq, Eq)] -enum Core { - WLAN = 0, - SOCSRAM = 1, - SDIOD = 2, -} - -impl Core { - fn base_addr(&self) -> u32 { - match self { - Self::WLAN => CHIP.arm_core_base_address, - Self::SOCSRAM => CHIP.socsram_wrapper_base_address, - Self::SDIOD => CHIP.sdiod_core_base_address, - } - } -} - -#[allow(unused)] -struct Chip { - arm_core_base_address: u32, - socsram_base_address: u32, - socsram_wrapper_base_address: u32, - sdiod_core_base_address: u32, - pmu_base_address: u32, - chip_ram_size: u32, - atcm_ram_base_address: u32, - socram_srmem_size: u32, - chanspec_band_mask: u32, - chanspec_band_2g: u32, - chanspec_band_5g: u32, - chanspec_band_shift: u32, - chanspec_bw_10: u32, - chanspec_bw_20: u32, - chanspec_bw_40: u32, - chanspec_bw_mask: u32, - chanspec_bw_shift: u32, - chanspec_ctl_sb_lower: u32, - chanspec_ctl_sb_upper: u32, - chanspec_ctl_sb_none: u32, - chanspec_ctl_sb_mask: u32, -} - -const WRAPPER_REGISTER_OFFSET: u32 = 0x100000; - -// Data for CYW43439 -const CHIP: Chip = Chip { - arm_core_base_address: 0x18003000 + WRAPPER_REGISTER_OFFSET, - socsram_base_address: 0x18004000, - socsram_wrapper_base_address: 0x18004000 + WRAPPER_REGISTER_OFFSET, - sdiod_core_base_address: 0x18002000, - pmu_base_address: 0x18000000, - chip_ram_size: 512 * 1024, - atcm_ram_base_address: 0, - socram_srmem_size: 64 * 1024, - chanspec_band_mask: 0xc000, - chanspec_band_2g: 0x0000, - chanspec_band_5g: 0xc000, - chanspec_band_shift: 14, - chanspec_bw_10: 0x0800, - chanspec_bw_20: 0x1000, - chanspec_bw_40: 0x1800, - chanspec_bw_mask: 0x3800, - chanspec_bw_shift: 11, - chanspec_ctl_sb_lower: 0x0000, - chanspec_ctl_sb_upper: 0x0100, - chanspec_ctl_sb_none: 0x0000, - chanspec_ctl_sb_mask: 0x0700, -}; - -pub struct State { - ioctl_state: IoctlState, - ch: ch::State, - events: Events, -} - -impl State { - pub fn new() -> Self { - Self { - ioctl_state: IoctlState::new(), - ch: ch::State::new(), - events: Events::new(), - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum PowerManagementMode { - /// Custom, officially unsupported mode. Use at your own risk. - /// All power-saving features set to their max at only a marginal decrease in power consumption - /// as oppposed to `Aggressive`. - SuperSave, - - /// Aggressive power saving mode. - Aggressive, - - /// The default mode. - PowerSave, - - /// Performance is prefered over power consumption but still some power is conserved as opposed to - /// `None`. - Performance, - - /// Unlike all the other PM modes, this lowers the power consumption at all times at the cost of - /// a much lower throughput. - ThroughputThrottling, - - /// No power management is configured. This consumes the most power. - None, -} - -impl Default for PowerManagementMode { - fn default() -> Self { - Self::PowerSave - } -} - -impl PowerManagementMode { - fn sleep_ret_ms(&self) -> u16 { - match self { - PowerManagementMode::SuperSave => 2000, - PowerManagementMode::Aggressive => 2000, - PowerManagementMode::PowerSave => 200, - PowerManagementMode::Performance => 20, - PowerManagementMode::ThroughputThrottling => 0, // value doesn't matter - PowerManagementMode::None => 0, // value doesn't matter - } - } - - fn beacon_period(&self) -> u8 { - match self { - PowerManagementMode::SuperSave => 255, - PowerManagementMode::Aggressive => 1, - PowerManagementMode::PowerSave => 1, - PowerManagementMode::Performance => 1, - PowerManagementMode::ThroughputThrottling => 0, // value doesn't matter - PowerManagementMode::None => 0, // value doesn't matter - } - } - - fn dtim_period(&self) -> u8 { - match self { - PowerManagementMode::SuperSave => 255, - PowerManagementMode::Aggressive => 1, - PowerManagementMode::PowerSave => 1, - PowerManagementMode::Performance => 1, - PowerManagementMode::ThroughputThrottling => 0, // value doesn't matter - PowerManagementMode::None => 0, // value doesn't matter - } - } - - fn assoc(&self) -> u8 { - match self { - PowerManagementMode::SuperSave => 255, - PowerManagementMode::Aggressive => 10, - PowerManagementMode::PowerSave => 10, - PowerManagementMode::Performance => 1, - PowerManagementMode::ThroughputThrottling => 0, // value doesn't matter - PowerManagementMode::None => 0, // value doesn't matter - } - } - - fn mode(&self) -> u32 { - match self { - PowerManagementMode::ThroughputThrottling => 1, - PowerManagementMode::None => 0, - _ => 2, - } - } -} - -pub type NetDriver<'a> = ch::Device<'a, MTU>; - -pub async fn new<'a, PWR, SPI>( - state: &'a mut State, - pwr: PWR, - spi: SPI, - firmware: &[u8], -) -> (NetDriver<'a>, Control<'a>, Runner<'a, PWR, SPI>) -where - PWR: OutputPin, - SPI: SpiBusCyw43, -{ - let (ch_runner, device) = ch::new(&mut state.ch, [0; 6]); - let state_ch = ch_runner.state_runner(); - - let mut runner = Runner::new(ch_runner, Bus::new(pwr, spi), &state.ioctl_state, &state.events); - - runner.init(firmware).await; - - ( - device, - Control::new(state_ch, &state.events, &state.ioctl_state), - runner, - ) -} - -fn slice8_mut(x: &mut [u32]) -> &mut [u8] { - let len = x.len() * 4; - unsafe { slice::from_raw_parts_mut(x.as_mut_ptr() as _, len) } -} diff --git a/src/nvram.rs b/src/nvram.rs deleted file mode 100644 index 964a3128d..000000000 --- a/src/nvram.rs +++ /dev/null @@ -1,54 +0,0 @@ -macro_rules! nvram { - ($($s:literal,)*) => { - concat_bytes!($($s, b"\x00",)* b"\x00\x00") - }; -} - -pub static NVRAM: &'static [u8] = &*nvram!( - b"NVRAMRev=$Rev$", - b"manfid=0x2d0", - b"prodid=0x0727", - b"vendid=0x14e4", - b"devid=0x43e2", - b"boardtype=0x0887", - b"boardrev=0x1100", - b"boardnum=22", - b"macaddr=00:A0:50:b5:59:5e", - b"sromrev=11", - b"boardflags=0x00404001", - b"boardflags3=0x04000000", - b"xtalfreq=37400", - b"nocrc=1", - b"ag0=255", - b"aa2g=1", - b"ccode=ALL", - b"pa0itssit=0x20", - b"extpagain2g=0", - b"pa2ga0=-168,6649,-778", - b"AvVmid_c0=0x0,0xc8", - b"cckpwroffset0=5", - b"maxp2ga0=84", - b"txpwrbckof=6", - b"cckbw202gpo=0", - b"legofdmbw202gpo=0x66111111", - b"mcsbw202gpo=0x77711111", - b"propbw202gpo=0xdd", - b"ofdmdigfilttype=18", - b"ofdmdigfilttypebe=18", - b"papdmode=1", - b"papdvalidtest=1", - b"pacalidx2g=45", - b"papdepsoffset=-30", - b"papdendidx=58", - b"ltecxmux=0", - b"ltecxpadnum=0x0102", - b"ltecxfnsel=0x44", - b"ltecxgcigpio=0x01", - b"il0macaddr=00:90:4c:c5:12:38", - b"wl0id=0x431b", - b"deadman_to=0xffffffff", - b"muxenab=0x100", - b"spurconfig=0x3", - b"glitch_based_crsmin=1", - b"btc_mode=1", -); diff --git a/src/runner.rs b/src/runner.rs deleted file mode 100644 index 5706696b4..000000000 --- a/src/runner.rs +++ /dev/null @@ -1,575 +0,0 @@ -use embassy_futures::select::{select3, Either3}; -use embassy_net_driver_channel as ch; -use embassy_sync::pubsub::PubSubBehavior; -use embassy_time::{block_for, Duration, Timer}; -use embedded_hal_1::digital::OutputPin; - -use crate::bus::Bus; -pub use crate::bus::SpiBusCyw43; -use crate::consts::*; -use crate::events::{Event, Events, Status}; -use crate::fmt::Bytes; -use crate::ioctl::{IoctlState, IoctlType, PendingIoctl}; -use crate::nvram::NVRAM; -use crate::structs::*; -use crate::{events, slice8_mut, Core, CHIP, MTU}; - -#[cfg(feature = "firmware-logs")] -struct LogState { - addr: u32, - last_idx: usize, - buf: [u8; 256], - buf_count: usize, -} - -#[cfg(feature = "firmware-logs")] -impl Default for LogState { - fn default() -> Self { - Self { - addr: Default::default(), - last_idx: Default::default(), - buf: [0; 256], - buf_count: Default::default(), - } - } -} - -pub struct Runner<'a, PWR, SPI> { - ch: ch::Runner<'a, MTU>, - bus: Bus, - - ioctl_state: &'a IoctlState, - ioctl_id: u16, - sdpcm_seq: u8, - sdpcm_seq_max: u8, - - events: &'a Events, - - #[cfg(feature = "firmware-logs")] - log: LogState, -} - -impl<'a, PWR, SPI> Runner<'a, PWR, SPI> -where - PWR: OutputPin, - SPI: SpiBusCyw43, -{ - pub(crate) fn new( - ch: ch::Runner<'a, MTU>, - bus: Bus, - ioctl_state: &'a IoctlState, - events: &'a Events, - ) -> Self { - Self { - ch, - bus, - ioctl_state, - ioctl_id: 0, - sdpcm_seq: 0, - sdpcm_seq_max: 1, - events, - #[cfg(feature = "firmware-logs")] - log: LogState::default(), - } - } - - pub(crate) async fn init(&mut self, firmware: &[u8]) { - self.bus.init().await; - - // Init ALP (Active Low Power) clock - self.bus - .write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, BACKPLANE_ALP_AVAIL_REQ) - .await; - debug!("waiting for clock..."); - while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & BACKPLANE_ALP_AVAIL == 0 {} - debug!("clock ok"); - - let chip_id = self.bus.bp_read16(0x1800_0000).await; - debug!("chip ID: {}", chip_id); - - // Upload firmware. - self.core_disable(Core::WLAN).await; - self.core_reset(Core::SOCSRAM).await; - self.bus.bp_write32(CHIP.socsram_base_address + 0x10, 3).await; - self.bus.bp_write32(CHIP.socsram_base_address + 0x44, 0).await; - - let ram_addr = CHIP.atcm_ram_base_address; - - debug!("loading fw"); - self.bus.bp_write(ram_addr, firmware).await; - - debug!("loading nvram"); - // Round up to 4 bytes. - let nvram_len = (NVRAM.len() + 3) / 4 * 4; - self.bus - .bp_write(ram_addr + CHIP.chip_ram_size - 4 - nvram_len as u32, NVRAM) - .await; - - let nvram_len_words = nvram_len as u32 / 4; - let nvram_len_magic = (!nvram_len_words << 16) | nvram_len_words; - self.bus - .bp_write32(ram_addr + CHIP.chip_ram_size - 4, nvram_len_magic) - .await; - - // Start core! - debug!("starting up core..."); - self.core_reset(Core::WLAN).await; - assert!(self.core_is_up(Core::WLAN).await); - - while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {} - - // "Set up the interrupt mask and enable interrupts" - // self.bus.bp_write32(CHIP.sdiod_core_base_address + 0x24, 0xF0).await; - - self.bus - .write16(FUNC_BUS, REG_BUS_INTERRUPT_ENABLE, IRQ_F2_PACKET_AVAILABLE) - .await; - - // "Lower F2 Watermark to avoid DMA Hang in F2 when SD Clock is stopped." - // Sounds scary... - self.bus - .write8(FUNC_BACKPLANE, REG_BACKPLANE_FUNCTION2_WATERMARK, 32) - .await; - - // wait for wifi startup - debug!("waiting for wifi init..."); - while self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await & STATUS_F2_RX_READY == 0 {} - - // Some random configs related to sleep. - // These aren't needed if we don't want to sleep the bus. - // TODO do we need to sleep the bus to read the irq line, due to - // being on the same pin as MOSI/MISO? - - /* - let mut val = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_WAKEUP_CTRL).await; - val |= 0x02; // WAKE_TILL_HT_AVAIL - self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_WAKEUP_CTRL, val).await; - self.bus.write8(FUNC_BUS, 0xF0, 0x08).await; // SDIOD_CCCR_BRCM_CARDCAP.CMD_NODEC = 1 - self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x02).await; // SBSDIO_FORCE_HT - - let mut val = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_SLEEP_CSR).await; - val |= 0x01; // SBSDIO_SLPCSR_KEEP_SDIO_ON - self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_SLEEP_CSR, val).await; - */ - - // clear pulls - self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP, 0).await; - let _ = self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_PULL_UP).await; - - // start HT clock - //self.bus.write8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR, 0x10).await; - //debug!("waiting for HT clock..."); - //while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {} - //debug!("clock ok"); - - #[cfg(feature = "firmware-logs")] - self.log_init().await; - - debug!("wifi init done"); - } - - #[cfg(feature = "firmware-logs")] - async fn log_init(&mut self) { - // Initialize shared memory for logging. - - let addr = CHIP.atcm_ram_base_address + CHIP.chip_ram_size - 4 - CHIP.socram_srmem_size; - let shared_addr = self.bus.bp_read32(addr).await; - debug!("shared_addr {:08x}", shared_addr); - - let mut shared = [0; SharedMemData::SIZE]; - self.bus.bp_read(shared_addr, &mut shared).await; - let shared = SharedMemData::from_bytes(&shared); - - self.log.addr = shared.console_addr + 8; - } - - #[cfg(feature = "firmware-logs")] - async fn log_read(&mut self) { - // Read log struct - let mut log = [0; SharedMemLog::SIZE]; - self.bus.bp_read(self.log.addr, &mut log).await; - let log = SharedMemLog::from_bytes(&log); - - let idx = log.idx as usize; - - // If pointer hasn't moved, no need to do anything. - if idx == self.log.last_idx { - return; - } - - // Read entire buf for now. We could read only what we need, but then we - // run into annoying alignment issues in `bp_read`. - let mut buf = [0; 0x400]; - self.bus.bp_read(log.buf, &mut buf).await; - - while self.log.last_idx != idx as usize { - let b = buf[self.log.last_idx]; - if b == b'\r' || b == b'\n' { - if self.log.buf_count != 0 { - let s = unsafe { core::str::from_utf8_unchecked(&self.log.buf[..self.log.buf_count]) }; - debug!("LOGS: {}", s); - self.log.buf_count = 0; - } - } else if self.log.buf_count < self.log.buf.len() { - self.log.buf[self.log.buf_count] = b; - self.log.buf_count += 1; - } - - self.log.last_idx += 1; - if self.log.last_idx == 0x400 { - self.log.last_idx = 0; - } - } - } - - pub async fn run(mut self) -> ! { - let mut buf = [0; 512]; - loop { - #[cfg(feature = "firmware-logs")] - self.log_read().await; - - if self.has_credit() { - let ioctl = self.ioctl_state.wait_pending(); - let tx = self.ch.tx_buf(); - let ev = self.bus.wait_for_event(); - - match select3(ioctl, tx, ev).await { - Either3::First(PendingIoctl { - buf: iobuf, - kind, - cmd, - iface, - }) => { - self.send_ioctl(kind, cmd, iface, unsafe { &*iobuf }).await; - self.check_status(&mut buf).await; - } - Either3::Second(packet) => { - trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)])); - - let mut buf = [0; 512]; - let buf8 = slice8_mut(&mut buf); - - // There MUST be 2 bytes of padding between the SDPCM and BDC headers. - // And ONLY for data packets! - // No idea why, but the firmware will append two zero bytes to the tx'd packets - // otherwise. If the packet is exactly 1514 bytes (the max MTU), this makes it - // be oversized and get dropped. - // WHD adds it here https://github.com/Infineon/wifi-host-driver/blob/c04fcbb6b0d049304f376cf483fd7b1b570c8cd5/WiFi_Host_Driver/src/include/whd_sdpcm.h#L90 - // and adds it to the header size her https://github.com/Infineon/wifi-host-driver/blob/c04fcbb6b0d049304f376cf483fd7b1b570c8cd5/WiFi_Host_Driver/src/whd_sdpcm.c#L597 - // ¯\_(ツ)_/¯ - const PADDING_SIZE: usize = 2; - let total_len = SdpcmHeader::SIZE + PADDING_SIZE + BdcHeader::SIZE + packet.len(); - - let seq = self.sdpcm_seq; - self.sdpcm_seq = self.sdpcm_seq.wrapping_add(1); - - let sdpcm_header = SdpcmHeader { - len: total_len as u16, // TODO does this len need to be rounded up to u32? - len_inv: !total_len as u16, - sequence: seq, - channel_and_flags: CHANNEL_TYPE_DATA, - next_length: 0, - header_length: (SdpcmHeader::SIZE + PADDING_SIZE) as _, - wireless_flow_control: 0, - bus_data_credit: 0, - reserved: [0, 0], - }; - - let bdc_header = BdcHeader { - flags: BDC_VERSION << BDC_VERSION_SHIFT, - priority: 0, - flags2: 0, - data_offset: 0, - }; - trace!("tx {:?}", sdpcm_header); - trace!(" {:?}", bdc_header); - - buf8[0..SdpcmHeader::SIZE].copy_from_slice(&sdpcm_header.to_bytes()); - buf8[SdpcmHeader::SIZE + PADDING_SIZE..][..BdcHeader::SIZE] - .copy_from_slice(&bdc_header.to_bytes()); - buf8[SdpcmHeader::SIZE + PADDING_SIZE + BdcHeader::SIZE..][..packet.len()] - .copy_from_slice(packet); - - let total_len = (total_len + 3) & !3; // round up to 4byte - - trace!(" {:02x}", Bytes(&buf8[..total_len.min(48)])); - - self.bus.wlan_write(&buf[..(total_len / 4)]).await; - self.ch.tx_done(); - self.check_status(&mut buf).await; - } - Either3::Third(()) => { - self.handle_irq(&mut buf).await; - } - } - } else { - warn!("TX stalled"); - self.bus.wait_for_event().await; - self.handle_irq(&mut buf).await; - } - } - } - - /// Wait for IRQ on F2 packet available - async fn handle_irq(&mut self, buf: &mut [u32; 512]) { - // Receive stuff - let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await; - trace!("irq{}", FormatInterrupt(irq)); - - if irq & IRQ_F2_PACKET_AVAILABLE != 0 { - self.check_status(buf).await; - } - - if irq & IRQ_DATA_UNAVAILABLE != 0 { - // TODO what should we do here? - warn!("IRQ DATA_UNAVAILABLE, clearing..."); - self.bus.write16(FUNC_BUS, REG_BUS_INTERRUPT, 1).await; - } - } - - /// Handle F2 events while status register is set - async fn check_status(&mut self, buf: &mut [u32; 512]) { - loop { - let status = self.bus.status(); - trace!("check status{}", FormatStatus(status)); - - if status & STATUS_F2_PKT_AVAILABLE != 0 { - let len = (status & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT; - self.bus.wlan_read(buf, len).await; - trace!("rx {:02x}", Bytes(&slice8_mut(buf)[..(len as usize).min(48)])); - self.rx(&mut slice8_mut(buf)[..len as usize]); - } else { - break; - } - } - } - - fn rx(&mut self, packet: &mut [u8]) { - let Some((sdpcm_header, payload)) = SdpcmHeader::parse(packet) else { return }; - - self.update_credit(&sdpcm_header); - - let channel = sdpcm_header.channel_and_flags & 0x0f; - - match channel { - CHANNEL_TYPE_CONTROL => { - let Some((cdc_header, response)) = CdcHeader::parse(payload) else { return; }; - trace!(" {:?}", cdc_header); - - if cdc_header.id == self.ioctl_id { - if cdc_header.status != 0 { - // TODO: propagate error instead - panic!("IOCTL error {}", cdc_header.status as i32); - } - - self.ioctl_state.ioctl_done(response); - } - } - CHANNEL_TYPE_EVENT => { - let Some((_, bdc_packet)) = BdcHeader::parse(payload) else { - warn!("BDC event, incomplete header"); - return; - }; - - let Some((event_packet, evt_data)) = EventPacket::parse(bdc_packet) else { - warn!("BDC event, incomplete data"); - return; - }; - - const ETH_P_LINK_CTL: u16 = 0x886c; // HPNA, wlan link local tunnel, according to linux if_ether.h - if event_packet.eth.ether_type != ETH_P_LINK_CTL { - warn!( - "unexpected ethernet type 0x{:04x}, expected Broadcom ether type 0x{:04x}", - event_packet.eth.ether_type, ETH_P_LINK_CTL - ); - return; - } - const BROADCOM_OUI: &[u8] = &[0x00, 0x10, 0x18]; - if event_packet.hdr.oui != BROADCOM_OUI { - warn!( - "unexpected ethernet OUI {:02x}, expected Broadcom OUI {:02x}", - Bytes(&event_packet.hdr.oui), - Bytes(BROADCOM_OUI) - ); - return; - } - const BCMILCP_SUBTYPE_VENDOR_LONG: u16 = 32769; - if event_packet.hdr.subtype != BCMILCP_SUBTYPE_VENDOR_LONG { - warn!("unexpected subtype {}", event_packet.hdr.subtype); - return; - } - - const BCMILCP_BCM_SUBTYPE_EVENT: u16 = 1; - if event_packet.hdr.user_subtype != BCMILCP_BCM_SUBTYPE_EVENT { - warn!("unexpected user_subtype {}", event_packet.hdr.subtype); - return; - } - - let evt_type = events::Event::from(event_packet.msg.event_type as u8); - debug!( - "=== EVENT {:?}: {:?} {:02x}", - evt_type, - event_packet.msg, - Bytes(evt_data) - ); - - if self.events.mask.is_enabled(evt_type) { - let status = event_packet.msg.status; - let event_payload = match evt_type { - Event::ESCAN_RESULT if status == EStatus::PARTIAL => { - let Some((_, bss_info)) = ScanResults::parse(evt_data) else { return }; - let Some(bss_info) = BssInfo::parse(bss_info) else { return }; - events::Payload::BssInfo(*bss_info) - } - Event::ESCAN_RESULT => events::Payload::None, - _ => events::Payload::None, - }; - - // this intentionally uses the non-blocking publish immediate - // publish() is a deadlock risk in the current design as awaiting here prevents ioctls - // The `Runner` always yields when accessing the device, so consumers always have a chance to receive the event - // (if they are actively awaiting the queue) - self.events.queue.publish_immediate(events::Message::new( - Status { - event_type: evt_type, - status, - }, - event_payload, - )); - } - } - CHANNEL_TYPE_DATA => { - let Some((_, packet)) = BdcHeader::parse(payload) else { return }; - trace!("rx pkt {:02x}", Bytes(&packet[..packet.len().min(48)])); - - match self.ch.try_rx_buf() { - Some(buf) => { - buf[..packet.len()].copy_from_slice(packet); - self.ch.rx_done(packet.len()) - } - None => warn!("failed to push rxd packet to the channel."), - } - } - _ => {} - } - } - - fn update_credit(&mut self, sdpcm_header: &SdpcmHeader) { - if sdpcm_header.channel_and_flags & 0xf < 3 { - let mut sdpcm_seq_max = sdpcm_header.bus_data_credit; - if sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) > 0x40 { - sdpcm_seq_max = self.sdpcm_seq + 2; - } - self.sdpcm_seq_max = sdpcm_seq_max; - } - } - - fn has_credit(&self) -> bool { - self.sdpcm_seq != self.sdpcm_seq_max && self.sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) & 0x80 == 0 - } - - async fn send_ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, data: &[u8]) { - let mut buf = [0; 512]; - let buf8 = slice8_mut(&mut buf); - - let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len(); - - let sdpcm_seq = self.sdpcm_seq; - self.sdpcm_seq = self.sdpcm_seq.wrapping_add(1); - self.ioctl_id = self.ioctl_id.wrapping_add(1); - - let sdpcm_header = SdpcmHeader { - len: total_len as u16, // TODO does this len need to be rounded up to u32? - len_inv: !total_len as u16, - sequence: sdpcm_seq, - channel_and_flags: CHANNEL_TYPE_CONTROL, - next_length: 0, - header_length: SdpcmHeader::SIZE as _, - wireless_flow_control: 0, - bus_data_credit: 0, - reserved: [0, 0], - }; - - let cdc_header = CdcHeader { - cmd: cmd, - len: data.len() as _, - flags: kind as u16 | (iface as u16) << 12, - id: self.ioctl_id, - status: 0, - }; - trace!("tx {:?}", sdpcm_header); - trace!(" {:?}", cdc_header); - - buf8[0..SdpcmHeader::SIZE].copy_from_slice(&sdpcm_header.to_bytes()); - buf8[SdpcmHeader::SIZE..][..CdcHeader::SIZE].copy_from_slice(&cdc_header.to_bytes()); - buf8[SdpcmHeader::SIZE + CdcHeader::SIZE..][..data.len()].copy_from_slice(data); - - let total_len = (total_len + 3) & !3; // round up to 4byte - - trace!(" {:02x}", Bytes(&buf8[..total_len.min(48)])); - - self.bus.wlan_write(&buf[..total_len / 4]).await; - } - - async fn core_disable(&mut self, core: Core) { - let base = core.base_addr(); - - // Dummy read? - let _ = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await; - - // Check it isn't already reset - let r = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await; - if r & AI_RESETCTRL_BIT_RESET != 0 { - return; - } - - self.bus.bp_write8(base + AI_IOCTRL_OFFSET, 0).await; - let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await; - - block_for(Duration::from_millis(1)); - - self.bus - .bp_write8(base + AI_RESETCTRL_OFFSET, AI_RESETCTRL_BIT_RESET) - .await; - let _ = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await; - } - - async fn core_reset(&mut self, core: Core) { - self.core_disable(core).await; - - let base = core.base_addr(); - self.bus - .bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_FGC | AI_IOCTRL_BIT_CLOCK_EN) - .await; - let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await; - - self.bus.bp_write8(base + AI_RESETCTRL_OFFSET, 0).await; - - Timer::after(Duration::from_millis(1)).await; - - self.bus - .bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_CLOCK_EN) - .await; - let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await; - - Timer::after(Duration::from_millis(1)).await; - } - - async fn core_is_up(&mut self, core: Core) -> bool { - let base = core.base_addr(); - - let io = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await; - if io & (AI_IOCTRL_BIT_FGC | AI_IOCTRL_BIT_CLOCK_EN) != AI_IOCTRL_BIT_CLOCK_EN { - debug!("core_is_up: returning false due to bad ioctrl {:02x}", io); - return false; - } - - let r = self.bus.bp_read8(base + AI_RESETCTRL_OFFSET).await; - if r & (AI_RESETCTRL_BIT_RESET) != 0 { - debug!("core_is_up: returning false due to bad resetctrl {:02x}", r); - return false; - } - - true - } -} diff --git a/src/structs.rs b/src/structs.rs deleted file mode 100644 index 5ba633c74..000000000 --- a/src/structs.rs +++ /dev/null @@ -1,496 +0,0 @@ -use crate::events::Event; -use crate::fmt::Bytes; - -macro_rules! impl_bytes { - ($t:ident) => { - impl $t { - pub const SIZE: usize = core::mem::size_of::(); - - #[allow(unused)] - pub fn to_bytes(&self) -> [u8; Self::SIZE] { - unsafe { core::mem::transmute(*self) } - } - - #[allow(unused)] - pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> &Self { - let alignment = core::mem::align_of::(); - assert_eq!( - bytes.as_ptr().align_offset(alignment), - 0, - "{} is not aligned", - core::any::type_name::() - ); - unsafe { core::mem::transmute(bytes) } - } - - #[allow(unused)] - pub fn from_bytes_mut(bytes: &mut [u8; Self::SIZE]) -> &mut Self { - let alignment = core::mem::align_of::(); - assert_eq!( - bytes.as_ptr().align_offset(alignment), - 0, - "{} is not aligned", - core::any::type_name::() - ); - - unsafe { core::mem::transmute(bytes) } - } - } - }; -} - -#[derive(Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(C)] -pub struct SharedMemData { - pub flags: u32, - pub trap_addr: u32, - pub assert_exp_addr: u32, - pub assert_file_addr: u32, - pub assert_line: u32, - pub console_addr: u32, - pub msgtrace_addr: u32, - pub fwid: u32, -} -impl_bytes!(SharedMemData); - -#[derive(Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(C)] -pub struct SharedMemLog { - pub buf: u32, - pub buf_size: u32, - pub idx: u32, - pub out_idx: u32, -} -impl_bytes!(SharedMemLog); - -#[derive(Debug, Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(C)] -pub struct SdpcmHeader { - pub len: u16, - pub len_inv: u16, - /// Rx/Tx sequence number - pub sequence: u8, - /// 4 MSB Channel number, 4 LSB arbitrary flag - pub channel_and_flags: u8, - /// Length of next data frame, reserved for Tx - pub next_length: u8, - /// Data offset - pub header_length: u8, - /// Flow control bits, reserved for Tx - pub wireless_flow_control: u8, - /// Maximum Sequence number allowed by firmware for Tx - pub bus_data_credit: u8, - /// Reserved - pub reserved: [u8; 2], -} -impl_bytes!(SdpcmHeader); - -impl SdpcmHeader { - pub fn parse(packet: &mut [u8]) -> Option<(&mut Self, &mut [u8])> { - let packet_len = packet.len(); - if packet_len < Self::SIZE { - warn!("packet too short, len={}", packet.len()); - return None; - } - let (sdpcm_header, sdpcm_packet) = packet.split_at_mut(Self::SIZE); - let sdpcm_header = Self::from_bytes_mut(sdpcm_header.try_into().unwrap()); - trace!("rx {:?}", sdpcm_header); - - if sdpcm_header.len != !sdpcm_header.len_inv { - warn!("len inv mismatch"); - return None; - } - - if sdpcm_header.len as usize != packet_len { - warn!("len from header doesn't match len from spi"); - return None; - } - - let sdpcm_packet = &mut sdpcm_packet[(sdpcm_header.header_length as usize - Self::SIZE)..]; - Some((sdpcm_header, sdpcm_packet)) - } -} - -#[derive(Debug, Clone, Copy)] -#[repr(C, packed(2))] -pub struct CdcHeader { - pub cmd: u32, - pub len: u32, - pub flags: u16, - pub id: u16, - pub status: u32, -} -impl_bytes!(CdcHeader); - -#[cfg(feature = "defmt")] -impl defmt::Format for CdcHeader { - fn format(&self, fmt: defmt::Formatter) { - fn copy(t: T) -> T { - t - } - - defmt::write!( - fmt, - "CdcHeader{{cmd: {=u32:08x}, len: {=u32:08x}, flags: {=u16:04x}, id: {=u16:04x}, status: {=u32:08x}}}", - copy(self.cmd), - copy(self.len), - copy(self.flags), - copy(self.id), - copy(self.status), - ) - } -} - -impl CdcHeader { - pub fn parse(packet: &mut [u8]) -> Option<(&mut Self, &mut [u8])> { - if packet.len() < Self::SIZE { - warn!("payload too short, len={}", packet.len()); - return None; - } - - let (cdc_header, payload) = packet.split_at_mut(Self::SIZE); - let cdc_header = Self::from_bytes_mut(cdc_header.try_into().unwrap()); - - let payload = &mut payload[..cdc_header.len as usize]; - Some((cdc_header, payload)) - } -} - -pub const BDC_VERSION: u8 = 2; -pub const BDC_VERSION_SHIFT: u8 = 4; - -#[derive(Debug, Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(C)] -pub struct BdcHeader { - pub flags: u8, - /// 802.1d Priority (low 3 bits) - pub priority: u8, - pub flags2: u8, - /// Offset from end of BDC header to packet data, in 4-uint8_t words. Leaves room for optional headers. - pub data_offset: u8, -} -impl_bytes!(BdcHeader); - -impl BdcHeader { - pub fn parse(packet: &mut [u8]) -> Option<(&mut Self, &mut [u8])> { - if packet.len() < Self::SIZE { - return None; - } - - let (bdc_header, bdc_packet) = packet.split_at_mut(Self::SIZE); - let bdc_header = Self::from_bytes_mut(bdc_header.try_into().unwrap()); - trace!(" {:?}", bdc_header); - - let packet_start = 4 * bdc_header.data_offset as usize; - - let bdc_packet = bdc_packet.get_mut(packet_start..)?; - trace!(" {:02x}", Bytes(&bdc_packet[..bdc_packet.len().min(36)])); - - Some((bdc_header, bdc_packet)) - } -} - -#[derive(Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(C)] -pub struct EthernetHeader { - pub destination_mac: [u8; 6], - pub source_mac: [u8; 6], - pub ether_type: u16, -} - -impl EthernetHeader { - pub fn byteswap(&mut self) { - self.ether_type = self.ether_type.to_be(); - } -} - -#[derive(Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(C)] -pub struct EventHeader { - pub subtype: u16, - pub length: u16, - pub version: u8, - pub oui: [u8; 3], - pub user_subtype: u16, -} - -impl EventHeader { - pub fn byteswap(&mut self) { - self.subtype = self.subtype.to_be(); - self.length = self.length.to_be(); - self.user_subtype = self.user_subtype.to_be(); - } -} - -#[derive(Debug, Clone, Copy)] -// #[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(C, packed(2))] -pub struct EventMessage { - /// version - pub version: u16, - /// see flags below - pub flags: u16, - /// Message (see below) - pub event_type: u32, - /// Status code (see below) - pub status: u32, - /// Reason code (if applicable) - pub reason: u32, - /// WLC_E_AUTH - pub auth_type: u32, - /// data buf - pub datalen: u32, - /// Station address (if applicable) - pub addr: [u8; 6], - /// name of the incoming packet interface - pub ifname: [u8; 16], - /// destination OS i/f index - pub ifidx: u8, - /// source bsscfg index - pub bsscfgidx: u8, -} -impl_bytes!(EventMessage); - -#[cfg(feature = "defmt")] -impl defmt::Format for EventMessage { - fn format(&self, fmt: defmt::Formatter) { - let event_type = self.event_type; - let status = self.status; - let reason = self.reason; - let auth_type = self.auth_type; - let datalen = self.datalen; - - defmt::write!( - fmt, - "EventMessage {{ \ - version: {=u16}, \ - flags: {=u16}, \ - event_type: {=u32}, \ - status: {=u32}, \ - reason: {=u32}, \ - auth_type: {=u32}, \ - datalen: {=u32}, \ - addr: {=[u8; 6]:x}, \ - ifname: {=[u8; 16]:x}, \ - ifidx: {=u8}, \ - bsscfgidx: {=u8}, \ - }} ", - self.version, - self.flags, - event_type, - status, - reason, - auth_type, - datalen, - self.addr, - self.ifname, - self.ifidx, - self.bsscfgidx - ); - } -} - -impl EventMessage { - pub fn byteswap(&mut self) { - self.version = self.version.to_be(); - self.flags = self.flags.to_be(); - self.event_type = self.event_type.to_be(); - self.status = self.status.to_be(); - self.reason = self.reason.to_be(); - self.auth_type = self.auth_type.to_be(); - self.datalen = self.datalen.to_be(); - } -} - -#[derive(Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(C, packed(2))] -pub struct EventPacket { - pub eth: EthernetHeader, - pub hdr: EventHeader, - pub msg: EventMessage, -} -impl_bytes!(EventPacket); - -impl EventPacket { - pub fn parse(packet: &mut [u8]) -> Option<(&mut Self, &mut [u8])> { - if packet.len() < Self::SIZE { - return None; - } - - let (event_header, event_packet) = packet.split_at_mut(Self::SIZE); - let event_header = Self::from_bytes_mut(event_header.try_into().unwrap()); - // warn!("event_header {:x}", event_header as *const _); - event_header.byteswap(); - - let event_packet = event_packet.get_mut(..event_header.msg.datalen as usize)?; - - Some((event_header, event_packet)) - } - - pub fn byteswap(&mut self) { - self.eth.byteswap(); - self.hdr.byteswap(); - self.msg.byteswap(); - } -} - -#[derive(Clone, Copy)] -#[repr(C)] -pub struct DownloadHeader { - pub flag: u16, // - pub dload_type: u16, - pub len: u32, - pub crc: u32, -} -impl_bytes!(DownloadHeader); - -#[allow(unused)] -pub const DOWNLOAD_FLAG_NO_CRC: u16 = 0x0001; -pub const DOWNLOAD_FLAG_BEGIN: u16 = 0x0002; -pub const DOWNLOAD_FLAG_END: u16 = 0x0004; -pub const DOWNLOAD_FLAG_HANDLER_VER: u16 = 0x1000; - -// Country Locale Matrix (CLM) -pub const DOWNLOAD_TYPE_CLM: u16 = 2; - -#[derive(Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(C)] -pub struct CountryInfo { - pub country_abbrev: [u8; 4], - pub rev: i32, - pub country_code: [u8; 4], -} -impl_bytes!(CountryInfo); - -#[derive(Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(C)] -pub struct SsidInfo { - pub len: u32, - pub ssid: [u8; 32], -} -impl_bytes!(SsidInfo); - -#[derive(Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(C)] -pub struct PassphraseInfo { - pub len: u16, - pub flags: u16, - pub passphrase: [u8; 64], -} -impl_bytes!(PassphraseInfo); - -#[derive(Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(C)] -pub struct SsidInfoWithIndex { - pub index: u32, - pub ssid_info: SsidInfo, -} -impl_bytes!(SsidInfoWithIndex); - -#[derive(Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(C)] -pub struct EventMask { - pub iface: u32, - pub events: [u8; 24], -} -impl_bytes!(EventMask); - -impl EventMask { - pub fn unset(&mut self, evt: Event) { - let evt = evt as u8 as usize; - self.events[evt / 8] &= !(1 << (evt % 8)); - } -} - -/// Parameters for a wifi scan -#[derive(Clone, Copy)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(C)] -pub struct ScanParams { - pub version: u32, - pub action: u16, - pub sync_id: u16, - pub ssid_len: u32, - pub ssid: [u8; 32], - pub bssid: [u8; 6], - pub bss_type: u8, - pub scan_type: u8, - pub nprobes: u32, - pub active_time: u32, - pub passive_time: u32, - pub home_time: u32, - pub channel_num: u32, - pub channel_list: [u16; 1], -} -impl_bytes!(ScanParams); - -/// Wifi Scan Results Header, followed by `bss_count` `BssInfo` -#[derive(Clone, Copy)] -// #[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(C, packed(2))] -pub struct ScanResults { - pub buflen: u32, - pub version: u32, - pub sync_id: u16, - pub bss_count: u16, -} -impl_bytes!(ScanResults); - -impl ScanResults { - pub fn parse(packet: &mut [u8]) -> Option<(&mut ScanResults, &mut [u8])> { - if packet.len() < ScanResults::SIZE { - return None; - } - - let (scan_results, bssinfo) = packet.split_at_mut(ScanResults::SIZE); - let scan_results = ScanResults::from_bytes_mut(scan_results.try_into().unwrap()); - - if scan_results.bss_count > 0 && bssinfo.len() < BssInfo::SIZE { - warn!("Scan result, incomplete BssInfo"); - return None; - } - - Some((scan_results, bssinfo)) - } -} - -/// Wifi Scan Result -#[derive(Clone, Copy)] -// #[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(C, packed(2))] -#[non_exhaustive] -pub struct BssInfo { - pub version: u32, - pub length: u32, - pub bssid: [u8; 6], - pub beacon_period: u16, - pub capability: u16, - pub ssid_len: u8, - pub ssid: [u8; 32], - // there will be more stuff here -} -impl_bytes!(BssInfo); - -impl BssInfo { - pub fn parse(packet: &mut [u8]) -> Option<&mut Self> { - if packet.len() < BssInfo::SIZE { - return None; - } - - Some(BssInfo::from_bytes_mut( - packet[..BssInfo::SIZE].as_mut().try_into().unwrap(), - )) - } -} -- cgit