N! T! P!
This commit is contained in:
parent
97238b56f7
commit
4d087a56d0
7 changed files with 382 additions and 169 deletions
52
Cargo.lock
generated
52
Cargo.lock
generated
|
|
@ -125,6 +125,15 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.38"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codespan-reporting"
|
name = "codespan-reporting"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
|
|
@ -191,7 +200,7 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cyw43"
|
name = "cyw43"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy.git#c84495ef2eb99580fea5392b2b3aff5ad66043a0"
|
source = "git+https://github.com/embassy-rs/embassy.git#4f08d5bc5ff0f765198665b1f37b6372f43b8567"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cortex-m",
|
"cortex-m",
|
||||||
"cortex-m-rt",
|
"cortex-m-rt",
|
||||||
|
|
@ -208,7 +217,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cyw43-pio"
|
name = "cyw43-pio"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy.git#c84495ef2eb99580fea5392b2b3aff5ad66043a0"
|
source = "git+https://github.com/embassy-rs/embassy.git#4f08d5bc5ff0f765198665b1f37b6372f43b8567"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cyw43",
|
"cyw43",
|
||||||
"embassy-rp",
|
"embassy-rp",
|
||||||
|
|
@ -303,7 +312,7 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-embedded-hal"
|
name = "embassy-embedded-hal"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy.git#c84495ef2eb99580fea5392b2b3aff5ad66043a0"
|
source = "git+https://github.com/embassy-rs/embassy.git#4f08d5bc5ff0f765198665b1f37b6372f43b8567"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"embassy-futures",
|
"embassy-futures",
|
||||||
"embassy-sync",
|
"embassy-sync",
|
||||||
|
|
@ -319,7 +328,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-executor"
|
name = "embassy-executor"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy.git#c84495ef2eb99580fea5392b2b3aff5ad66043a0"
|
source = "git+https://github.com/embassy-rs/embassy.git#4f08d5bc5ff0f765198665b1f37b6372f43b8567"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cortex-m",
|
"cortex-m",
|
||||||
"critical-section",
|
"critical-section",
|
||||||
|
|
@ -332,7 +341,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-executor-macros"
|
name = "embassy-executor-macros"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy.git#c84495ef2eb99580fea5392b2b3aff5ad66043a0"
|
source = "git+https://github.com/embassy-rs/embassy.git#4f08d5bc5ff0f765198665b1f37b6372f43b8567"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling",
|
"darling",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
|
@ -343,12 +352,12 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-futures"
|
name = "embassy-futures"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "git+https://github.com/embassy-rs/embassy.git#c84495ef2eb99580fea5392b2b3aff5ad66043a0"
|
source = "git+https://github.com/embassy-rs/embassy.git#4f08d5bc5ff0f765198665b1f37b6372f43b8567"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-hal-internal"
|
name = "embassy-hal-internal"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy.git#c84495ef2eb99580fea5392b2b3aff5ad66043a0"
|
source = "git+https://github.com/embassy-rs/embassy.git#4f08d5bc5ff0f765198665b1f37b6372f43b8567"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cortex-m",
|
"cortex-m",
|
||||||
"critical-section",
|
"critical-section",
|
||||||
|
|
@ -358,7 +367,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-net"
|
name = "embassy-net"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy.git#c84495ef2eb99580fea5392b2b3aff5ad66043a0"
|
source = "git+https://github.com/embassy-rs/embassy.git#4f08d5bc5ff0f765198665b1f37b6372f43b8567"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"document-features",
|
"document-features",
|
||||||
"embassy-net-driver",
|
"embassy-net-driver",
|
||||||
|
|
@ -374,12 +383,12 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-net-driver"
|
name = "embassy-net-driver"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy.git#c84495ef2eb99580fea5392b2b3aff5ad66043a0"
|
source = "git+https://github.com/embassy-rs/embassy.git#4f08d5bc5ff0f765198665b1f37b6372f43b8567"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-net-driver-channel"
|
name = "embassy-net-driver-channel"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy.git#c84495ef2eb99580fea5392b2b3aff5ad66043a0"
|
source = "git+https://github.com/embassy-rs/embassy.git#4f08d5bc5ff0f765198665b1f37b6372f43b8567"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"embassy-futures",
|
"embassy-futures",
|
||||||
"embassy-net-driver",
|
"embassy-net-driver",
|
||||||
|
|
@ -389,7 +398,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-rp"
|
name = "embassy-rp"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy.git#c84495ef2eb99580fea5392b2b3aff5ad66043a0"
|
source = "git+https://github.com/embassy-rs/embassy.git#4f08d5bc5ff0f765198665b1f37b6372f43b8567"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atomic-polyfill",
|
"atomic-polyfill",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
|
@ -426,7 +435,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-sync"
|
name = "embassy-sync"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy.git#c84495ef2eb99580fea5392b2b3aff5ad66043a0"
|
source = "git+https://github.com/embassy-rs/embassy.git#4f08d5bc5ff0f765198665b1f37b6372f43b8567"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"critical-section",
|
"critical-section",
|
||||||
|
|
@ -438,7 +447,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-time"
|
name = "embassy-time"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
source = "git+https://github.com/embassy-rs/embassy.git#c84495ef2eb99580fea5392b2b3aff5ad66043a0"
|
source = "git+https://github.com/embassy-rs/embassy.git#4f08d5bc5ff0f765198665b1f37b6372f43b8567"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"critical-section",
|
"critical-section",
|
||||||
|
|
@ -455,7 +464,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-time-driver"
|
name = "embassy-time-driver"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy.git#c84495ef2eb99580fea5392b2b3aff5ad66043a0"
|
source = "git+https://github.com/embassy-rs/embassy.git#4f08d5bc5ff0f765198665b1f37b6372f43b8567"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"document-features",
|
"document-features",
|
||||||
]
|
]
|
||||||
|
|
@ -463,12 +472,12 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-time-queue-driver"
|
name = "embassy-time-queue-driver"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy.git#c84495ef2eb99580fea5392b2b3aff5ad66043a0"
|
source = "git+https://github.com/embassy-rs/embassy.git#4f08d5bc5ff0f765198665b1f37b6372f43b8567"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-usb"
|
name = "embassy-usb"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy.git#c84495ef2eb99580fea5392b2b3aff5ad66043a0"
|
source = "git+https://github.com/embassy-rs/embassy.git#4f08d5bc5ff0f765198665b1f37b6372f43b8567"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"embassy-futures",
|
"embassy-futures",
|
||||||
"embassy-net-driver-channel",
|
"embassy-net-driver-channel",
|
||||||
|
|
@ -482,12 +491,12 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-usb-driver"
|
name = "embassy-usb-driver"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy.git#c84495ef2eb99580fea5392b2b3aff5ad66043a0"
|
source = "git+https://github.com/embassy-rs/embassy.git#4f08d5bc5ff0f765198665b1f37b6372f43b8567"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embassy-usb-logger"
|
name = "embassy-usb-logger"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/embassy-rs/embassy.git#c84495ef2eb99580fea5392b2b3aff5ad66043a0"
|
source = "git+https://github.com/embassy-rs/embassy.git#4f08d5bc5ff0f765198665b1f37b6372f43b8567"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"embassy-futures",
|
"embassy-futures",
|
||||||
"embassy-sync",
|
"embassy-sync",
|
||||||
|
|
@ -1001,15 +1010,18 @@ dependencies = [
|
||||||
name = "picow"
|
name = "picow"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
"cortex-m-rt",
|
"cortex-m-rt",
|
||||||
"cyw43",
|
"cyw43",
|
||||||
"cyw43-pio",
|
"cyw43-pio",
|
||||||
"embassy-executor",
|
"embassy-executor",
|
||||||
"embassy-net",
|
"embassy-net",
|
||||||
"embassy-rp",
|
"embassy-rp",
|
||||||
|
"embassy-sync",
|
||||||
"embassy-time",
|
"embassy-time",
|
||||||
"embassy-usb-logger",
|
"embassy-usb-logger",
|
||||||
"log",
|
"log",
|
||||||
|
"no-std-net",
|
||||||
"panic-halt",
|
"panic-halt",
|
||||||
"portable-atomic",
|
"portable-atomic",
|
||||||
"rand",
|
"rand",
|
||||||
|
|
@ -1236,9 +1248,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.17"
|
version = "1.0.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
|
checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
|
|
|
||||||
|
|
@ -9,19 +9,22 @@ serde = { version = "*", features = ["derive"] }
|
||||||
serde_yaml = "*"
|
serde_yaml = "*"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
chrono = { version = "*", default-features = false}
|
||||||
cortex-m-rt = "*"
|
cortex-m-rt = "*"
|
||||||
cyw43 = { git = "https://github.com/embassy-rs/embassy.git" }
|
cyw43 = { git = "https://github.com/embassy-rs/embassy.git" }
|
||||||
cyw43-pio = { git = "https://github.com/embassy-rs/embassy.git" }
|
cyw43-pio = { git = "https://github.com/embassy-rs/embassy.git" }
|
||||||
embassy-executor = { git = "https://github.com/embassy-rs/embassy.git", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "integrated-timers", "nightly"] }
|
embassy-executor = { git = "https://github.com/embassy-rs/embassy.git", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "integrated-timers", "nightly"] }
|
||||||
embassy-net = { git = "https://github.com/embassy-rs/embassy.git", features = ["tcp", "udp", "raw", "dhcpv4", "dhcpv4-hostname", "dns", "proto-ipv4", "multicast"] }
|
embassy-net = { git = "https://github.com/embassy-rs/embassy.git", features = ["raw", "dhcpv4", "dhcpv4-hostname", "dns", "multicast", "proto-ipv4", "proto-ipv6", "tcp", "udp" ] }
|
||||||
embassy-rp = { git = "https://github.com/embassy-rs/embassy.git", features = ["critical-section-impl", "time-driver", "rp2040"] }
|
embassy-rp = { git = "https://github.com/embassy-rs/embassy.git", features = ["critical-section-impl", "rp2040", "time-driver" ] }
|
||||||
|
embassy-sync = { git = "https://github.com/embassy-rs/embassy.git" }
|
||||||
embassy-time = { git = "https://github.com/embassy-rs/embassy.git" }
|
embassy-time = { git = "https://github.com/embassy-rs/embassy.git" }
|
||||||
embassy-usb-logger = { git = "https://github.com/embassy-rs/embassy.git" }
|
embassy-usb-logger = { git = "https://github.com/embassy-rs/embassy.git" }
|
||||||
log = "*"
|
log = "*"
|
||||||
|
no-std-net = "*"
|
||||||
panic-halt = "*"
|
panic-halt = "*"
|
||||||
portable-atomic = { version = "*", features = ["critical-section"] }
|
portable-atomic = { version = "*", features = ["critical-section"] }
|
||||||
rand = { version = "*", default-features = false }
|
rand = { version = "*", default-features = false }
|
||||||
sntpc = { version = "*", default-features = false }
|
sntpc = { version = "*", default-features = false, features = ["async"] }
|
||||||
static_cell = "*"
|
static_cell = "*"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
|
|
||||||
18
flake.lock
generated
18
flake.lock
generated
|
|
@ -2,11 +2,11 @@
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"crane": {
|
"crane": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1728344376,
|
"lastModified": 1728776144,
|
||||||
"narHash": "sha256-lxTce2XE6mfJH8Zk6yBbqsbu9/jpwdymbSH5cCbiVOA=",
|
"narHash": "sha256-fROVjMcKRoGHofDm8dY3uDUtCMwUICh/KjBFQnuBzfg=",
|
||||||
"owner": "ipetkov",
|
"owner": "ipetkov",
|
||||||
"repo": "crane",
|
"repo": "crane",
|
||||||
"rev": "fd86b78f5f35f712c72147427b1eb81a9bd55d0b",
|
"rev": "f876e3d905b922502f031aeec1a84490122254b7",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -21,11 +21,11 @@
|
||||||
"rust-analyzer-src": "rust-analyzer-src"
|
"rust-analyzer-src": "rust-analyzer-src"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1728628307,
|
"lastModified": 1728887700,
|
||||||
"narHash": "sha256-GRMRHZyU+R0RqKPFFgi7BBMDIRFPnHaAhOIxlqyvbZQ=",
|
"narHash": "sha256-i+WCARuldFmXlNW6XlEYiL8UGMzjdg5lMQ9gpACQL/A=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "fenix",
|
"repo": "fenix",
|
||||||
"rev": "b0a014d5b9dba793ebc205bcf12a93b5f6a4c66c",
|
"rev": "bcf74e45d5a818fe3aadf5cb3099189770e18579",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -95,11 +95,11 @@
|
||||||
"rust-analyzer-src": {
|
"rust-analyzer-src": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1728505432,
|
"lastModified": 1728719115,
|
||||||
"narHash": "sha256-QFPMazeiGLo7AGy4RREmTgko0Quch/toMVKhGUjDEeo=",
|
"narHash": "sha256-SLcHmKzkIuahBbSCWr2gzu6bXo6wF12JP4myDzH1CvQ=",
|
||||||
"owner": "rust-lang",
|
"owner": "rust-lang",
|
||||||
"repo": "rust-analyzer",
|
"repo": "rust-analyzer",
|
||||||
"rev": "0fb804acb375b02a3beeaceeb75b71969ef37b15",
|
"rev": "d7628c0a8b95cadefe89d9a45f9be5ee4898c6b1",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
fenixPkgs = fenix.packages.${system};
|
fenixPkgs = fenix.packages.${system};
|
||||||
fenixToolchain = fenixPkgs.fromToolchainFile {
|
fenixToolchain = fenixPkgs.fromToolchainFile {
|
||||||
dir = ./.;
|
dir = ./.;
|
||||||
sha256 = "sha256-HAFn+jo7K/dwbCKRHNXQU+x9b+8LJ8xlQGL/tE0rNlE=";
|
sha256 = "sha256-xN1aESBFCg2dq0LYOHWtU0FtIwkswFbmMoC1GoWCz9c=";
|
||||||
};
|
};
|
||||||
craneLib = (crane.mkLib pkgs).overrideToolchain fenixToolchain;
|
craneLib = (crane.mkLib pkgs).overrideToolchain fenixToolchain;
|
||||||
in {
|
in {
|
||||||
|
|
|
||||||
220
src/main.rs
220
src/main.rs
|
|
@ -2,16 +2,17 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
mod picow_time;
|
mod time;
|
||||||
|
|
||||||
extern crate panic_halt;
|
extern crate panic_halt;
|
||||||
|
|
||||||
|
use chrono::DateTime;
|
||||||
use cyw43::JoinOptions;
|
use cyw43::JoinOptions;
|
||||||
use cyw43_pio::PioSpi;
|
use cyw43_pio::PioSpi;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_net::{
|
use embassy_net::{
|
||||||
dns::{DnsQueryType, DnsSocket},
|
dns::{DnsQueryType, DnsSocket},
|
||||||
Config, DhcpConfig, IpAddress, StackResources,
|
Config, DhcpConfig, IpAddress, Stack, StackResources,
|
||||||
};
|
};
|
||||||
use embassy_rp::{
|
use embassy_rp::{
|
||||||
bind_interrupts,
|
bind_interrupts,
|
||||||
|
|
@ -21,17 +22,24 @@ use embassy_rp::{
|
||||||
pio::{self, Pio},
|
pio::{self, Pio},
|
||||||
usb::{self, Driver},
|
usb::{self, Driver},
|
||||||
};
|
};
|
||||||
|
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal};
|
||||||
use embassy_time::Timer;
|
use embassy_time::Timer;
|
||||||
use log::info;
|
use log::info;
|
||||||
use picow_time::PicowUDPBuffer;
|
use no_std_net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
|
use sntpc::{async_impl::get_time, NtpContext};
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
|
use time::{PicowClock, PicowTimestampGenerator, PicowUDPBuffer};
|
||||||
|
|
||||||
|
const DNS_WAIT_SECOND: u64 = 1 << 3;
|
||||||
const HOSTNAME: &str = "picow";
|
const HOSTNAME: &str = "picow";
|
||||||
const NTP_ENDPOINT: &str = "time.google.com";
|
const NTP_ENDPOINT: &str = "time.google.com";
|
||||||
const WAIT_SECOND: u64 = 7;
|
const NTP_PORT: u16 = 123;
|
||||||
|
const NTP_WAIT_SECOND: u64 = 1 << 6;
|
||||||
|
const TIMER_WAIT_SECOND: u64 = 1 << 1;
|
||||||
const WIRELESS_CREDENTIALS: &[(&str, &str)] =
|
const WIRELESS_CREDENTIALS: &[(&str, &str)] =
|
||||||
&include!(concat!(env!("OUT_DIR"), "/wireless-credentials.rs"));
|
&include!(concat!(env!("OUT_DIR"), "/wireless-credentials.rs"));
|
||||||
|
const WIRELESS_SCAN_WAIT_SECOND: u64 = 1 << 3;
|
||||||
|
|
||||||
bind_interrupts!(struct Irqs {
|
bind_interrupts!(struct Irqs {
|
||||||
PIO0_IRQ_0 => pio::InterruptHandler<PIO0>;
|
PIO0_IRQ_0 => pio::InterruptHandler<PIO0>;
|
||||||
|
|
@ -50,6 +58,124 @@ async fn network_task(
|
||||||
network_runner.run().await;
|
network_runner.run().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn ntp_task(
|
||||||
|
clock: &'static PicowClock,
|
||||||
|
network_stack: Stack<'static>,
|
||||||
|
offline_signal: &'static Signal<CriticalSectionRawMutex, ()>,
|
||||||
|
) -> ! {
|
||||||
|
// dns client
|
||||||
|
let dns_client = DnsSocket::new(network_stack);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// wait for network stack
|
||||||
|
info!("Wait for network setup");
|
||||||
|
network_stack.wait_config_up().await;
|
||||||
|
network_stack.wait_link_up().await;
|
||||||
|
info!("Successfully setup network stack");
|
||||||
|
info!("Network configuration: {:?}", network_stack.config_v4());
|
||||||
|
|
||||||
|
let socket_address = match dns_client.query(NTP_ENDPOINT, DnsQueryType::A).await {
|
||||||
|
Ok(address) => match address.first() {
|
||||||
|
Some(IpAddress::Ipv4(ipv4)) => {
|
||||||
|
let octets = ipv4.octets();
|
||||||
|
SocketAddr::new(
|
||||||
|
IpAddr::V4(Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3])),
|
||||||
|
NTP_PORT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
info!("DNS A record lookup returned no IPv4 address: {NTP_ENDPOINT}",);
|
||||||
|
Timer::after_secs(DNS_WAIT_SECOND).await;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(error) => {
|
||||||
|
info!("DNS A record lookup for {NTP_ENDPOINT} returned error: {error:?}",);
|
||||||
|
Timer::after_secs(DNS_WAIT_SECOND).await;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
info!("NTP endpoint identified for {NTP_ENDPOINT}: {socket_address}");
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// udp client
|
||||||
|
let mut udp_buffer = PicowUDPBuffer::default();
|
||||||
|
let udp_client = udp_buffer.socket(network_stack, NTP_PORT);
|
||||||
|
let ntp_context = NtpContext::new(PicowTimestampGenerator::from_clock(clock).await);
|
||||||
|
match get_time(socket_address, udp_client, ntp_context).await {
|
||||||
|
Ok(result) => {
|
||||||
|
if let Some(now) = DateTime::from_timestamp(result.sec() as i64, 0) {
|
||||||
|
clock.set_time(now).await;
|
||||||
|
info!("Calibrated system clock with NTP time: {now}");
|
||||||
|
} else {
|
||||||
|
info!("Invalid NTP result: {result:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
info!("Failed to run NTP protocol: {error:?}");
|
||||||
|
offline_signal.signal(());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Timer::after_secs(NTP_WAIT_SECOND).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn online_task(
|
||||||
|
offline_signal: &'static Signal<CriticalSectionRawMutex, ()>,
|
||||||
|
mut wireless_control: cyw43::Control<'static>,
|
||||||
|
) -> ! {
|
||||||
|
loop {
|
||||||
|
// search and join wireless network
|
||||||
|
for (ssid, password) in WIRELESS_CREDENTIALS.iter().cycle() {
|
||||||
|
info!("Search for wireless network: {ssid}");
|
||||||
|
if wireless_control
|
||||||
|
.join(ssid, JoinOptions::new(password.as_bytes()))
|
||||||
|
.await
|
||||||
|
.is_ok()
|
||||||
|
{
|
||||||
|
info!("Successfully joined wireless network: {ssid}");
|
||||||
|
break;
|
||||||
|
} else if ssid
|
||||||
|
== &WIRELESS_CREDENTIALS
|
||||||
|
.last()
|
||||||
|
.expect("The list of wireless credentials should not be empty")
|
||||||
|
.0
|
||||||
|
{
|
||||||
|
info!("Unable to join any wireless network with provided credentials");
|
||||||
|
info!("Sleep for {WIRELESS_SCAN_WAIT_SECOND} seconds before rescan");
|
||||||
|
Timer::after_secs(WIRELESS_SCAN_WAIT_SECOND).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// turn on led for connected wireless
|
||||||
|
wireless_control.gpio_set(0, true).await;
|
||||||
|
|
||||||
|
// wait for offline signal
|
||||||
|
offline_signal.wait().await;
|
||||||
|
info!("Network is down");
|
||||||
|
|
||||||
|
// disconnect wireless
|
||||||
|
info!("Reset wireless");
|
||||||
|
wireless_control.leave().await;
|
||||||
|
|
||||||
|
// turn off led for disconnected network
|
||||||
|
wireless_control.gpio_set(0, false).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn timer_task(clock: &'static PicowClock) -> ! {
|
||||||
|
loop {
|
||||||
|
info!("The current time is: {}", clock.now().await);
|
||||||
|
Timer::after_secs(TIMER_WAIT_SECOND).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn wireless_task(
|
async fn wireless_task(
|
||||||
wireless_runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>,
|
wireless_runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>,
|
||||||
|
|
@ -58,7 +184,11 @@ async fn wireless_task(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[embassy_executor::main]
|
#[embassy_executor::main]
|
||||||
async fn main(spawner: Spawner) -> ! {
|
async fn main(spawner: Spawner) {
|
||||||
|
// system clock
|
||||||
|
static CLOCK: StaticCell<PicowClock> = StaticCell::new();
|
||||||
|
let clock = CLOCK.init(PicowClock::new());
|
||||||
|
|
||||||
// hardware abstraction layer
|
// hardware abstraction layer
|
||||||
let hal = embassy_rp::init(Default::default());
|
let hal = embassy_rp::init(Default::default());
|
||||||
|
|
||||||
|
|
@ -126,73 +256,27 @@ async fn main(spawner: Spawner) -> ! {
|
||||||
RoscRng.next_u64(),
|
RoscRng.next_u64(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// offline signal
|
||||||
|
static OFFLINE_SIGNAL: StaticCell<Signal<CriticalSectionRawMutex, ()>> = StaticCell::new();
|
||||||
|
let offline_signal = OFFLINE_SIGNAL.init(Signal::new());
|
||||||
|
|
||||||
|
// spawn online task
|
||||||
|
spawner
|
||||||
|
.spawn(online_task(offline_signal, wireless_control))
|
||||||
|
.expect("Online task should not fail to spawn");
|
||||||
|
|
||||||
// spawn network task
|
// spawn network task
|
||||||
spawner
|
spawner
|
||||||
.spawn(network_task(network_runner))
|
.spawn(network_task(network_runner))
|
||||||
.expect("Network task should not fail to spawn");
|
.expect("Network task should not fail to spawn");
|
||||||
|
|
||||||
// search and join wireless network
|
// span ntp task
|
||||||
for (ssid, password) in WIRELESS_CREDENTIALS.iter().cycle() {
|
spawner
|
||||||
info!("Searching for wireless network: {ssid}");
|
.spawn(ntp_task(clock, network_stack, offline_signal))
|
||||||
if let Ok(_) = wireless_control
|
.expect("NTP task should not fail to spawn");
|
||||||
.join(ssid, JoinOptions::new(password.as_bytes()))
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
info!("Successfully joined wireless network: {ssid}");
|
|
||||||
break;
|
|
||||||
} else if ssid
|
|
||||||
== &WIRELESS_CREDENTIALS
|
|
||||||
.last()
|
|
||||||
.expect("The list of wireless credentials should not be empty")
|
|
||||||
.0
|
|
||||||
{
|
|
||||||
info!("Unable to join any wireless network with provided credentials");
|
|
||||||
info!("Sleep for {WAIT_SECOND} seconds before rescan");
|
|
||||||
Timer::after_secs(WAIT_SECOND).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait for network stack
|
// spawn timer task
|
||||||
info!("Wait for network setup");
|
spawner
|
||||||
network_stack.wait_config_up().await;
|
.spawn(timer_task(clock))
|
||||||
network_stack.wait_link_up().await;
|
.expect("Timer task should not fail to spawn");
|
||||||
info!("Successfully setup network stack");
|
|
||||||
info!("Network configuration: {:?}", network_stack.config_v4());
|
|
||||||
|
|
||||||
// turn on led to indicate network connection
|
|
||||||
wireless_control.gpio_set(0, true).await;
|
|
||||||
|
|
||||||
// dns client
|
|
||||||
let dns_client = DnsSocket::new(network_stack);
|
|
||||||
|
|
||||||
// udp client
|
|
||||||
// let mut udp_buffer = PicowUDPBuffer::default();
|
|
||||||
// let udp_client = udp_buffer.socket(network_stack);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let ntp_ipv4 = match dns_client.query(NTP_ENDPOINT, DnsQueryType::A).await {
|
|
||||||
Ok(address) => match address.first() {
|
|
||||||
Some(IpAddress::Ipv4(ipv4)) => ipv4.octets(),
|
|
||||||
None => {
|
|
||||||
info!(
|
|
||||||
"DNS A record lookup returned no IPv4 address: {}",
|
|
||||||
NTP_ENDPOINT
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(error) => {
|
|
||||||
info!(
|
|
||||||
"DNS A record lookup returned error: {}, {:?}",
|
|
||||||
NTP_ENDPOINT, error
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
info!(
|
|
||||||
"Resolved IPv4 address for {}: {}.{}.{}.{}",
|
|
||||||
NTP_ENDPOINT, ntp_ipv4[0], ntp_ipv4[1], ntp_ipv4[1], ntp_ipv4[3]
|
|
||||||
);
|
|
||||||
Timer::after_secs(WAIT_SECOND).await;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
use embassy_net::{
|
|
||||||
udp::{PacketMetadata, UdpSocket},
|
|
||||||
Stack,
|
|
||||||
};
|
|
||||||
use embassy_time::{Duration, Instant};
|
|
||||||
use sntpc::NtpTimestampGenerator;
|
|
||||||
|
|
||||||
const UDP_BUFFER_SIZE_BYTE: usize = 1 << 12;
|
|
||||||
const UDP_METADATA_SIZE: usize = 1 << 3;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub struct PicowTimestampGenerator {
|
|
||||||
duration: Duration,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for PicowTimestampGenerator {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
duration: Instant::now().duration_since(Instant::MIN),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NtpTimestampGenerator for PicowTimestampGenerator {
|
|
||||||
fn init(&mut self) {
|
|
||||||
self.duration = Instant::now().duration_since(Instant::MIN);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn timestamp_sec(&self) -> u64 {
|
|
||||||
self.duration.as_secs()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn timestamp_subsec_micros(&self) -> u32 {
|
|
||||||
(self.duration.as_micros() % 1000000) as u32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct PicowUDPBuffer {
|
|
||||||
receive_buffer: [u8; UDP_BUFFER_SIZE_BYTE],
|
|
||||||
receive_metadata: [PacketMetadata; UDP_METADATA_SIZE],
|
|
||||||
transmit_buffer: [u8; UDP_BUFFER_SIZE_BYTE],
|
|
||||||
transmit_metadata: [PacketMetadata; UDP_METADATA_SIZE],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for PicowUDPBuffer {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
receive_buffer: [0; UDP_BUFFER_SIZE_BYTE],
|
|
||||||
receive_metadata: [PacketMetadata::EMPTY; UDP_METADATA_SIZE],
|
|
||||||
transmit_buffer: [0; UDP_BUFFER_SIZE_BYTE],
|
|
||||||
transmit_metadata: [PacketMetadata::EMPTY; UDP_METADATA_SIZE],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PicowUDPBuffer {
|
|
||||||
pub fn socket<'me>(&'me mut self, network_stack: Stack<'me>) -> UdpSocket<'me> {
|
|
||||||
UdpSocket::new(
|
|
||||||
network_stack,
|
|
||||||
&mut self.receive_metadata,
|
|
||||||
&mut self.receive_buffer,
|
|
||||||
&mut self.transmit_metadata,
|
|
||||||
&mut self.transmit_buffer,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
181
src/time.rs
Normal file
181
src/time.rs
Normal file
|
|
@ -0,0 +1,181 @@
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
use chrono::{DateTime, Duration, Utc};
|
||||||
|
use embassy_net::{
|
||||||
|
udp::{PacketMetadata, UdpSocket},
|
||||||
|
IpAddress, IpEndpoint, Stack,
|
||||||
|
};
|
||||||
|
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex};
|
||||||
|
use embassy_time::Instant;
|
||||||
|
use no_std_net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
|
||||||
|
use sntpc::{async_impl::NtpUdpSocket, NtpTimestampGenerator};
|
||||||
|
|
||||||
|
const UDP_BUFFER_SIZE_BYTE: usize = 1 << 12;
|
||||||
|
const UDP_METADATA_SIZE: usize = 1 << 4;
|
||||||
|
|
||||||
|
pub struct PicowClock {
|
||||||
|
startup_timestamp: Mutex<CriticalSectionRawMutex, DateTime<Utc>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PicowClock {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
startup_timestamp: Mutex::new(DateTime::UNIX_EPOCH),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn now(&self) -> DateTime<Utc> {
|
||||||
|
*self.startup_timestamp.lock().await
|
||||||
|
+ Duration::microseconds(Instant::now().as_micros() as i64)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn set_time(&self, now: DateTime<Utc>) {
|
||||||
|
if let Some(corrected_startup_timestamp) =
|
||||||
|
now.checked_sub_signed(Duration::microseconds(Instant::now().as_micros() as i64))
|
||||||
|
{
|
||||||
|
*self.startup_timestamp.lock().await = corrected_startup_timestamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct PicowTimestampGenerator {
|
||||||
|
now: DateTime<Utc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NtpTimestampGenerator for PicowTimestampGenerator {
|
||||||
|
fn init(&mut self) {}
|
||||||
|
|
||||||
|
fn timestamp_sec(&self) -> u64 {
|
||||||
|
self.now.timestamp() as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn timestamp_subsec_micros(&self) -> u32 {
|
||||||
|
self.now.timestamp_subsec_micros()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PicowTimestampGenerator {
|
||||||
|
pub async fn from_clock(clock: &PicowClock) -> Self {
|
||||||
|
Self {
|
||||||
|
now: clock.now().await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PicowUDPSocket<'me> {
|
||||||
|
socket: UdpSocket<'me>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for PicowUDPSocket<'_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("PicowUDPSocket")
|
||||||
|
.field("socket", &self.socket.endpoint())
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'me> NtpUdpSocket for PicowUDPSocket<'me> {
|
||||||
|
async fn send_to<T: ToSocketAddrs + Send>(&self, buf: &[u8], addr: T) -> sntpc::Result<usize> {
|
||||||
|
use sntpc::Error::*;
|
||||||
|
let socket_address = addr
|
||||||
|
.to_socket_addrs()
|
||||||
|
.map_err(|_| AddressResolve)?
|
||||||
|
.next()
|
||||||
|
.ok_or(AddressResolve)?;
|
||||||
|
|
||||||
|
// TODO: Simplify conversion once no-std-net is deprecated
|
||||||
|
let endpoint = IpEndpoint::new(
|
||||||
|
match socket_address.ip() {
|
||||||
|
IpAddr::V4(ipv4) => {
|
||||||
|
let octets = ipv4.octets();
|
||||||
|
IpAddress::v4(octets[0], octets[1], octets[2], octets[3])
|
||||||
|
}
|
||||||
|
IpAddr::V6(ipv6) => {
|
||||||
|
let segments = ipv6.segments();
|
||||||
|
IpAddress::v6(
|
||||||
|
segments[0],
|
||||||
|
segments[1],
|
||||||
|
segments[2],
|
||||||
|
segments[3],
|
||||||
|
segments[4],
|
||||||
|
segments[5],
|
||||||
|
segments[6],
|
||||||
|
segments[7],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
socket_address.port(),
|
||||||
|
);
|
||||||
|
self.socket
|
||||||
|
.send_to(buf, endpoint)
|
||||||
|
.await
|
||||||
|
.map_err(|_| Network)?;
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn recv_from(&self, buf: &mut [u8]) -> sntpc::Result<(usize, SocketAddr)> {
|
||||||
|
use sntpc::Error::*;
|
||||||
|
let (size, metadata) = self.socket.recv_from(buf).await.map_err(|_| Network)?;
|
||||||
|
Ok((
|
||||||
|
size,
|
||||||
|
SocketAddr::new(
|
||||||
|
// TODO: Simplify conversion once no-std-net is deprecated
|
||||||
|
match metadata.endpoint.addr {
|
||||||
|
IpAddress::Ipv4(ipv4) => {
|
||||||
|
let octets = ipv4.octets();
|
||||||
|
IpAddr::V4(Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]))
|
||||||
|
}
|
||||||
|
IpAddress::Ipv6(ipv6) => {
|
||||||
|
let segments = ipv6.segments();
|
||||||
|
IpAddr::V6(Ipv6Addr::new(
|
||||||
|
segments[0],
|
||||||
|
segments[1],
|
||||||
|
segments[2],
|
||||||
|
segments[3],
|
||||||
|
segments[4],
|
||||||
|
segments[5],
|
||||||
|
segments[6],
|
||||||
|
segments[7],
|
||||||
|
))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
metadata.endpoint.port,
|
||||||
|
),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PicowUDPBuffer {
|
||||||
|
receive_buffer: [u8; UDP_BUFFER_SIZE_BYTE],
|
||||||
|
receive_metadata: [PacketMetadata; UDP_METADATA_SIZE],
|
||||||
|
transmit_buffer: [u8; UDP_BUFFER_SIZE_BYTE],
|
||||||
|
transmit_metadata: [PacketMetadata; UDP_METADATA_SIZE],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PicowUDPBuffer {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
receive_buffer: [0; UDP_BUFFER_SIZE_BYTE],
|
||||||
|
receive_metadata: [PacketMetadata::EMPTY; UDP_METADATA_SIZE],
|
||||||
|
transmit_buffer: [0; UDP_BUFFER_SIZE_BYTE],
|
||||||
|
transmit_metadata: [PacketMetadata::EMPTY; UDP_METADATA_SIZE],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PicowUDPBuffer {
|
||||||
|
pub fn socket<'me>(&'me mut self, network_stack: Stack<'me>, port: u16) -> PicowUDPSocket<'me> {
|
||||||
|
let mut socket = UdpSocket::new(
|
||||||
|
network_stack,
|
||||||
|
&mut self.receive_metadata,
|
||||||
|
&mut self.receive_buffer,
|
||||||
|
&mut self.transmit_metadata,
|
||||||
|
&mut self.transmit_buffer,
|
||||||
|
);
|
||||||
|
socket
|
||||||
|
.bind(port)
|
||||||
|
.expect("UDP socket should be able to bind to local port");
|
||||||
|
PicowUDPSocket { socket }
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue