Compare commits
602 Commits
embassy-ti
...
embassy-ex
Author | SHA1 | Date | |
---|---|---|---|
dd6a29adb2 | |||
74683c706b | |||
2795e1350d | |||
aed3e5674f | |||
d941882066 | |||
3f74ff7235 | |||
9cead47212 | |||
78739d4aa9 | |||
e07e790613 | |||
ca283eed0c | |||
57edf289ea | |||
3912f5d67b | |||
c9b50e46a5 | |||
ad07ea0290 | |||
573734008a | |||
f4a78e00a7 | |||
0d6094c8b1 | |||
b6fc682117 | |||
0beb84768e | |||
b98a279367 | |||
e8a3cfaed6 | |||
0cc3e18db6 | |||
6b19c0abd1 | |||
f956d19e6e | |||
ceb0d0bf08 | |||
b3879ec223 | |||
bda99e59ec | |||
25c2a9baaa | |||
1e362c750b | |||
1a51a84313 | |||
7f72dbdaf2 | |||
e8c162ac03 | |||
1aaa19748a | |||
9e230b64a4 | |||
17b4cf8ce7 | |||
df4aa0fe25 | |||
188ee59ba6 | |||
591612db7e | |||
d673f8a865 | |||
82593bd404 | |||
a39ae12edc | |||
0ef1cb29f7 | |||
64ab23d17d | |||
18c9bcd44a | |||
e895ea2d8b | |||
b9e13cb5d1 | |||
46ff2c82aa | |||
a84ad741a4 | |||
412bcad2d1 | |||
e70c531d3d | |||
7c5f963d1f | |||
62e1e1637c | |||
3d03c18d4f | |||
2157c5a4e3 | |||
0fb677aad7 | |||
b1d0947a18 | |||
5b3f75dc72 | |||
6f2995cd4c | |||
88ada52146 | |||
d622181205 | |||
630443a4d6 | |||
035800bfbd | |||
c7803bb8f4 | |||
d496a1213c | |||
241488ef1c | |||
88b2cdd6a0 | |||
35ffdf2143 | |||
3cbc687424 | |||
4f7b831676 | |||
f20f170b1f | |||
67010d123c | |||
51708c8ed1 | |||
361fde35cf | |||
7ce3b19389 | |||
10f08445e4 | |||
f24a1b62bb | |||
bbd12c9372 | |||
6906cc9c25 | |||
cb211f88d3 | |||
3f262a2603 | |||
d94b9fe6fb | |||
b478640463 | |||
846f2fc6e4 | |||
683d5c3066 | |||
a3574e519a | |||
3e3317e8bd | |||
e7aeb9b29f | |||
7fd868ade9 | |||
6e6df22979 | |||
f7980885a5 | |||
5a1393aa0b | |||
40e4ca4751 | |||
1d810baa18 | |||
213b4c9dca | |||
889d482d2d | |||
ea0e83a7f9 | |||
f0497039ed | |||
aff77d2b65 | |||
a7c6999670 | |||
18e96898ea | |||
870dcc5970 | |||
5c5e681819 | |||
f54753beaa | |||
b24520579a | |||
31d4516516 | |||
66e62e9994 | |||
eeedaf2e76 | |||
1fc35c753b | |||
cd92bc3145 | |||
4a156df7a1 | |||
c46e758e2c | |||
8a10948ce9 | |||
7045c53170 | |||
0621e957a0 | |||
a818f33658 | |||
3bfbf2697f | |||
7559f9e583 | |||
c8fdbe19f9 | |||
2e50bf667a | |||
ba62037642 | |||
824556c9c8 | |||
f7c0ec66d2 | |||
69bb455c60 | |||
575db17264 | |||
0aa99e66f7 | |||
3264941c1b | |||
a57d383b1d | |||
9a7fda87b0 | |||
adc810d24b | |||
75baf186f3 | |||
a6bbb130c5 | |||
d1ac6d2824 | |||
636958ff70 | |||
7f6fe93f55 | |||
e9b1904db8 | |||
02d2c06b23 | |||
debda2f52c | |||
97ca0e77bf | |||
66e399b5c6 | |||
01eb1a7339 | |||
f0d6ee69bc | |||
65f81a1f57 | |||
ecdd7c0e2f | |||
d7d79f3068 | |||
f65a96c541 | |||
eb368f77a4 | |||
57ccc1051a | |||
ac84631a2a | |||
70a91945fc | |||
32b89eeba1 | |||
063e6f96da | |||
4cec4b0548 | |||
e6c47c3718 | |||
2f7c2750d1 | |||
032b1f2d59 | |||
f76d50e837 | |||
ee5ea7aa06 | |||
251d004708 | |||
cd68f85501 | |||
b6c0ddb7df | |||
ee93bbf1d4 | |||
7b1cd42936 | |||
1cd3ae9bd5 | |||
bfcca79c1e | |||
c283e2d1b9 | |||
4a43cd3982 | |||
0dda888c95 | |||
b91d1eaca0 | |||
5a19d18b9c | |||
ed7b6056a6 | |||
322f9cb153 | |||
3ec4e6320a | |||
233aa1b53a | |||
21915a9a3f | |||
d0d0ceec6a | |||
9be61a2967 | |||
0cfa8d1bb5 | |||
cd12c9cbce | |||
eff73d6dfa | |||
3616d68aaa | |||
904f1cfc7a | |||
e62bf6a9fd | |||
7526b8edba | |||
0c97ce2fcc | |||
62d6bb6c8a | |||
c3ef98a73d | |||
6186fe0807 | |||
c4cff0b79b | |||
2e5ab7981e | |||
9d311121f2 | |||
25c3754cd2 | |||
85c6f23dcb | |||
9c6a2d9cbd | |||
b67b179933 | |||
d4ed8e5779 | |||
3e054a6f0d | |||
c6d53e7bce | |||
3bf8e4de5f | |||
9090a78df4 | |||
022d870d61 | |||
534eb960e9 | |||
7a2b8481f7 | |||
710874021a | |||
3a8e0d4a27 | |||
b217d147de | |||
68c4820dde | |||
f30fc949ff | |||
75c1a9a3aa | |||
4075ac84e1 | |||
f01609036f | |||
930b8f3495 | |||
38e7709a24 | |||
65ed19aae2 | |||
be9c05fbc9 | |||
42176b1a3a | |||
e1a0635ca3 | |||
b887b7516e | |||
c6513f93fe | |||
59f706ee2f | |||
ba7d74ac16 | |||
0324cee0ca | |||
8ac5c1a963 | |||
e7ab044935 | |||
0c4cddfafb | |||
e561e673c2 | |||
09dfcd6b66 | |||
bb8a1b7f1f | |||
b012a67df7 | |||
40f30fa4cd | |||
f197aa9419 | |||
80a740bc72 | |||
ad524373ed | |||
9badf740d8 | |||
6e901846df | |||
c0a6c78a14 | |||
58280048e3 | |||
00824af82b | |||
adf9ffb109 | |||
bc203ebe4b | |||
e042b3056d | |||
9dc927250c | |||
b856d760f4 | |||
a742a80171 | |||
a9dc887060 | |||
137e47f98d | |||
90ade1b311 | |||
a931dfd9ad | |||
eff61648fe | |||
9228a6334b | |||
3c9dfbbc9d | |||
ce0add61f8 | |||
bf6e06060b | |||
eb12114345 | |||
4b252586e5 | |||
5f6a915a32 | |||
923f1851ee | |||
bd267a6479 | |||
f3aa0cfe5a | |||
6ea5aa347d | |||
8c13126cff | |||
81da9ca621 | |||
729338875c | |||
f98c8886b2 | |||
05a9b11316 | |||
a1036e111e | |||
561126b0d6 | |||
2af97e7595 | |||
2008030a8b | |||
480328d07e | |||
05218a52e6 | |||
d2a2734752 | |||
5ad34404af | |||
a7b1e51650 | |||
70005c3956 | |||
93adbb9922 | |||
e80df91e02 | |||
5cb58754d4 | |||
5c83179071 | |||
49608714aa | |||
f116ca83e0 | |||
6e5f3f9515 | |||
5924cc8b49 | |||
0d49aaf8ca | |||
5dd9e9b3b7 | |||
d42cfda2db | |||
d1f4511cd1 | |||
fa8d5da4a5 | |||
7bc57ca3f7 | |||
7ad102695d | |||
4999de6f82 | |||
9b8bdad403 | |||
3c3fb0a529 | |||
dc4c27aead | |||
74eb519810 | |||
61dc36b1f2 | |||
55a0a15be2 | |||
fc8f96fea5 | |||
08175f191a | |||
8da987cfbb | |||
1be5f193c3 | |||
4a632e08b7 | |||
6cdee93934 | |||
5c8c1b2146 | |||
2addfc4b86 | |||
92df87781d | |||
a35d149cb1 | |||
c52320f467 | |||
2f9b59c5cf | |||
ce91fb2bfc | |||
95b3d9eb3b | |||
f1e7205055 | |||
6627824c02 | |||
d62533879c | |||
e1a8caffa4 | |||
dffdb9268b | |||
22e820b743 | |||
aa14f18d3f | |||
39f1b26a39 | |||
e70143ef8f | |||
d6654bf8b5 | |||
322a4a8401 | |||
ee5591017b | |||
b1b32f079b | |||
e8a462768e | |||
ce0d787781 | |||
fa2e63f74b | |||
23f3889167 | |||
a72a91ab06 | |||
b9ef831ff7 | |||
e538aeacc8 | |||
6b3745fc47 | |||
6200d22438 | |||
901d31e8f8 | |||
79146c4bd5 | |||
d9eae79f3e | |||
3d1b4116ec | |||
901f0257bd | |||
fec4194ae6 | |||
f866735802 | |||
20ea76c19c | |||
e1951f3ddf | |||
8b5fb254c0 | |||
624f786203 | |||
a57e48459e | |||
c604d8a8f1 | |||
be0c52bf5e | |||
44bb405683 | |||
e8587e2fba | |||
5d8817d109 | |||
c79a84a98a | |||
96edbd84fb | |||
dc400a0539 | |||
04b09a2acb | |||
481d2998ef | |||
4b695120fc | |||
bd9021ca1d | |||
6e63c8d4bf | |||
70acc093dd | |||
f7c2db245f | |||
2543bcafaf | |||
9f2fc04caa | |||
f32bfafa61 | |||
e03239e88d | |||
7d5e62d4a7 | |||
65d36f9f99 | |||
347ff18644 | |||
1e80fd81f7 | |||
52e269edbb | |||
c849620cd6 | |||
6f83acc010 | |||
2b7b7a917d | |||
f1488864eb | |||
7cf327130e | |||
02b0523199 | |||
47175198c0 | |||
4b20e6c258 | |||
83b4c01273 | |||
e313ca4ae8 | |||
ad64d7b20b | |||
5626a28af2 | |||
766ae724cb | |||
00b9f9acef | |||
d46920dce6 | |||
e1ed492577 | |||
2405aff11f | |||
a402aed3d1 | |||
c573959a95 | |||
561696dfad | |||
b1abaa380f | |||
e640933e2f | |||
183824fbdd | |||
5d0c40f61d | |||
fdfe12fe1c | |||
4bfbcd6c72 | |||
0da793e5de | |||
0dcb34fc7d | |||
feaeee1e83 | |||
a6ef314be1 | |||
daeb497045 | |||
88eb5cca71 | |||
cd128c20fa | |||
087ef918bf | |||
75cae09e79 | |||
bbe1d96045 | |||
3ddc9cd110 | |||
de2773afdd | |||
2930be5e17 | |||
09f087e53e | |||
044b837caa | |||
ad0a306ea5 | |||
b5fffbf66f | |||
537e2f3b44 | |||
80d7193b5b | |||
8315cf064e | |||
a2a26f489b | |||
f27620cc0b | |||
2911774849 | |||
6da75ea285 | |||
aa2fa29b89 | |||
c28a6bdd0b | |||
5a158b94bd | |||
c091ed2f63 | |||
45e9e51bdc | |||
7c77d2bd94 | |||
f76d94098d | |||
07233ca5b4 | |||
9fb14379c3 | |||
309c3d6b47 | |||
f1f4943ca5 | |||
1b20ba27b1 | |||
f5e96a9d60 | |||
e8b961232b | |||
85a9f5816f | |||
7bcc7e8962 | |||
b118c4cc1b | |||
f090a38dde | |||
dcd1a91966 | |||
49847ff432 | |||
b9d4b18f14 | |||
3a1ed823f8 | |||
9c647dd0e8 | |||
582ef90994 | |||
5e381d49da | |||
af59fa0a7e | |||
4907ccaa4d | |||
2c38dd17b9 | |||
d36e7abb71 | |||
e11db9fa59 | |||
f877a5889d | |||
db54edf56c | |||
4072a16af6 | |||
44a5c32ea4 | |||
b9889ad3b5 | |||
527bdc57b9 | |||
1133cbf90e | |||
77c357e744 | |||
521970535e | |||
93d4cfe7c1 | |||
8413a89752 | |||
db717d9c81 | |||
808fa9dce6 | |||
ceb13def19 | |||
5cf494113f | |||
8edb7bb012 | |||
8900f5f52b | |||
8201979d71 | |||
2d9f50addc | |||
18da91e252 | |||
28e2570533 | |||
26e0823c35 | |||
ceca8b4336 | |||
e308286f3c | |||
268da2fcde | |||
a992d4895d | |||
1bae34d37c | |||
aac42e3209 | |||
08415e001e | |||
d6a1b567ee | |||
a47fb42962 | |||
70a4a193c5 | |||
2132afb48b | |||
0e9131fd14 | |||
40a18b075d | |||
f17f09057d | |||
11a78fb1e4 | |||
48154e18bf | |||
cf2d4eca7c | |||
3e0b752bef | |||
6070d61d8c | |||
a4f8d82ef5 | |||
c27b0296fe | |||
336ae54a56 | |||
d6a1118406 | |||
9de08d56a0 | |||
26740bb3ef | |||
4550452f43 | |||
08410432b5 | |||
3cf3caa3ab | |||
c21ad04c2e | |||
d097c99719 | |||
af7c93abba | |||
c356585a59 | |||
0d3ff34d80 | |||
bb2d6c8542 | |||
a05afc5426 | |||
50116e5b27 | |||
a80acf686e | |||
6770d8e8a6 | |||
7307098780 | |||
f4601af2a4 | |||
fd22f4fac5 | |||
7622d2eb61 | |||
7573160077 | |||
7e18e5e0c1 | |||
9d76a6e933 | |||
f502271940 | |||
e2f8bf19ea | |||
1180e1770d | |||
49ba9c3da2 | |||
ce662766be | |||
a03b6be693 | |||
87d3086533 | |||
d19e1c1dd1 | |||
8a55adbfd8 | |||
6dc56d2b35 | |||
394503ab69 | |||
bfb4cf775a | |||
274f63a879 | |||
615882ebd6 | |||
6e38b07642 | |||
1eb03dc41a | |||
a2656f402b | |||
3466c9cfa9 | |||
3295ec94e5 | |||
c5732ce285 | |||
2e6f4237f2 | |||
ac11635b0b | |||
9dd58660c3 | |||
9baa3bafb0 | |||
360286e67c | |||
0c66636d00 | |||
9d8c527308 | |||
1d87ec9cc3 | |||
b74645e259 | |||
56351cedcb | |||
0823d9dc93 | |||
c10fb7c1c4 | |||
a2ce3aa1a1 | |||
3769447382 | |||
2c6b428ed4 | |||
83a976cf4b | |||
a76ff53fb3 | |||
f69e8459c9 | |||
891f1758bc | |||
ae174fd0e0 | |||
5c936d33d4 | |||
36ec9bcc1d | |||
5adc80f6d9 | |||
98f55fa54d | |||
416ecc73d8 | |||
27dfced285 | |||
21681d8b4e | |||
989c98f316 | |||
fdb2c4946a | |||
5e613d9abb | |||
40b576584e | |||
aa7752020e | |||
6c165f8dc0 | |||
975f2f23c0 | |||
0eeefd3dbf | |||
de01fe352b | |||
70662ec4ba | |||
a4d78a6552 | |||
f503417f4c | |||
6b8b145266 | |||
e07f943562 | |||
70a5221b2e | |||
b315c28d4e | |||
e025693914 | |||
05ee02b593 | |||
4098a61ef0 | |||
1db00f5439 | |||
7fc17bc150 | |||
6e616a6fe6 | |||
d02886786e | |||
2db4d01198 | |||
fd739250ea | |||
71c4e7e4d2 | |||
2c80784fe6 | |||
538001a4bc | |||
e981cd4968 | |||
91bb3aae3f | |||
e08dbcd027 | |||
5c27265a21 | |||
2c36199dea | |||
13a0be6289 | |||
9f928010a8 | |||
7f7256050c | |||
4b6538c8a8 | |||
f033089625 | |||
6d8a5c6c20 | |||
3aedbce5c2 |
4
.github/bors.toml
vendored
4
.github/bors.toml
vendored
@ -1,4 +0,0 @@
|
|||||||
status = [
|
|
||||||
"all",
|
|
||||||
]
|
|
||||||
delete_merged_branches = true
|
|
4
.github/ci/build-stable.sh
vendored
4
.github/ci/build-stable.sh
vendored
@ -8,6 +8,10 @@ export RUSTUP_HOME=/ci/cache/rustup
|
|||||||
export CARGO_HOME=/ci/cache/cargo
|
export CARGO_HOME=/ci/cache/cargo
|
||||||
export CARGO_TARGET_DIR=/ci/cache/target
|
export CARGO_TARGET_DIR=/ci/cache/target
|
||||||
|
|
||||||
|
# needed for "dumb HTTP" transport support
|
||||||
|
# used when pointing stm32-metapac to a CI-built one.
|
||||||
|
export CARGO_NET_GIT_FETCH_WITH_CLI=true
|
||||||
|
|
||||||
hashtime restore /ci/cache/filetime.json || true
|
hashtime restore /ci/cache/filetime.json || true
|
||||||
hashtime save /ci/cache/filetime.json
|
hashtime save /ci/cache/filetime.json
|
||||||
|
|
||||||
|
5
.github/ci/build.sh
vendored
5
.github/ci/build.sh
vendored
@ -11,8 +11,13 @@ if [ -f /ci/secrets/teleprobe-token.txt ]; then
|
|||||||
echo Got teleprobe token!
|
echo Got teleprobe token!
|
||||||
export TELEPROBE_HOST=https://teleprobe.embassy.dev
|
export TELEPROBE_HOST=https://teleprobe.embassy.dev
|
||||||
export TELEPROBE_TOKEN=$(cat /ci/secrets/teleprobe-token.txt)
|
export TELEPROBE_TOKEN=$(cat /ci/secrets/teleprobe-token.txt)
|
||||||
|
export TELEPROBE_CACHE=/ci/cache/teleprobe_cache.json
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# needed for "dumb HTTP" transport support
|
||||||
|
# used when pointing stm32-metapac to a CI-built one.
|
||||||
|
export CARGO_NET_GIT_FETCH_WITH_CLI=true
|
||||||
|
|
||||||
hashtime restore /ci/cache/filetime.json || true
|
hashtime restore /ci/cache/filetime.json || true
|
||||||
hashtime save /ci/cache/filetime.json
|
hashtime save /ci/cache/filetime.json
|
||||||
|
|
||||||
|
2
.github/ci/doc.sh
vendored
2
.github/ci/doc.sh
vendored
@ -48,8 +48,8 @@ kubectl cp webroot/static $POD:/data
|
|||||||
|
|
||||||
# build and upload stm32 last
|
# build and upload stm32 last
|
||||||
# so that it doesn't prevent other crates from getting docs updates when it breaks.
|
# so that it doesn't prevent other crates from getting docs updates when it breaks.
|
||||||
|
|
||||||
rm -rf webroot
|
rm -rf webroot
|
||||||
docserver-builder -i ./embassy-stm32 -o webroot/crates/embassy-stm32/git.zup
|
docserver-builder -i ./embassy-stm32 -o webroot/crates/embassy-stm32/git.zup
|
||||||
|
|
||||||
POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name})
|
POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name})
|
||||||
kubectl cp webroot/crates $POD:/data
|
kubectl cp webroot/crates $POD:/data
|
||||||
|
4
.github/ci/test.sh
vendored
4
.github/ci/test.sh
vendored
@ -8,6 +8,10 @@ export RUSTUP_HOME=/ci/cache/rustup
|
|||||||
export CARGO_HOME=/ci/cache/cargo
|
export CARGO_HOME=/ci/cache/cargo
|
||||||
export CARGO_TARGET_DIR=/ci/cache/target
|
export CARGO_TARGET_DIR=/ci/cache/target
|
||||||
|
|
||||||
|
# needed for "dumb HTTP" transport support
|
||||||
|
# used when pointing stm32-metapac to a CI-built one.
|
||||||
|
export CARGO_NET_GIT_FETCH_WITH_CLI=true
|
||||||
|
|
||||||
hashtime restore /ci/cache/filetime.json || true
|
hashtime restore /ci/cache/filetime.json || true
|
||||||
hashtime save /ci/cache/filetime.json
|
hashtime save /ci/cache/filetime.json
|
||||||
|
|
||||||
|
@ -62,9 +62,9 @@ async fn blink(pin: AnyPin) {
|
|||||||
loop {
|
loop {
|
||||||
// Timekeeping is globally available, no need to mess with hardware timers.
|
// Timekeeping is globally available, no need to mess with hardware timers.
|
||||||
led.set_high();
|
led.set_high();
|
||||||
Timer::after(Duration::from_millis(150)).await;
|
Timer::after_millis(150).await;
|
||||||
led.set_low();
|
led.set_low();
|
||||||
Timer::after(Duration::from_millis(150)).await;
|
Timer::after_millis(150).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
134
ci.sh
134
ci.sh
@ -1,9 +1,12 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -euo pipefail
|
set -eo pipefail
|
||||||
|
|
||||||
export RUSTFLAGS=-Dwarnings
|
export RUSTFLAGS=-Dwarnings
|
||||||
export DEFMT_LOG=trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info
|
export DEFMT_LOG=trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info
|
||||||
|
if [[ -z "${CARGO_TARGET_DIR}" ]]; then
|
||||||
|
export CARGO_TARGET_DIR=target_ci
|
||||||
|
fi
|
||||||
|
|
||||||
TARGET=$(rustc -vV | sed -n 's|host: ||p')
|
TARGET=$(rustc -vV | sed -n 's|host: ||p')
|
||||||
|
|
||||||
@ -36,7 +39,7 @@ cargo batch \
|
|||||||
--- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \
|
--- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,nightly \
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,nightly,dhcpv4-hostname \
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ieee802154 \
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ieee802154 \
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,medium-ieee802154 \
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,medium-ieee802154 \
|
||||||
@ -66,46 +69,68 @@ cargo batch \
|
|||||||
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly \
|
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly \
|
||||||
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,intrinsics \
|
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,intrinsics \
|
||||||
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,qspi-as-gpio \
|
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,qspi-as-gpio \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,time-driver-any \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,time-driver-any,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,time-driver-any \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,time-driver-any,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,time-driver-any,unstable-traits,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,unstable-traits,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,unstable-traits \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f410tb,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f401ve,defmt,exti,time-driver-any,unstable-traits \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f411ce,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f405zg,defmt,exti,time-driver-any,unstable-traits \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f413vh,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f407zg,defmt,exti,time-driver-any,unstable-traits \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits,embedded-sdmmc \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f401ve,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f730i8,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f405zg,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f407zg,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f410tb,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f411ce,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l422cb,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f412zg,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wb15cc,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f413vh,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l072cz,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f415zg,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f417zg,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f423zh,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f398ve,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f427zi,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f378cc,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits,embedded-sdmmc,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32g0c1ve,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f437zi,log,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f217zg,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f439zi,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,stm32l552ze,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f446ze,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32wl54jc-cm0p,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f469zi,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wle5jb,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f479zi,defmt,exti,time-driver-any,unstable-traits,embedded-sdmmc,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32g474pe,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f730i8,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f107vc,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h753zi,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f103re,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h735zg,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f100c4,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32h503rb,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32h562ag,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l422cb,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wb15cc,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l072cz,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l073cz,defmt,exti,time-driver-any,unstable-traits,low-power,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f398ve,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f378cc,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32g0c1ve,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f217zg,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,stm32l552ze,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32wl54jc-cm0p,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wle5jb,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32g474pe,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f107vc,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f103re,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f100c4,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32h503rb,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32h562ag,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\
|
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\
|
||||||
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \
|
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \
|
||||||
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \
|
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \
|
||||||
@ -144,9 +169,10 @@ cargo batch \
|
|||||||
--- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32l5 \
|
--- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32l5 \
|
||||||
--- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \
|
--- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \
|
||||||
--- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb \
|
--- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb \
|
||||||
|
--- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32wba \
|
||||||
--- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl \
|
--- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl \
|
||||||
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --out-dir out/examples/boot/nrf \
|
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --out-dir out/examples/boot/nrf52840 \
|
||||||
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --out-dir out/examples/boot/nrf \
|
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --out-dir out/examples/boot/nrf9160 \
|
||||||
--- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/rp \
|
--- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/rp \
|
||||||
--- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f3 \
|
--- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f3 \
|
||||||
--- build --release --manifest-path examples/boot/application/stm32f7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f7 \
|
--- build --release --manifest-path examples/boot/application/stm32f7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f7 \
|
||||||
@ -166,15 +192,41 @@ cargo batch \
|
|||||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g071rb --out-dir out/tests/stm32g071rb \
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g071rb --out-dir out/tests/stm32g071rb \
|
||||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32c031c6 --out-dir out/tests/stm32c031c6 \
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32c031c6 --out-dir out/tests/stm32c031c6 \
|
||||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi --out-dir out/tests/stm32h755zi \
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi --out-dir out/tests/stm32h755zi \
|
||||||
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h753zi --out-dir out/tests/stm32h753zi \
|
||||||
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7a3zi --out-dir out/tests/stm32h7a3zi \
|
||||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/stm32wb55rg \
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/stm32wb55rg \
|
||||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h563zi --out-dir out/tests/stm32h563zi \
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h563zi --out-dir out/tests/stm32h563zi \
|
||||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/stm32u585ai \
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/stm32u585ai \
|
||||||
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u5a5zj --out-dir out/tests/stm32u5a5zj \
|
||||||
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wba52cg --out-dir out/tests/stm32wba52cg \
|
||||||
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l073rz --out-dir out/tests/stm32l073rz \
|
||||||
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l152re --out-dir out/tests/stm32l152re \
|
||||||
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4a6zg --out-dir out/tests/stm32l4a6zg \
|
||||||
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4r5zi --out-dir out/tests/stm32l4r5zi \
|
||||||
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze --out-dir out/tests/stm32l552ze \
|
||||||
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f767zi --out-dir out/tests/stm32f767zi \
|
||||||
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f207zg --out-dir out/tests/stm32f207zg \
|
||||||
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303ze --out-dir out/tests/stm32f303ze \
|
||||||
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l496zg --out-dir out/tests/stm32l496zg \
|
||||||
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55jc --out-dir out/tests/stm32wl55jc \
|
||||||
--- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \
|
--- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \
|
||||||
--- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \
|
--- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \
|
||||||
--- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \
|
--- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \
|
||||||
$BUILD_EXTRA
|
$BUILD_EXTRA
|
||||||
|
|
||||||
|
|
||||||
|
rm out/tests/stm32wb55rg/wpan_mac
|
||||||
|
rm out/tests/stm32wb55rg/wpan_ble
|
||||||
|
|
||||||
|
# unstable
|
||||||
|
rm out/tests/stm32f429zi/stop
|
||||||
|
|
||||||
|
# unstable, I think it's running out of RAM?
|
||||||
|
rm out/tests/stm32f207zg/eth
|
||||||
|
|
||||||
|
# doesn't work, gives "noise error", no idea why. usart_dma does pass.
|
||||||
|
rm out/tests/stm32u5a5zj/usart
|
||||||
|
|
||||||
if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
|
if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
|
||||||
echo No teleprobe token found, skipping running HIL tests
|
echo No teleprobe token found, skipping running HIL tests
|
||||||
exit
|
exit
|
||||||
|
61
ci_stable.sh
61
ci_stable.sh
@ -40,33 +40,38 @@ cargo batch \
|
|||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585zi,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585zi,defmt,exti,time-driver-any,unstable-traits \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55vy,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55vy,defmt,exti,time-driver-any,unstable-traits \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55cc-cm4,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55cc-cm4,defmt,exti,time-driver-any,unstable-traits \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4r9zi,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g473cc,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303vc,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g491re,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585zi,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55vy,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55cc-cm4,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4r9zi,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303vc,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,time \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,unstable-traits,time \
|
||||||
--- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --no-default-features --out-dir out/examples/nrf52840 --bin raw_spawn \
|
--- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --no-default-features --out-dir out/examples/nrf52840 --bin raw_spawn \
|
||||||
--- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --no-default-features --out-dir out/examples/stm32l0 --bin raw_spawn \
|
--- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --no-default-features --out-dir out/examples/stm32l0 --bin raw_spawn \
|
||||||
|
@ -11,11 +11,10 @@ log = ["dep:log"]
|
|||||||
firmware-logs = []
|
firmware-logs = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-time = { version = "0.1.3", path = "../embassy-time"}
|
embassy-time = { version = "0.1.5", path = "../embassy-time"}
|
||||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync"}
|
embassy-sync = { version = "0.4.0", path = "../embassy-sync"}
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
|
||||||
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"}
|
embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"}
|
||||||
atomic-polyfill = "0.1.5"
|
|
||||||
|
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
log = { version = "0.4.17", optional = true }
|
log = { version = "0.4.17", optional = true }
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use embassy_futures::yield_now;
|
use embassy_futures::yield_now;
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::Timer;
|
||||||
use embedded_hal_1::digital::OutputPin;
|
use embedded_hal_1::digital::OutputPin;
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
|
|
||||||
@ -51,9 +51,9 @@ where
|
|||||||
pub async fn init(&mut self) {
|
pub async fn init(&mut self) {
|
||||||
// Reset
|
// Reset
|
||||||
self.pwr.set_low().unwrap();
|
self.pwr.set_low().unwrap();
|
||||||
Timer::after(Duration::from_millis(20)).await;
|
Timer::after_millis(20).await;
|
||||||
self.pwr.set_high().unwrap();
|
self.pwr.set_high().unwrap();
|
||||||
Timer::after(Duration::from_millis(250)).await;
|
Timer::after_millis(250).await;
|
||||||
|
|
||||||
while self
|
while self
|
||||||
.read32_swapped(REG_BUS_TEST_RO)
|
.read32_swapped(REG_BUS_TEST_RO)
|
||||||
|
@ -96,6 +96,7 @@ pub(crate) const IOCTL_CMD_UP: u32 = 2;
|
|||||||
pub(crate) const IOCTL_CMD_DOWN: u32 = 3;
|
pub(crate) const IOCTL_CMD_DOWN: u32 = 3;
|
||||||
pub(crate) const IOCTL_CMD_SET_SSID: u32 = 26;
|
pub(crate) const IOCTL_CMD_SET_SSID: u32 = 26;
|
||||||
pub(crate) const IOCTL_CMD_SET_CHANNEL: u32 = 30;
|
pub(crate) const IOCTL_CMD_SET_CHANNEL: u32 = 30;
|
||||||
|
pub(crate) const IOCTL_CMD_DISASSOC: u32 = 52;
|
||||||
pub(crate) const IOCTL_CMD_ANTDIV: u32 = 64;
|
pub(crate) const IOCTL_CMD_ANTDIV: u32 = 64;
|
||||||
pub(crate) const IOCTL_CMD_SET_AP: u32 = 118;
|
pub(crate) const IOCTL_CMD_SET_AP: u32 = 118;
|
||||||
pub(crate) const IOCTL_CMD_SET_VAR: u32 = 263;
|
pub(crate) const IOCTL_CMD_SET_VAR: u32 = 263;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use core::cmp::{max, min};
|
use core::cmp::{max, min};
|
||||||
|
|
||||||
use ch::driver::LinkState;
|
|
||||||
use embassy_net_driver_channel as ch;
|
use embassy_net_driver_channel as ch;
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_net_driver_channel::driver::{HardwareAddress, LinkState};
|
||||||
|
use embassy_time::Timer;
|
||||||
|
|
||||||
pub use crate::bus::SpiBusCyw43;
|
pub use crate::bus::SpiBusCyw43;
|
||||||
use crate::consts::*;
|
use crate::consts::*;
|
||||||
@ -87,22 +87,22 @@ impl<'a> Control<'a> {
|
|||||||
self.set_iovar("country", &country_info.to_bytes()).await;
|
self.set_iovar("country", &country_info.to_bytes()).await;
|
||||||
|
|
||||||
// set country takes some time, next ioctls fail if we don't wait.
|
// set country takes some time, next ioctls fail if we don't wait.
|
||||||
Timer::after(Duration::from_millis(100)).await;
|
Timer::after_millis(100).await;
|
||||||
|
|
||||||
// Set antenna to chip antenna
|
// Set antenna to chip antenna
|
||||||
self.ioctl_set_u32(IOCTL_CMD_ANTDIV, 0, 0).await;
|
self.ioctl_set_u32(IOCTL_CMD_ANTDIV, 0, 0).await;
|
||||||
|
|
||||||
self.set_iovar_u32("bus:txglom", 0).await;
|
self.set_iovar_u32("bus:txglom", 0).await;
|
||||||
Timer::after(Duration::from_millis(100)).await;
|
Timer::after_millis(100).await;
|
||||||
//self.set_iovar_u32("apsta", 1).await; // this crashes, also we already did it before...??
|
//self.set_iovar_u32("apsta", 1).await; // this crashes, also we already did it before...??
|
||||||
//Timer::after(Duration::from_millis(100)).await;
|
//Timer::after_millis(100).await;
|
||||||
self.set_iovar_u32("ampdu_ba_wsize", 8).await;
|
self.set_iovar_u32("ampdu_ba_wsize", 8).await;
|
||||||
Timer::after(Duration::from_millis(100)).await;
|
Timer::after_millis(100).await;
|
||||||
self.set_iovar_u32("ampdu_mpdu", 4).await;
|
self.set_iovar_u32("ampdu_mpdu", 4).await;
|
||||||
Timer::after(Duration::from_millis(100)).await;
|
Timer::after_millis(100).await;
|
||||||
//self.set_iovar_u32("ampdu_rx_factor", 0).await; // this crashes
|
//self.set_iovar_u32("ampdu_rx_factor", 0).await; // this crashes
|
||||||
|
|
||||||
//Timer::after(Duration::from_millis(100)).await;
|
//Timer::after_millis(100).await;
|
||||||
|
|
||||||
// evts
|
// evts
|
||||||
let mut evts = EventMask {
|
let mut evts = EventMask {
|
||||||
@ -121,23 +121,33 @@ impl<'a> Control<'a> {
|
|||||||
|
|
||||||
self.set_iovar("bsscfg:event_msgs", &evts.to_bytes()).await;
|
self.set_iovar("bsscfg:event_msgs", &evts.to_bytes()).await;
|
||||||
|
|
||||||
Timer::after(Duration::from_millis(100)).await;
|
Timer::after_millis(100).await;
|
||||||
|
|
||||||
// set wifi up
|
// set wifi up
|
||||||
self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await;
|
self.up().await;
|
||||||
|
|
||||||
Timer::after(Duration::from_millis(100)).await;
|
Timer::after_millis(100).await;
|
||||||
|
|
||||||
self.ioctl_set_u32(110, 0, 1).await; // SET_GMODE = auto
|
self.ioctl_set_u32(110, 0, 1).await; // SET_GMODE = auto
|
||||||
self.ioctl_set_u32(142, 0, 0).await; // SET_BAND = any
|
self.ioctl_set_u32(142, 0, 0).await; // SET_BAND = any
|
||||||
|
|
||||||
Timer::after(Duration::from_millis(100)).await;
|
Timer::after_millis(100).await;
|
||||||
|
|
||||||
self.state_ch.set_ethernet_address(mac_addr);
|
self.state_ch.set_hardware_address(HardwareAddress::Ethernet(mac_addr));
|
||||||
|
|
||||||
debug!("INIT DONE");
|
debug!("INIT DONE");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the WiFi interface up.
|
||||||
|
async fn up(&mut self) {
|
||||||
|
self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the interface down.
|
||||||
|
async fn down(&mut self) {
|
||||||
|
self.ioctl(IoctlType::Set, IOCTL_CMD_DOWN, 0, &mut []).await;
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn set_power_management(&mut self, mode: PowerManagementMode) {
|
pub async fn set_power_management(&mut self, mode: PowerManagementMode) {
|
||||||
// power save mode
|
// power save mode
|
||||||
let mode_num = mode.mode();
|
let mode_num = mode.mode();
|
||||||
@ -175,7 +185,7 @@ impl<'a> Control<'a> {
|
|||||||
self.set_iovar_u32x2("bsscfg:sup_wpa2_eapver", 0, 0xFFFF_FFFF).await;
|
self.set_iovar_u32x2("bsscfg:sup_wpa2_eapver", 0, 0xFFFF_FFFF).await;
|
||||||
self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).await;
|
self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).await;
|
||||||
|
|
||||||
Timer::after(Duration::from_millis(100)).await;
|
Timer::after_millis(100).await;
|
||||||
|
|
||||||
let mut pfi = PassphraseInfo {
|
let mut pfi = PassphraseInfo {
|
||||||
len: passphrase.len() as _,
|
len: passphrase.len() as _,
|
||||||
@ -256,13 +266,13 @@ impl<'a> Control<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Temporarily set wifi down
|
// Temporarily set wifi down
|
||||||
self.ioctl(IoctlType::Set, IOCTL_CMD_DOWN, 0, &mut []).await;
|
self.down().await;
|
||||||
|
|
||||||
// Turn off APSTA mode
|
// Turn off APSTA mode
|
||||||
self.set_iovar_u32("apsta", 0).await;
|
self.set_iovar_u32("apsta", 0).await;
|
||||||
|
|
||||||
// Set wifi up again
|
// Set wifi up again
|
||||||
self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await;
|
self.up().await;
|
||||||
|
|
||||||
// Turn on AP mode
|
// Turn on AP mode
|
||||||
self.ioctl_set_u32(IOCTL_CMD_SET_AP, 0, 1).await;
|
self.ioctl_set_u32(IOCTL_CMD_SET_AP, 0, 1).await;
|
||||||
@ -287,7 +297,7 @@ impl<'a> Control<'a> {
|
|||||||
if security != Security::OPEN {
|
if security != Security::OPEN {
|
||||||
self.set_iovar_u32x2("bsscfg:wpa_auth", 0, 0x0084).await; // wpa_auth = WPA2_AUTH_PSK | WPA_AUTH_PSK
|
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;
|
Timer::after_millis(100).await;
|
||||||
|
|
||||||
// Set passphrase
|
// Set passphrase
|
||||||
let mut pfi = PassphraseInfo {
|
let mut pfi = PassphraseInfo {
|
||||||
@ -423,6 +433,11 @@ impl<'a> Control<'a> {
|
|||||||
events: &self.events,
|
events: &self.events,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Leave the wifi, with which we are currently associated.
|
||||||
|
pub async fn leave(&mut self) {
|
||||||
|
self.ioctl(IoctlType::Set, IOCTL_CMD_DISASSOC, 0, &mut []).await;
|
||||||
|
info!("Disassociated")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Scanner<'a> {
|
pub struct Scanner<'a> {
|
||||||
|
@ -83,14 +83,17 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
{
|
::core::unreachable!($($x)*)
|
||||||
#[cfg(not(feature = "defmt"))]
|
};
|
||||||
::core::unreachable!($($x)*);
|
}
|
||||||
#[cfg(feature = "defmt")]
|
|
||||||
::defmt::unreachable!($($x)*);
|
#[cfg(feature = "defmt")]
|
||||||
}
|
macro_rules! unreachable {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
::defmt::unreachable!($($x)*)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,7 +229,8 @@ impl<T, E> Try for Result<T, E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Bytes<'a>(pub &'a [u8]);
|
#[allow(unused)]
|
||||||
|
pub(crate) struct Bytes<'a>(pub &'a [u8]);
|
||||||
|
|
||||||
impl<'a> Debug for Bytes<'a> {
|
impl<'a> Debug for Bytes<'a> {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
@ -27,7 +27,7 @@ use ioctl::IoctlState;
|
|||||||
|
|
||||||
use crate::bus::Bus;
|
use crate::bus::Bus;
|
||||||
pub use crate::bus::SpiBusCyw43;
|
pub use crate::bus::SpiBusCyw43;
|
||||||
pub use crate::control::{Control, Error as ControlError};
|
pub use crate::control::{Control, Error as ControlError, Scanner};
|
||||||
pub use crate::runner::Runner;
|
pub use crate::runner::Runner;
|
||||||
pub use crate::structs::BssInfo;
|
pub use crate::structs::BssInfo;
|
||||||
|
|
||||||
|
@ -555,14 +555,14 @@ where
|
|||||||
|
|
||||||
self.bus.bp_write8(base + AI_RESETCTRL_OFFSET, 0).await;
|
self.bus.bp_write8(base + AI_RESETCTRL_OFFSET, 0).await;
|
||||||
|
|
||||||
Timer::after(Duration::from_millis(1)).await;
|
Timer::after_millis(1).await;
|
||||||
|
|
||||||
self.bus
|
self.bus
|
||||||
.bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_CLOCK_EN)
|
.bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_CLOCK_EN)
|
||||||
.await;
|
.await;
|
||||||
let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
|
let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
|
||||||
|
|
||||||
Timer::after(Duration::from_millis(1)).await;
|
Timer::after_millis(1).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn core_is_up(&mut self, core: Core) -> bool {
|
async fn core_is_up(&mut self, core: Core) -> bool {
|
||||||
|
@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-executor = { version = "0.3.0", path = "../../../../../embassy-executor", features = ["defmt", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
|
embassy-executor = { version = "0.3.0", path = "../../../../../embassy-executor", features = ["defmt", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
|
||||||
embassy-time = { version = "0.1.0", path = "../../../../../embassy-time", features = ["defmt", "nightly"] }
|
embassy-time = { version = "0.1.4", path = "../../../../../embassy-time", features = ["defmt", "nightly"] }
|
||||||
embassy-nrf = { version = "0.1.0", path = "../../../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "nightly"] }
|
embassy-nrf = { version = "0.1.0", path = "../../../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "nightly"] }
|
||||||
|
|
||||||
defmt = "0.3"
|
defmt = "0.3"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
* xref:getting_started.adoc[Getting started]
|
* xref:getting_started.adoc[Getting started]
|
||||||
** xref:basic_application.adoc[Basic application]
|
** xref:basic_application.adoc[Basic application]
|
||||||
** xref:layer_by_layer.adoc[Layer by Layer]
|
* xref:layer_by_layer.adoc[Bare metal to async]
|
||||||
* xref:runtime.adoc[Executor]
|
* xref:runtime.adoc[Executor]
|
||||||
* xref:hal.adoc[HAL]
|
* xref:hal.adoc[HAL]
|
||||||
** xref:nrf.adoc[nRF]
|
** xref:nrf.adoc[nRF]
|
||||||
@ -8,3 +8,5 @@
|
|||||||
* xref:bootloader.adoc[Bootloader]
|
* xref:bootloader.adoc[Bootloader]
|
||||||
|
|
||||||
* xref:examples.adoc[Examples]
|
* xref:examples.adoc[Examples]
|
||||||
|
* xref:developer.adoc[Developer]
|
||||||
|
** xref:developer_stm32.adoc[Developer: STM32]
|
||||||
|
@ -48,7 +48,7 @@ The `Spawner` is the way the main application spawns other tasks. The `Periphera
|
|||||||
include::example$basic/src/main.rs[lines="22..-1"]
|
include::example$basic/src/main.rs[lines="22..-1"]
|
||||||
----
|
----
|
||||||
|
|
||||||
What happens when the `blinker` task has been spawned and main returns? Well, the main entry point is actually just like any other task, except that you can only have one and it takes some specific type arguments. The magic lies within the `#[embassy::main]` macro. The macro does the following:
|
What happens when the `blinker` task has been spawned and main returns? Well, the main entry point is actually just like any other task, except that you can only have one and it takes some specific type arguments. The magic lies within the `#[embassy_executor::main]` macro. The macro does the following:
|
||||||
|
|
||||||
. Creates an Embassy Executor
|
. Creates an Embassy Executor
|
||||||
. Initializes the microcontroller HAL to get the `Peripherals`
|
. Initializes the microcontroller HAL to get the `Peripherals`
|
||||||
|
1
docs/modules/ROOT/pages/developer.adoc
Normal file
1
docs/modules/ROOT/pages/developer.adoc
Normal file
@ -0,0 +1 @@
|
|||||||
|
= Developer Documentation
|
79
docs/modules/ROOT/pages/developer_stm32.adoc
Normal file
79
docs/modules/ROOT/pages/developer_stm32.adoc
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
= Developer Documentation: STM32
|
||||||
|
|
||||||
|
== Understanding metapac
|
||||||
|
|
||||||
|
When a project that imports `embassy-stm32` is compiled, that project selects the feature corresponding to the chip that project is using. Based on that feature, `embassy-stm32` selects supported link:https://anysilicon.com/ip-intellectual-property-core-semiconductors/[IP] for the chip, and enables the corresponding HAL implementations. But how does `embassy-stm32` know what IP the chip contains, out of the hundreds of chips that we support? It's a long story that starts with `stm32-data-sources`.
|
||||||
|
|
||||||
|
== `stm32-data-sources`
|
||||||
|
|
||||||
|
link:https://github.com/embassy-rs/stm32-data-sources[`stm32-data-sources`] is as mostly barren repository. It has no README, no documentation, and few watchers. But it's the core of what makes `embassy-stm32` possible. The data for every chip that we support is taken in part from a corresponding XML file like link:https://github.com/embassy-rs/stm32-data-sources/blob/b8b85202e22a954d6c59d4a43d9795d34cff05cf/cubedb/mcu/STM32F051K4Ux.xml[`STM32F051K4Ux.xml`]. In that file, you'll see lines like the following:
|
||||||
|
|
||||||
|
[source,xml]
|
||||||
|
----
|
||||||
|
<IP InstanceName="I2C1" Name="I2C" Version="i2c2_v1_1_Cube"/>
|
||||||
|
<!-- snip -->
|
||||||
|
<IP ConfigFile="TIM-STM32F0xx" InstanceName="TIM1" Name="TIM1_8F0" Version="gptimer2_v2_x_Cube"/>
|
||||||
|
----
|
||||||
|
|
||||||
|
These lines indicate that this chip has an i2c, and that it's version is "v1_1". It also indicates that it has a general purpose timer that with a version of "v2_x". From this data, it's possible to determine which implementations should be included in `embassy-stm32`. But actually doing that is another matter.
|
||||||
|
|
||||||
|
|
||||||
|
== `stm32-data`
|
||||||
|
|
||||||
|
While all users of this project are familiar with `embassy-stm32`, fewer are familiar with the project that powers it: `stm32-data`. This project doesn't just aim to generate data for `embassy-stm32`, but for machine consumption in general. To acheive this, information from multiple files from the `stm32-data-sources` project are combined and parsed to assign register block implementations for each supported IP. The core of this matching resides in `chips.rs`:
|
||||||
|
|
||||||
|
[source,rust]
|
||||||
|
----
|
||||||
|
(".*:I2C:i2c2_v1_1", ("i2c", "v2", "I2C")),
|
||||||
|
// snip
|
||||||
|
(r".*TIM\d.*:gptimer.*", ("timer", "v1", "TIM_GP16")),
|
||||||
|
----
|
||||||
|
|
||||||
|
In this case, the i2c version corresponds to our "v2" and the general purpose timer version corresponds to our "v1". Therefore, the `i2c_v2.yaml` and `timer_v1.yaml` register block implementations are assigned to those IP, respectively. The result is that these lines arr generated in `STM32F051K4.json`:
|
||||||
|
|
||||||
|
[source,json]
|
||||||
|
----
|
||||||
|
{
|
||||||
|
"name": "I2C1",
|
||||||
|
"address": 1073763328,
|
||||||
|
"registers": {
|
||||||
|
"kind": "i2c",
|
||||||
|
"version": "v2",
|
||||||
|
"block": "I2C"
|
||||||
|
},
|
||||||
|
// snip
|
||||||
|
}
|
||||||
|
// snip
|
||||||
|
{
|
||||||
|
"name": "TIM1",
|
||||||
|
"address": 1073818624,
|
||||||
|
"registers": {
|
||||||
|
"kind": "timer",
|
||||||
|
"version": "v1",
|
||||||
|
"block": "TIM_ADV"
|
||||||
|
},
|
||||||
|
// snip
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
In addition to register blocks, data for pin and RCC mapping is also generated and consumed by `embassy-stm32`. `stm32-metapac-gen` is used to package and publish the data as a crate.
|
||||||
|
|
||||||
|
|
||||||
|
== `embassy-stm32`
|
||||||
|
|
||||||
|
In the `lib.rs` file located in the root of `embassy-stm32`, you'll see this line:
|
||||||
|
|
||||||
|
[source,rust]
|
||||||
|
----
|
||||||
|
#[cfg(i2c)]
|
||||||
|
pub mod i2c;
|
||||||
|
----
|
||||||
|
|
||||||
|
And in the `mod.rs` of the i2c mod, you'll see this:
|
||||||
|
|
||||||
|
[source,rust]
|
||||||
|
----
|
||||||
|
#[cfg_attr(i2c_v2, path = "v2.rs")]
|
||||||
|
----
|
||||||
|
|
||||||
|
Because i2c is supported for STM32F051K4 and its version corresponds to our "v2", the `i2c` and `i2c_v2`, configuration directives will be present, and `embassy-stm32` will include these files, respectively. This and other configuration directives and tables are generated from the data for chip, allowing `embassy-stm32` to expressively and clearly adapt logic and implementations to what is required for each chip. Compared to other projects across the embedded ecosystem, `embassy-stm32` is the only project that can re-use code across the entire stm32 lineup and remove difficult-to-implement unsafe logic to the HAL.
|
@ -3,7 +3,7 @@
|
|||||||
So you want to try Embassy, great! To get started, there are a few tools you need to install:
|
So you want to try Embassy, great! To get started, there are a few tools you need to install:
|
||||||
|
|
||||||
* link:https://rustup.rs/[rustup] - the Rust toolchain is needed to compile Rust code.
|
* link:https://rustup.rs/[rustup] - the Rust toolchain is needed to compile Rust code.
|
||||||
* link:https://crates.io/crates/probe-run[probe-run] - to flash the firmware on your device. If you already have other tools like `OpenOCD` setup, you can use that as well.
|
* link:https://crates.io/crates/probe-rs[probe-rs] - to flash the firmware on your device. If you already have other tools like `OpenOCD` setup, you can use that as well.
|
||||||
|
|
||||||
If you don't have any supported board, don't worry: you can also run embassy on your PC using the `std` examples.
|
If you don't have any supported board, don't worry: you can also run embassy on your PC using the `std` examples.
|
||||||
|
|
||||||
@ -30,6 +30,10 @@ Embassy supports many microcontroller families, but the easiest ways to get star
|
|||||||
|
|
||||||
* link:https://www.raspberrypi.com/products/raspberry-pi-pico/[Raspberry Pi Pico]
|
* link:https://www.raspberrypi.com/products/raspberry-pi-pico/[Raspberry Pi Pico]
|
||||||
|
|
||||||
|
=== ESP32
|
||||||
|
|
||||||
|
* link:https://github.com/esp-rs/esp-rust-board[ESP32C3]
|
||||||
|
|
||||||
== Running an example
|
== Running an example
|
||||||
|
|
||||||
First you need to clone the [github repository];
|
First you need to clone the [github repository];
|
||||||
@ -38,7 +42,6 @@ First you need to clone the [github repository];
|
|||||||
----
|
----
|
||||||
git clone https://github.com/embassy-rs/embassy.git
|
git clone https://github.com/embassy-rs/embassy.git
|
||||||
cd embassy
|
cd embassy
|
||||||
git submodule update --init
|
|
||||||
----
|
----
|
||||||
|
|
||||||
You can run an example by opening a terminal and entering the following commands:
|
You can run an example by opening a terminal and entering the following commands:
|
||||||
|
@ -7,4 +7,6 @@ Embassy provides HALs for several microcontroller families:
|
|||||||
* `embassy-rp` for the Raspberry Pi RP2040 microcontrollers
|
* `embassy-rp` for the Raspberry Pi RP2040 microcontrollers
|
||||||
|
|
||||||
These HALs implement async/await functionality for most peripherals while also implementing the
|
These HALs implement async/await functionality for most peripherals while also implementing the
|
||||||
async traits in `embedded-hal-async`. You can also use these HALs with another executor.
|
async traits in `embedded-hal` and `embedded-hal-async`. You can also use these HALs with another executor.
|
||||||
|
|
||||||
|
For the ESP32 series, there is an link:https://github.com/esp-rs/esp-hal[esp-hal] which you can use.
|
||||||
|
@ -4,14 +4,9 @@ Embassy is a project to make async/await a first-class option for embedded devel
|
|||||||
|
|
||||||
== What is async?
|
== What is async?
|
||||||
|
|
||||||
Software written without async may block on I/O operations. In an std environment, such as a PC, software can handle this either by using threads or non-blocking operations.
|
When handling I/O, software must call functions that block program execution until the I/O operation completes. When running inside of an OS such as Linux, such functions generally transfer control to the kernel so that another task, known as a thread, can be executed if available, or the CPU can be put to sleep until another such task is ready to perform more work. Because an OS cannot presume that threads will behave cooperatively, threads are relatively resource-intensive, and may be forcibly interrupted they do not transfer control back to the kernel within an allotted time. But if tasks could be presumed to behave cooperatively, or at least not maliciously, it would be possible to create tasks that appear to be almost free when compared to a traditional OS thread. In Rust, these lightweight tasks, known as 'coroutines' or 'goroutines' in other languages, are implemented with async.
|
||||||
|
|
||||||
With threads, one thread blocks on an I/O operation, another is able to take its place. However, even on a PC, threads are relatively heavy, and therefore some programming languages, such as Go, have implemented a concept called coroutines or 'goroutines' that are much lighter and less-intensive than threads.
|
Async-await works by transforming each async function into an object called a future. When a future blocks on I/O the future yields, and the scheduler, called an executor, can select a different future to execute. Compared to alternatives such as an RTOS, async can yield better performance and lower power consumption because the executor doesn't have to guess when a future is ready to execute. However, program size may be higher than other alternatives, which may be a problem for certain space-constrained devices with very low memory. On the devices Embassy supports, such as stm32 and nrf, memory is generally large enough to accommodate the modestly-increased program size.
|
||||||
|
|
||||||
The other way to handle blocking I/O operations is to support polling the state of the underlying peripherals to check whether it is available to perform the requested operation. In programming languages without builtin async support,
|
|
||||||
this requires building a complex loop checking for events.
|
|
||||||
|
|
||||||
In Rust, non-blocking operations can be implemented using async-await. Async-await works by transforming each async function into an object called a future. When a future blocks on I/O the future yields, and the scheduler, called an executor, can select a different future to execute. Compared to alternatives such as an RTOS, async can yield better performance and lower power consumption because the executor doesn't have to guess when a future is ready to execute. However, program size may be higher than other alternatives, which may be a problem for certain space-constrained devices with very low memory. On the devices Embassy supports, such as stm32 and nrf, memory is generally large enough to accommodate the modestly-increased program size.
|
|
||||||
|
|
||||||
== What is Embassy?
|
== What is Embassy?
|
||||||
|
|
||||||
@ -22,13 +17,26 @@ The Embassy project consists of several crates that you can use together or inde
|
|||||||
* **Hardware Abstraction Layers** - HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy.
|
* **Hardware Abstraction Layers** - HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy.
|
||||||
** link:https://docs.embassy.dev/embassy-stm32/[embassy-stm32], for all STM32 microcontroller families.
|
** link:https://docs.embassy.dev/embassy-stm32/[embassy-stm32], for all STM32 microcontroller families.
|
||||||
** link:https://docs.embassy.dev/embassy-nrf/[embassy-nrf], for the Nordic Semiconductor nRF52, nRF53, nRF91 series.
|
** link:https://docs.embassy.dev/embassy-nrf/[embassy-nrf], for the Nordic Semiconductor nRF52, nRF53, nRF91 series.
|
||||||
|
** link:https://docs.embassy.dev/embassy-rp/[embassy-rp], for the Raspberry Pi RP2040 microcontroller.
|
||||||
|
** link:https://github.com/esp-rs[esp-rs], for the Espressif Systems ESP32 series of chips.
|
||||||
|
+
|
||||||
|
NOTE: A common question is if one can use the Embassy HALs standalone. Yes, it is possible! There are no dependency on the executor within the HALs. You can even use them without async,
|
||||||
|
as they implement both the link:https://github.com/rust-embedded/embedded-hal[Embedded HAL] blocking and async traits.
|
||||||
|
|
||||||
* **Networking** - The link:https://docs.embassy.dev/embassy-net/[embassy-net] network stack implements extensive networking functionality, including Ethernet, IP, TCP, UDP, ICMP and DHCP. Async drastically simplifies managing timeouts and serving multiple connections concurrently.
|
* **Networking** - The link:https://docs.embassy.dev/embassy-net/[embassy-net] network stack implements extensive networking functionality, including Ethernet, IP, TCP, UDP, ICMP and DHCP. Async drastically simplifies managing timeouts and serving multiple connections concurrently. Several drivers for WiFi and Ethernet chips can be found.
|
||||||
|
|
||||||
* **Bluetooth** - The link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers.
|
* **Bluetooth** - The link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers.
|
||||||
|
|
||||||
* **LoRa** - link:https://docs.embassy.dev/embassy-lora/[embassy-lora] supports LoRa networking on STM32WL wireless microcontrollers and Semtech SX127x transceivers.
|
* **LoRa** - link:https://github.com/embassy-rs/lora-phy[lora-phy] and link:https://docs.embassy.dev/embassy-lora/[embassy-lora] supports LoRa networking on a wide range of LoRa radios, fully integrated with a Rust link:https://github.com/ivajloip/rust-lorawan[LoRaWAN] implementation.
|
||||||
|
|
||||||
* **USB** - link:https://docs.embassy.dev/embassy-usb/[embassy-usb] implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own.
|
* **USB** - link:https://docs.embassy.dev/embassy-usb/[embassy-usb] implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own.
|
||||||
|
|
||||||
* **Bootloader and DFU** - link:https://github.com/embassy-rs/embassy/tree/master/embassy-boot[embassy-boot] is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks.
|
* **Bootloader and DFU** - link:https://github.com/embassy-rs/embassy/tree/master/embassy-boot[embassy-boot] is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks.
|
||||||
|
|
||||||
|
== Resources
|
||||||
|
|
||||||
|
For more reading material on async Rust and Embassy:
|
||||||
|
|
||||||
|
* link:https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown[Comparsion of FreeRTOS and Embassy]
|
||||||
|
* link:https://dev.to/apollolabsbin/series/20707[Tutorials]
|
||||||
|
* link:https://blog.drogue.io/firmware-updates-part-1/[Firmware Updates with Embassy]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
= Embassy layer by layer
|
= From bare metal to async Rust
|
||||||
|
|
||||||
If you're new to Embassy, it can be overwhelming to grasp all the terminology and concepts. This guide aims to clarify the different layers in Embassy, which problem each layer solves for the application writer.
|
If you're new to Embassy, it can be overwhelming to grasp all the terminology and concepts. This guide aims to clarify the different layers in Embassy, which problem each layer solves for the application writer.
|
||||||
|
|
||||||
@ -8,8 +8,7 @@ The application we'll write is a simple 'push button, blink led' application, wh
|
|||||||
|
|
||||||
== PAC version
|
== PAC version
|
||||||
|
|
||||||
The PAC is the lowest API for accessing peripherals and registers, if you don't count reading/writing directly to memory addresses. It provides distinct types
|
The PAC is the lowest API for accessing peripherals and registers, if you don't count reading/writing directly to memory addresses. It provides distinct types to make accessing peripheral registers easier, but it does not prevent you from writing unsafe code.
|
||||||
to make accessing peripheral registers easier, but it does not prevent you from writing unsafe code.
|
|
||||||
|
|
||||||
Writing an application using the PAC directly is therefore not recommended, but if the functionality you want to use is not exposed in the upper layers, that's what you need to use.
|
Writing an application using the PAC directly is therefore not recommended, but if the functionality you want to use is not exposed in the upper layers, that's what you need to use.
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ The nRF timer driver operates at 32768 Hz by default.
|
|||||||
|
|
||||||
== Peripherals
|
== Peripherals
|
||||||
|
|
||||||
The following peripherals have a HAL implementation at present:
|
The following peripherals have a HAL implementation at present
|
||||||
|
|
||||||
* PWM
|
* PWM
|
||||||
* SPIM
|
* SPIM
|
||||||
@ -23,3 +23,7 @@ The following peripherals have a HAL implementation at present:
|
|||||||
* UARTE
|
* UARTE
|
||||||
* TWIM
|
* TWIM
|
||||||
* SAADC
|
* SAADC
|
||||||
|
|
||||||
|
== Bluetooth
|
||||||
|
|
||||||
|
For bluetooth, you can use the link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] crate.
|
||||||
|
@ -6,11 +6,11 @@ The Embassy executor is an async/await executor designed for embedded usage alon
|
|||||||
|
|
||||||
* No `alloc`, no heap needed. Task are statically allocated.
|
* No `alloc`, no heap needed. Task are statically allocated.
|
||||||
* No "fixed capacity" data structures, executor works with 1 or 1000 tasks without needing config/tuning.
|
* No "fixed capacity" data structures, executor works with 1 or 1000 tasks without needing config/tuning.
|
||||||
* Integrated timer queue: sleeping is easy, just do `Timer::after(Duration::from_secs(1)).await;`.
|
* Integrated timer queue: sleeping is easy, just do `Timer::after_secs(1).await;`.
|
||||||
* No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`.
|
* No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`.
|
||||||
* Efficient polling: a wake will only poll the woken task, not all of them.
|
* Efficient polling: a wake will only poll the woken task, not all of them.
|
||||||
* Fair: a task can't monopolize CPU time even if it's constantly being woken. All other tasks get a chance to run before a given task gets polled for the second time.
|
* Fair: a task can't monopolize CPU time even if it's constantly being woken. All other tasks get a chance to run before a given task gets polled for the second time.
|
||||||
* Creating multiple executor instances is supported, to run tasks with multiple priority levels. This allows higher-priority tasks to preempt lower-priority tasks.
|
* Creating multiple executor instances is supported, to run tasks at different priority levels. This allows higher-priority tasks to preempt lower-priority tasks.
|
||||||
|
|
||||||
== Executor
|
== Executor
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ digest = "0.10"
|
|||||||
log = { version = "0.4", optional = true }
|
log = { version = "0.4", optional = true }
|
||||||
ed25519-dalek = { version = "1.0.1", default_features = false, features = ["u32_backend"], optional = true }
|
ed25519-dalek = { version = "1.0.1", default_features = false, features = ["u32_backend"], optional = true }
|
||||||
embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
|
embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
|
||||||
embassy-sync = { version = "0.2.0", path = "../../embassy-sync" }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync" }
|
||||||
embedded-storage = "0.3.0"
|
embedded-storage = "0.3.0"
|
||||||
embedded-storage-async = { version = "0.4.0", optional = true }
|
embedded-storage-async = { version = "0.4.0", optional = true }
|
||||||
salty = { git = "https://github.com/ycrypto/salty.git", rev = "a9f17911a5024698406b75c0fac56ab5ccf6a8c7", optional = true }
|
salty = { git = "https://github.com/ycrypto/salty.git", rev = "a9f17911a5024698406b75c0fac56ab5ccf6a8c7", optional = true }
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
#![allow(unused_macros)]
|
#![allow(unused_macros)]
|
||||||
|
|
||||||
|
use core::fmt::{Debug, Display, LowerHex};
|
||||||
|
|
||||||
#[cfg(all(feature = "defmt", feature = "log"))]
|
#[cfg(all(feature = "defmt", feature = "log"))]
|
||||||
compile_error!("You may not enable both `defmt` and `log` features.");
|
compile_error!("You may not enable both `defmt` and `log` features.");
|
||||||
|
|
||||||
@ -81,14 +83,17 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
{
|
::core::unreachable!($($x)*)
|
||||||
#[cfg(not(feature = "defmt"))]
|
};
|
||||||
::core::unreachable!($($x)*);
|
}
|
||||||
#[cfg(feature = "defmt")]
|
|
||||||
::defmt::unreachable!($($x)*);
|
#[cfg(feature = "defmt")]
|
||||||
}
|
macro_rules! unreachable {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
::defmt::unreachable!($($x)*)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub(crate) 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -16,7 +16,7 @@ target = "thumbv7em-none-eabi"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
|
|
||||||
embassy-sync = { path = "../../embassy-sync" }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync" }
|
||||||
embassy-nrf = { path = "../../embassy-nrf" }
|
embassy-nrf = { path = "../../embassy-nrf" }
|
||||||
embassy-boot = { path = "../boot", default-features = false }
|
embassy-boot = { path = "../boot", default-features = false }
|
||||||
cortex-m = { version = "0.7.6" }
|
cortex-m = { version = "0.7.6" }
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
#![allow(unused_macros)]
|
#![allow(unused_macros)]
|
||||||
|
|
||||||
|
use core::fmt::{Debug, Display, LowerHex};
|
||||||
|
|
||||||
#[cfg(all(feature = "defmt", feature = "log"))]
|
#[cfg(all(feature = "defmt", feature = "log"))]
|
||||||
compile_error!("You may not enable both `defmt` and `log` features.");
|
compile_error!("You may not enable both `defmt` and `log` features.");
|
||||||
|
|
||||||
@ -81,14 +83,17 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
{
|
::core::unreachable!($($x)*)
|
||||||
#[cfg(not(feature = "defmt"))]
|
};
|
||||||
::core::unreachable!($($x)*);
|
}
|
||||||
#[cfg(feature = "defmt")]
|
|
||||||
::defmt::unreachable!($($x)*);
|
#[cfg(feature = "defmt")]
|
||||||
}
|
macro_rules! unreachable {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
::defmt::unreachable!($($x)*)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub(crate) 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -17,7 +17,7 @@ defmt = { version = "0.3", optional = true }
|
|||||||
defmt-rtt = { version = "0.4", optional = true }
|
defmt-rtt = { version = "0.4", optional = true }
|
||||||
log = { version = "0.4", optional = true }
|
log = { version = "0.4", optional = true }
|
||||||
|
|
||||||
embassy-sync = { path = "../../embassy-sync" }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync" }
|
||||||
embassy-rp = { path = "../../embassy-rp", default-features = false }
|
embassy-rp = { path = "../../embassy-rp", default-features = false }
|
||||||
embassy-boot = { path = "../boot", default-features = false }
|
embassy-boot = { path = "../boot", default-features = false }
|
||||||
embassy-time = { path = "../../embassy-time" }
|
embassy-time = { path = "../../embassy-time" }
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
#![allow(unused_macros)]
|
#![allow(unused_macros)]
|
||||||
|
|
||||||
|
use core::fmt::{Debug, Display, LowerHex};
|
||||||
|
|
||||||
#[cfg(all(feature = "defmt", feature = "log"))]
|
#[cfg(all(feature = "defmt", feature = "log"))]
|
||||||
compile_error!("You may not enable both `defmt` and `log` features.");
|
compile_error!("You may not enable both `defmt` and `log` features.");
|
||||||
|
|
||||||
@ -81,14 +83,17 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
{
|
::core::unreachable!($($x)*)
|
||||||
#[cfg(not(feature = "defmt"))]
|
};
|
||||||
::core::unreachable!($($x)*);
|
}
|
||||||
#[cfg(feature = "defmt")]
|
|
||||||
::defmt::unreachable!($($x)*);
|
#[cfg(feature = "defmt")]
|
||||||
}
|
macro_rules! unreachable {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
::defmt::unreachable!($($x)*)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub(crate) 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -18,7 +18,7 @@ defmt = { version = "0.3", optional = true }
|
|||||||
defmt-rtt = { version = "0.4", optional = true }
|
defmt-rtt = { version = "0.4", optional = true }
|
||||||
log = { version = "0.4", optional = true }
|
log = { version = "0.4", optional = true }
|
||||||
|
|
||||||
embassy-sync = { path = "../../embassy-sync" }
|
embassy-sync = { version = "0.4.0", path = "../../embassy-sync" }
|
||||||
embassy-stm32 = { path = "../../embassy-stm32", default-features = false }
|
embassy-stm32 = { path = "../../embassy-stm32", default-features = false }
|
||||||
embassy-boot = { path = "../boot", default-features = false }
|
embassy-boot = { path = "../boot", default-features = false }
|
||||||
cortex-m = { version = "0.7.6" }
|
cortex-m = { version = "0.7.6" }
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
#![allow(unused_macros)]
|
#![allow(unused_macros)]
|
||||||
|
|
||||||
|
use core::fmt::{Debug, Display, LowerHex};
|
||||||
|
|
||||||
#[cfg(all(feature = "defmt", feature = "log"))]
|
#[cfg(all(feature = "defmt", feature = "log"))]
|
||||||
compile_error!("You may not enable both `defmt` and `log` features.");
|
compile_error!("You may not enable both `defmt` and `log` features.");
|
||||||
|
|
||||||
@ -81,14 +83,17 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
{
|
::core::unreachable!($($x)*)
|
||||||
#[cfg(not(feature = "defmt"))]
|
};
|
||||||
::core::unreachable!($($x)*);
|
}
|
||||||
#[cfg(feature = "defmt")]
|
|
||||||
::defmt::unreachable!($($x)*);
|
#[cfg(feature = "defmt")]
|
||||||
}
|
macro_rules! unreachable {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
::defmt::unreachable!($($x)*)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub(crate) 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -20,8 +20,8 @@ default = ["time"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures", optional = true }
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures", optional = true }
|
||||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.4.0", path = "../embassy-sync" }
|
||||||
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
|
embassy-time = { version = "0.1.5", path = "../embassy-time", optional = true }
|
||||||
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [
|
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [
|
||||||
"unproven",
|
"unproven",
|
||||||
] }
|
] }
|
||||||
|
@ -11,7 +11,7 @@ pub use asynch::Partition;
|
|||||||
pub use blocking::BlockingPartition;
|
pub use blocking::BlockingPartition;
|
||||||
|
|
||||||
/// Partition error
|
/// Partition error
|
||||||
#[derive(Debug)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum Error<T> {
|
pub enum Error<T> {
|
||||||
/// The requested flash area is outside the partition
|
/// The requested flash area is outside the partition
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections, try_blocks))]
|
#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections, try_blocks))]
|
||||||
|
#![cfg_attr(feature = "nightly", allow(stable_features, unknown_lints, async_fn_in_trait))]
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
//! Utilities to use `embedded-hal` traits with Embassy.
|
//! Utilities to use `embedded-hal` traits with Embassy.
|
||||||
@ -26,6 +27,18 @@ pub trait SetConfig {
|
|||||||
/// The configuration type used by this driver.
|
/// The configuration type used by this driver.
|
||||||
type Config;
|
type Config;
|
||||||
|
|
||||||
|
/// The error type that can occur if `set_config` fails.
|
||||||
|
type ConfigError;
|
||||||
|
|
||||||
/// Set the configuration of the driver.
|
/// Set the configuration of the driver.
|
||||||
fn set_config(&mut self, config: &Self::Config);
|
fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the configuration of a peripheral driver.
|
||||||
|
pub trait GetConfig {
|
||||||
|
/// The configuration type used by this driver.
|
||||||
|
type Config;
|
||||||
|
|
||||||
|
/// Get the configuration of the driver.
|
||||||
|
fn get_config(&self) -> Self::Config;
|
||||||
}
|
}
|
||||||
|
@ -125,14 +125,14 @@ where
|
|||||||
{
|
{
|
||||||
async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), I2cDeviceError<BUS::Error>> {
|
async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), I2cDeviceError<BUS::Error>> {
|
||||||
let mut bus = self.bus.lock().await;
|
let mut bus = self.bus.lock().await;
|
||||||
bus.set_config(&self.config);
|
bus.set_config(&self.config).map_err(|_| I2cDeviceError::Config)?;
|
||||||
bus.read(address, buffer).await.map_err(I2cDeviceError::I2c)?;
|
bus.read(address, buffer).await.map_err(I2cDeviceError::I2c)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), I2cDeviceError<BUS::Error>> {
|
async fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), I2cDeviceError<BUS::Error>> {
|
||||||
let mut bus = self.bus.lock().await;
|
let mut bus = self.bus.lock().await;
|
||||||
bus.set_config(&self.config);
|
bus.set_config(&self.config).map_err(|_| I2cDeviceError::Config)?;
|
||||||
bus.write(address, bytes).await.map_err(I2cDeviceError::I2c)?;
|
bus.write(address, bytes).await.map_err(I2cDeviceError::I2c)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -144,7 +144,7 @@ where
|
|||||||
rd_buffer: &mut [u8],
|
rd_buffer: &mut [u8],
|
||||||
) -> Result<(), I2cDeviceError<BUS::Error>> {
|
) -> Result<(), I2cDeviceError<BUS::Error>> {
|
||||||
let mut bus = self.bus.lock().await;
|
let mut bus = self.bus.lock().await;
|
||||||
bus.set_config(&self.config);
|
bus.set_config(&self.config).map_err(|_| I2cDeviceError::Config)?;
|
||||||
bus.write_read(address, wr_buffer, rd_buffer)
|
bus.write_read(address, wr_buffer, rd_buffer)
|
||||||
.await
|
.await
|
||||||
.map_err(I2cDeviceError::I2c)?;
|
.map_err(I2cDeviceError::I2c)?;
|
||||||
@ -153,7 +153,7 @@ where
|
|||||||
|
|
||||||
async fn transaction(&mut self, address: u8, operations: &mut [i2c::Operation<'_>]) -> Result<(), Self::Error> {
|
async fn transaction(&mut self, address: u8, operations: &mut [i2c::Operation<'_>]) -> Result<(), Self::Error> {
|
||||||
let mut bus = self.bus.lock().await;
|
let mut bus = self.bus.lock().await;
|
||||||
bus.set_config(&self.config);
|
bus.set_config(&self.config).map_err(|_| I2cDeviceError::Config)?;
|
||||||
bus.transaction(address, operations)
|
bus.transaction(address, operations)
|
||||||
.await
|
.await
|
||||||
.map_err(I2cDeviceError::I2c)?;
|
.map_err(I2cDeviceError::I2c)?;
|
||||||
|
@ -76,9 +76,7 @@ where
|
|||||||
#[cfg(not(feature = "time"))]
|
#[cfg(not(feature = "time"))]
|
||||||
Operation::DelayUs(_) => return Err(SpiDeviceError::DelayUsNotSupported),
|
Operation::DelayUs(_) => return Err(SpiDeviceError::DelayUsNotSupported),
|
||||||
#[cfg(feature = "time")]
|
#[cfg(feature = "time")]
|
||||||
Operation::DelayUs(us) => {
|
Operation::DelayUs(us) => embassy_time::Timer::after_micros(*us as _).await,
|
||||||
embassy_time::Timer::after(embassy_time::Duration::from_micros(*us as _)).await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -130,7 +128,7 @@ where
|
|||||||
{
|
{
|
||||||
async fn transaction(&mut self, operations: &mut [spi::Operation<'_, u8>]) -> Result<(), Self::Error> {
|
async fn transaction(&mut self, operations: &mut [spi::Operation<'_, u8>]) -> Result<(), Self::Error> {
|
||||||
let mut bus = self.bus.lock().await;
|
let mut bus = self.bus.lock().await;
|
||||||
bus.set_config(&self.config);
|
bus.set_config(&self.config).map_err(|_| SpiDeviceError::Config)?;
|
||||||
self.cs.set_low().map_err(SpiDeviceError::Cs)?;
|
self.cs.set_low().map_err(SpiDeviceError::Cs)?;
|
||||||
|
|
||||||
let op_res: Result<(), BUS::Error> = try {
|
let op_res: Result<(), BUS::Error> = try {
|
||||||
@ -143,9 +141,7 @@ where
|
|||||||
#[cfg(not(feature = "time"))]
|
#[cfg(not(feature = "time"))]
|
||||||
Operation::DelayUs(_) => return Err(SpiDeviceError::DelayUsNotSupported),
|
Operation::DelayUs(_) => return Err(SpiDeviceError::DelayUsNotSupported),
|
||||||
#[cfg(feature = "time")]
|
#[cfg(feature = "time")]
|
||||||
Operation::DelayUs(us) => {
|
Operation::DelayUs(us) => embassy_time::Timer::after_micros(*us as _).await,
|
||||||
embassy_time::Timer::after(embassy_time::Duration::from_micros(*us as _)).await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -148,7 +148,7 @@ where
|
|||||||
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
|
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
|
||||||
self.bus.lock(|bus| {
|
self.bus.lock(|bus| {
|
||||||
let mut bus = bus.borrow_mut();
|
let mut bus = bus.borrow_mut();
|
||||||
bus.set_config(&self.config);
|
bus.set_config(&self.config).map_err(|_| I2cDeviceError::Config)?;
|
||||||
bus.read(address, buffer).map_err(I2cDeviceError::I2c)
|
bus.read(address, buffer).map_err(I2cDeviceError::I2c)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -156,7 +156,7 @@ where
|
|||||||
fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> {
|
fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> {
|
||||||
self.bus.lock(|bus| {
|
self.bus.lock(|bus| {
|
||||||
let mut bus = bus.borrow_mut();
|
let mut bus = bus.borrow_mut();
|
||||||
bus.set_config(&self.config);
|
bus.set_config(&self.config).map_err(|_| I2cDeviceError::Config)?;
|
||||||
bus.write(address, bytes).map_err(I2cDeviceError::I2c)
|
bus.write(address, bytes).map_err(I2cDeviceError::I2c)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -164,7 +164,7 @@ where
|
|||||||
fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> {
|
fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> {
|
||||||
self.bus.lock(|bus| {
|
self.bus.lock(|bus| {
|
||||||
let mut bus = bus.borrow_mut();
|
let mut bus = bus.borrow_mut();
|
||||||
bus.set_config(&self.config);
|
bus.set_config(&self.config).map_err(|_| I2cDeviceError::Config)?;
|
||||||
bus.write_read(address, wr_buffer, rd_buffer)
|
bus.write_read(address, wr_buffer, rd_buffer)
|
||||||
.map_err(I2cDeviceError::I2c)
|
.map_err(I2cDeviceError::I2c)
|
||||||
})
|
})
|
||||||
|
@ -163,7 +163,7 @@ where
|
|||||||
fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), Self::Error> {
|
fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), Self::Error> {
|
||||||
self.bus.lock(|bus| {
|
self.bus.lock(|bus| {
|
||||||
let mut bus = bus.borrow_mut();
|
let mut bus = bus.borrow_mut();
|
||||||
bus.set_config(&self.config);
|
bus.set_config(&self.config).map_err(|_| SpiDeviceError::Config)?;
|
||||||
self.cs.set_low().map_err(SpiDeviceError::Cs)?;
|
self.cs.set_low().map_err(SpiDeviceError::Cs)?;
|
||||||
|
|
||||||
let op_res = operations.iter_mut().try_for_each(|op| match op {
|
let op_res = operations.iter_mut().try_for_each(|op| match op {
|
||||||
|
@ -14,6 +14,8 @@ pub mod blocking;
|
|||||||
pub enum I2cDeviceError<BUS> {
|
pub enum I2cDeviceError<BUS> {
|
||||||
/// An operation on the inner I2C bus failed.
|
/// An operation on the inner I2C bus failed.
|
||||||
I2c(BUS),
|
I2c(BUS),
|
||||||
|
/// Configuration of the inner I2C bus failed.
|
||||||
|
Config,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<BUS> i2c::Error for I2cDeviceError<BUS>
|
impl<BUS> i2c::Error for I2cDeviceError<BUS>
|
||||||
@ -23,6 +25,7 @@ where
|
|||||||
fn kind(&self) -> i2c::ErrorKind {
|
fn kind(&self) -> i2c::ErrorKind {
|
||||||
match self {
|
match self {
|
||||||
Self::I2c(e) => e.kind(),
|
Self::I2c(e) => e.kind(),
|
||||||
|
Self::Config => i2c::ErrorKind::Other,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -38,6 +41,8 @@ pub enum SpiDeviceError<BUS, CS> {
|
|||||||
Cs(CS),
|
Cs(CS),
|
||||||
/// DelayUs operations are not supported when the `time` Cargo feature is not enabled.
|
/// DelayUs operations are not supported when the `time` Cargo feature is not enabled.
|
||||||
DelayUsNotSupported,
|
DelayUsNotSupported,
|
||||||
|
/// The SPI bus could not be configured.
|
||||||
|
Config,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<BUS, CS> spi::Error for SpiDeviceError<BUS, CS>
|
impl<BUS, CS> spi::Error for SpiDeviceError<BUS, CS>
|
||||||
@ -50,6 +55,7 @@ where
|
|||||||
Self::Spi(e) => e.kind(),
|
Self::Spi(e) => e.kind(),
|
||||||
Self::Cs(_) => spi::ErrorKind::Other,
|
Self::Cs(_) => spi::ErrorKind::Other,
|
||||||
Self::DelayUsNotSupported => spi::ErrorKind::Other,
|
Self::DelayUsNotSupported => spi::ErrorKind::Other,
|
||||||
|
Self::Config => spi::ErrorKind::Other,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## 0.3.1 - 2023-11-01
|
||||||
|
|
||||||
|
- Fix spurious "Found waker not created by the Embassy executor" error in recent nightlies.
|
||||||
|
|
||||||
## 0.3.0 - 2023-08-25
|
## 0.3.0 - 2023-08-25
|
||||||
|
|
||||||
- Replaced Pender. Implementations now must define an extern function called `__pender`.
|
- Replaced Pender. Implementations now must define an extern function called `__pender`.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "embassy-executor"
|
name = "embassy-executor"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "async/await executor designed for embedded usage"
|
description = "async/await executor designed for embedded usage"
|
||||||
@ -59,7 +59,7 @@ rtos-trace = { version = "0.1.2", optional = true }
|
|||||||
|
|
||||||
futures-util = { version = "0.3.17", default-features = false }
|
futures-util = { version = "0.3.17", default-features = false }
|
||||||
embassy-macros = { version = "0.2.1", path = "../embassy-macros" }
|
embassy-macros = { version = "0.2.1", path = "../embassy-macros" }
|
||||||
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true}
|
embassy-time = { version = "0.1.5", path = "../embassy-time", optional = true}
|
||||||
atomic-polyfill = "1.0.1"
|
atomic-polyfill = "1.0.1"
|
||||||
critical-section = "1.1"
|
critical-section = "1.1"
|
||||||
static_cell = "1.1"
|
static_cell = "1.1"
|
||||||
|
@ -4,7 +4,7 @@ An async/await executor designed for embedded usage.
|
|||||||
|
|
||||||
- No `alloc`, no heap needed. Task futures are statically allocated.
|
- No `alloc`, no heap needed. Task futures are statically allocated.
|
||||||
- No "fixed capacity" data structures, executor works with 1 or 1000 tasks without needing config/tuning.
|
- No "fixed capacity" data structures, executor works with 1 or 1000 tasks without needing config/tuning.
|
||||||
- Integrated timer queue: sleeping is easy, just do `Timer::after(Duration::from_secs(1)).await;`.
|
- Integrated timer queue: sleeping is easy, just do `Timer::after_secs(1).await;`.
|
||||||
- No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`.
|
- No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`.
|
||||||
- Efficient polling: a wake will only poll the woken task, not all of them.
|
- Efficient polling: a wake will only poll the woken task, not all of them.
|
||||||
- Fair: a task can't monopolize CPU time even if it's constantly being woken. All other tasks get a chance to run before a given task gets polled for the second time.
|
- Fair: a task can't monopolize CPU time even if it's constantly being woken. All other tasks get a chance to run before a given task gets polled for the second time.
|
||||||
|
@ -73,9 +73,10 @@ mod thread {
|
|||||||
pub fn start(&'static mut self, init: impl FnOnce(Spawner)) {
|
pub fn start(&'static mut self, init: impl FnOnce(Spawner)) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let executor = &self.inner;
|
let executor = &self.inner;
|
||||||
self.ctx.closure.write(Closure::new(move |_| {
|
let future = Closure::new(move |_| {
|
||||||
executor.poll();
|
executor.poll();
|
||||||
}));
|
});
|
||||||
|
self.ctx.closure.write_in_place(|| future);
|
||||||
init(self.inner.spawner());
|
init(self.inner.spawner());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
#![allow(unused_macros)]
|
#![allow(unused_macros)]
|
||||||
|
|
||||||
|
use core::fmt::{Debug, Display, LowerHex};
|
||||||
|
|
||||||
#[cfg(all(feature = "defmt", feature = "log"))]
|
#[cfg(all(feature = "defmt", feature = "log"))]
|
||||||
compile_error!("You may not enable both `defmt` and `log` features.");
|
compile_error!("You may not enable both `defmt` and `log` features.");
|
||||||
|
|
||||||
@ -81,14 +83,17 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
{
|
::core::unreachable!($($x)*)
|
||||||
#[cfg(not(feature = "defmt"))]
|
};
|
||||||
::core::unreachable!($($x)*);
|
}
|
||||||
#[cfg(feature = "defmt")]
|
|
||||||
::defmt::unreachable!($($x)*);
|
#[cfg(feature = "defmt")]
|
||||||
}
|
macro_rules! unreachable {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
::defmt::unreachable!($($x)*)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub(crate) 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -203,7 +203,7 @@ impl<F: Future + 'static> AvailableTask<F> {
|
|||||||
fn initialize_impl<S>(self, future: impl FnOnce() -> F) -> SpawnToken<S> {
|
fn initialize_impl<S>(self, future: impl FnOnce() -> F) -> SpawnToken<S> {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.task.raw.poll_fn.set(Some(TaskStorage::<F>::poll));
|
self.task.raw.poll_fn.set(Some(TaskStorage::<F>::poll));
|
||||||
self.task.future.write(future());
|
self.task.future.write_in_place(future);
|
||||||
|
|
||||||
let task = TaskRef::new(self.task);
|
let task = TaskRef::new(self.task);
|
||||||
|
|
||||||
|
@ -17,8 +17,9 @@ impl<T> UninitCell<T> {
|
|||||||
&mut *self.as_mut_ptr()
|
&mut *self.as_mut_ptr()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn write(&self, val: T) {
|
#[inline(never)]
|
||||||
ptr::write(self.as_mut_ptr(), val)
|
pub unsafe fn write_in_place(&self, func: impl FnOnce() -> T) {
|
||||||
|
ptr::write(self.as_mut_ptr(), func())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn drop_in_place(&self) {
|
pub unsafe fn drop_in_place(&self) {
|
||||||
|
@ -3,7 +3,7 @@ use core::task::{RawWaker, RawWakerVTable, Waker};
|
|||||||
|
|
||||||
use super::{wake_task, TaskHeader, TaskRef};
|
use super::{wake_task, TaskHeader, TaskRef};
|
||||||
|
|
||||||
const VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake, drop);
|
static VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake, drop);
|
||||||
|
|
||||||
unsafe fn clone(p: *const ()) -> RawWaker {
|
unsafe fn clone(p: *const ()) -> RawWaker {
|
||||||
RawWaker::new(p, &VTABLE)
|
RawWaker::new(p, &VTABLE)
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
#![allow(unused_macros)]
|
#![allow(unused_macros)]
|
||||||
|
|
||||||
|
use core::fmt::{Debug, Display, LowerHex};
|
||||||
|
|
||||||
#[cfg(all(feature = "defmt", feature = "log"))]
|
#[cfg(all(feature = "defmt", feature = "log"))]
|
||||||
compile_error!("You may not enable both `defmt` and `log` features.");
|
compile_error!("You may not enable both `defmt` and `log` features.");
|
||||||
|
|
||||||
@ -81,14 +83,17 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
{
|
::core::unreachable!($($x)*)
|
||||||
#[cfg(not(feature = "defmt"))]
|
};
|
||||||
::core::unreachable!($($x)*);
|
}
|
||||||
#[cfg(feature = "defmt")]
|
|
||||||
::defmt::unreachable!($($x)*);
|
#[cfg(feature = "defmt")]
|
||||||
}
|
macro_rules! unreachable {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
::defmt::unreachable!($($x)*)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub(crate) 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# embassy-macros
|
# embassy-hal-internal
|
||||||
|
|
||||||
An [Embassy](https://embassy.dev) project.
|
An [Embassy](https://embassy.dev) project.
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
#![allow(unused_macros)]
|
#![allow(unused_macros)]
|
||||||
|
|
||||||
|
use core::fmt::{Debug, Display, LowerHex};
|
||||||
|
|
||||||
#[cfg(all(feature = "defmt", feature = "log"))]
|
#[cfg(all(feature = "defmt", feature = "log"))]
|
||||||
compile_error!("You may not enable both `defmt` and `log` features.");
|
compile_error!("You may not enable both `defmt` and `log` features.");
|
||||||
|
|
||||||
@ -81,14 +83,17 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
{
|
::core::unreachable!($($x)*)
|
||||||
#[cfg(not(feature = "defmt"))]
|
};
|
||||||
::core::unreachable!($($x)*);
|
}
|
||||||
#[cfg(feature = "defmt")]
|
|
||||||
::defmt::unreachable!($($x)*);
|
#[cfg(feature = "defmt")]
|
||||||
}
|
macro_rules! unreachable {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
::defmt::unreachable!($($x)*)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub(crate) 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,6 +4,7 @@ use core::sync::atomic::{compiler_fence, Ordering};
|
|||||||
|
|
||||||
use cortex_m::interrupt::InterruptNumber;
|
use cortex_m::interrupt::InterruptNumber;
|
||||||
use cortex_m::peripheral::NVIC;
|
use cortex_m::peripheral::NVIC;
|
||||||
|
use critical_section::CriticalSection;
|
||||||
|
|
||||||
/// Generate a standard `mod interrupt` for a HAL.
|
/// Generate a standard `mod interrupt` for a HAL.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
@ -91,6 +92,12 @@ macro_rules! interrupt_mod {
|
|||||||
fn set_priority(prio: crate::interrupt::Priority) {
|
fn set_priority(prio: crate::interrupt::Priority) {
|
||||||
Self::IRQ.set_priority(prio)
|
Self::IRQ.set_priority(prio)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the interrupt priority with an already-acquired critical section
|
||||||
|
#[inline]
|
||||||
|
fn set_priority_with_cs(cs: critical_section::CriticalSection, prio: crate::interrupt::Priority) {
|
||||||
|
Self::IRQ.set_priority_with_cs(cs, prio)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$(
|
$(
|
||||||
@ -195,10 +202,29 @@ pub unsafe trait InterruptExt: InterruptNumber + Copy {
|
|||||||
/// Set the interrupt priority.
|
/// Set the interrupt priority.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn set_priority(self, prio: Priority) {
|
fn set_priority(self, prio: Priority) {
|
||||||
critical_section::with(|_| unsafe {
|
unsafe {
|
||||||
let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(());
|
let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(());
|
||||||
nvic.set_priority(self, prio.into())
|
|
||||||
})
|
// On thumbv6, set_priority must do a RMW to change 8bit in a 32bit reg.
|
||||||
|
#[cfg(armv6m)]
|
||||||
|
critical_section::with(|_| nvic.set_priority(self, prio.into()));
|
||||||
|
// On thumbv7+, set_priority does an atomic 8bit write, so no CS needed.
|
||||||
|
#[cfg(not(armv6m))]
|
||||||
|
nvic.set_priority(self, prio.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the interrupt priority with an already-acquired critical section
|
||||||
|
///
|
||||||
|
/// Equivalent to `set_priority`, except you pass a `CriticalSection` to prove
|
||||||
|
/// you've already acquired a critical section. This prevents acquiring another
|
||||||
|
/// one, which saves code size.
|
||||||
|
#[inline]
|
||||||
|
fn set_priority_with_cs(self, _cs: CriticalSection, prio: Priority) {
|
||||||
|
unsafe {
|
||||||
|
let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(());
|
||||||
|
nvic.set_priority(self, prio.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@ pub mod drop;
|
|||||||
mod macros;
|
mod macros;
|
||||||
mod peripheral;
|
mod peripheral;
|
||||||
pub mod ratio;
|
pub mod ratio;
|
||||||
pub mod ring_buffer;
|
|
||||||
pub use peripheral::{Peripheral, PeripheralRef};
|
pub use peripheral::{Peripheral, PeripheralRef};
|
||||||
|
|
||||||
#[cfg(feature = "cortex-m")]
|
#[cfg(feature = "cortex-m")]
|
||||||
|
@ -48,17 +48,23 @@ macro_rules! peripherals_struct {
|
|||||||
///Returns all the peripherals *once*
|
///Returns all the peripherals *once*
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn take() -> Self {
|
pub(crate) fn take() -> Self {
|
||||||
|
critical_section::with(Self::take_with_cs)
|
||||||
|
}
|
||||||
|
|
||||||
|
///Returns all the peripherals *once*
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn take_with_cs(_cs: critical_section::CriticalSection) -> Self {
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
static mut _EMBASSY_DEVICE_PERIPHERALS: bool = false;
|
static mut _EMBASSY_DEVICE_PERIPHERALS: bool = false;
|
||||||
|
|
||||||
critical_section::with(|_| unsafe {
|
// safety: OK because we're inside a CS.
|
||||||
|
unsafe {
|
||||||
if _EMBASSY_DEVICE_PERIPHERALS {
|
if _EMBASSY_DEVICE_PERIPHERALS {
|
||||||
panic!("init called more than once!")
|
panic!("init called more than once!")
|
||||||
}
|
}
|
||||||
_EMBASSY_DEVICE_PERIPHERALS = true;
|
_EMBASSY_DEVICE_PERIPHERALS = true;
|
||||||
Self::steal()
|
Self::steal()
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,136 +0,0 @@
|
|||||||
pub struct RingBuffer<'a> {
|
|
||||||
buf: &'a mut [u8],
|
|
||||||
start: usize,
|
|
||||||
end: usize,
|
|
||||||
empty: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> RingBuffer<'a> {
|
|
||||||
pub fn new(buf: &'a mut [u8]) -> Self {
|
|
||||||
Self {
|
|
||||||
buf,
|
|
||||||
start: 0,
|
|
||||||
end: 0,
|
|
||||||
empty: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push_buf(&mut self) -> &mut [u8] {
|
|
||||||
if self.start == self.end && !self.empty {
|
|
||||||
trace!(" ringbuf: push_buf empty");
|
|
||||||
return &mut self.buf[..0];
|
|
||||||
}
|
|
||||||
|
|
||||||
let n = if self.start <= self.end {
|
|
||||||
self.buf.len() - self.end
|
|
||||||
} else {
|
|
||||||
self.start - self.end
|
|
||||||
};
|
|
||||||
|
|
||||||
trace!(" ringbuf: push_buf {:?}..{:?}", self.end, self.end + n);
|
|
||||||
&mut self.buf[self.end..self.end + n]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push(&mut self, n: usize) {
|
|
||||||
trace!(" ringbuf: push {:?}", n);
|
|
||||||
if n == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.end = self.wrap(self.end + n);
|
|
||||||
self.empty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pop_buf(&mut self) -> &mut [u8] {
|
|
||||||
if self.empty {
|
|
||||||
trace!(" ringbuf: pop_buf empty");
|
|
||||||
return &mut self.buf[..0];
|
|
||||||
}
|
|
||||||
|
|
||||||
let n = if self.end <= self.start {
|
|
||||||
self.buf.len() - self.start
|
|
||||||
} else {
|
|
||||||
self.end - self.start
|
|
||||||
};
|
|
||||||
|
|
||||||
trace!(" ringbuf: pop_buf {:?}..{:?}", self.start, self.start + n);
|
|
||||||
&mut self.buf[self.start..self.start + n]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pop(&mut self, n: usize) {
|
|
||||||
trace!(" ringbuf: pop {:?}", n);
|
|
||||||
if n == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.start = self.wrap(self.start + n);
|
|
||||||
self.empty = self.start == self.end;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_full(&self) -> bool {
|
|
||||||
self.start == self.end && !self.empty
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.empty
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
self.start = 0;
|
|
||||||
self.end = 0;
|
|
||||||
self.empty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn wrap(&self, n: usize) -> usize {
|
|
||||||
assert!(n <= self.buf.len());
|
|
||||||
if n == self.buf.len() {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
n
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn push_pop() {
|
|
||||||
let mut b = [0; 4];
|
|
||||||
let mut rb = RingBuffer::new(&mut b);
|
|
||||||
let buf = rb.push_buf();
|
|
||||||
assert_eq!(4, buf.len());
|
|
||||||
buf[0] = 1;
|
|
||||||
buf[1] = 2;
|
|
||||||
buf[2] = 3;
|
|
||||||
buf[3] = 4;
|
|
||||||
rb.push(4);
|
|
||||||
|
|
||||||
let buf = rb.pop_buf();
|
|
||||||
assert_eq!(4, buf.len());
|
|
||||||
assert_eq!(1, buf[0]);
|
|
||||||
rb.pop(1);
|
|
||||||
|
|
||||||
let buf = rb.pop_buf();
|
|
||||||
assert_eq!(3, buf.len());
|
|
||||||
assert_eq!(2, buf[0]);
|
|
||||||
rb.pop(1);
|
|
||||||
|
|
||||||
let buf = rb.pop_buf();
|
|
||||||
assert_eq!(2, buf.len());
|
|
||||||
assert_eq!(3, buf[0]);
|
|
||||||
rb.pop(1);
|
|
||||||
|
|
||||||
let buf = rb.pop_buf();
|
|
||||||
assert_eq!(1, buf.len());
|
|
||||||
assert_eq!(4, buf[0]);
|
|
||||||
rb.pop(1);
|
|
||||||
|
|
||||||
let buf = rb.pop_buf();
|
|
||||||
assert_eq!(0, buf.len());
|
|
||||||
|
|
||||||
let buf = rb.push_buf();
|
|
||||||
assert_eq!(4, buf.len());
|
|
||||||
}
|
|
||||||
}
|
|
@ -20,15 +20,12 @@ defmt = ["dep:defmt", "lorawan-device/defmt"]
|
|||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
log = { version = "0.4.14", optional = true }
|
log = { version = "0.4.14", optional = true }
|
||||||
|
|
||||||
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
|
embassy-time = { version = "0.1.5", path = "../embassy-time", optional = true }
|
||||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.4.0", path = "../embassy-sync" }
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true }
|
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true }
|
||||||
embedded-hal-async = { version = "=1.0.0-rc.1" }
|
embedded-hal-async = { version = "=1.0.0-rc.1" }
|
||||||
embedded-hal = { version = "0.2", features = ["unproven"] }
|
embedded-hal = { version = "0.2", features = ["unproven"] }
|
||||||
|
|
||||||
futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] }
|
futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] }
|
||||||
lora-phy = { version = "1" }
|
lora-phy = { version = "2" }
|
||||||
lorawan-device = { version = "0.10.0", default-features = false, features = ["async"], optional = true }
|
lorawan-device = { version = "0.11.0", default-features = false, features = ["async"], optional = true }
|
||||||
|
|
||||||
[patch.crates-io]
|
|
||||||
lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"}
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
#![allow(unused_macros)]
|
#![allow(unused_macros)]
|
||||||
|
|
||||||
|
use core::fmt::{Debug, Display, LowerHex};
|
||||||
|
|
||||||
#[cfg(all(feature = "defmt", feature = "log"))]
|
#[cfg(all(feature = "defmt", feature = "log"))]
|
||||||
compile_error!("You may not enable both `defmt` and `log` features.");
|
compile_error!("You may not enable both `defmt` and `log` features.");
|
||||||
|
|
||||||
@ -81,14 +83,17 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
{
|
::core::unreachable!($($x)*)
|
||||||
#[cfg(not(feature = "defmt"))]
|
};
|
||||||
::core::unreachable!($($x)*);
|
}
|
||||||
#[cfg(feature = "defmt")]
|
|
||||||
::defmt::unreachable!($($x)*);
|
#[cfg(feature = "defmt")]
|
||||||
}
|
macro_rules! unreachable {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
::defmt::unreachable!($($x)*)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub(crate) 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -67,24 +67,20 @@ where
|
|||||||
self.board_type = board_type;
|
self.board_type = board_type;
|
||||||
}
|
}
|
||||||
async fn set_nss_low(&mut self) -> Result<(), RadioError> {
|
async fn set_nss_low(&mut self) -> Result<(), RadioError> {
|
||||||
let pwr = pac::PWR;
|
pac::PWR.subghzspicr().modify(|w| w.set_nss(false));
|
||||||
pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::LOW));
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
async fn set_nss_high(&mut self) -> Result<(), RadioError> {
|
async fn set_nss_high(&mut self) -> Result<(), RadioError> {
|
||||||
let pwr = pac::PWR;
|
pac::PWR.subghzspicr().modify(|w| w.set_nss(true));
|
||||||
pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::HIGH));
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
async fn reset(&mut self, _delay: &mut impl DelayUs) -> Result<(), RadioError> {
|
async fn reset(&mut self, _delay: &mut impl DelayUs) -> Result<(), RadioError> {
|
||||||
let rcc = pac::RCC;
|
pac::RCC.csr().modify(|w| w.set_rfrst(true));
|
||||||
rcc.csr().modify(|w| w.set_rfrst(true));
|
pac::RCC.csr().modify(|w| w.set_rfrst(false));
|
||||||
rcc.csr().modify(|w| w.set_rfrst(false));
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
async fn wait_on_busy(&mut self) -> Result<(), RadioError> {
|
async fn wait_on_busy(&mut self) -> Result<(), RadioError> {
|
||||||
let pwr = pac::PWR;
|
while pac::PWR.sr2().read().rfbusys() {}
|
||||||
while pwr.sr2().read().rfbusys() == pac::pwr::vals::Rfbusys::BUSY {}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,11 +280,7 @@ where
|
|||||||
self.busy.wait_for_low().await.map_err(|_| Busy)
|
self.busy.wait_for_low().await.map_err(|_| Busy)
|
||||||
}
|
}
|
||||||
async fn await_irq(&mut self) -> Result<(), RadioError> {
|
async fn await_irq(&mut self) -> Result<(), RadioError> {
|
||||||
if self.board_type != BoardType::RpPicoWaveshareSx1262 {
|
self.dio1.wait_for_high().await.map_err(|_| DIO1)?;
|
||||||
self.dio1.wait_for_high().await.map_err(|_| DIO1)?;
|
|
||||||
} else {
|
|
||||||
self.dio1.wait_for_rising_edge().await.map_err(|_| DIO1)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(async_fn_in_trait, impl_trait_projections)]
|
#![feature(async_fn_in_trait, impl_trait_projections)]
|
||||||
|
#![allow(stable_features, unknown_lints, async_fn_in_trait)]
|
||||||
//! embassy-lora holds LoRa-specific functionality.
|
//! embassy-lora holds LoRa-specific functionality.
|
||||||
|
|
||||||
pub(crate) mod fmt;
|
pub(crate) mod fmt;
|
||||||
@ -34,6 +35,6 @@ impl lorawan_device::async_device::radio::Timer for LoraTimer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn delay_ms(&mut self, millis: u64) {
|
async fn delay_ms(&mut self, millis: u64) {
|
||||||
Timer::after(Duration::from_millis(millis)).await
|
Timer::after_millis(millis).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "embassy-net-adin1110"
|
name = "embassy-net-adin1110"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
description = "embassy-net driver for the ADIN1110 ethernet chip"
|
description = "embassy-net driver for the ADIN1110 ethernet chip"
|
||||||
keywords = ["embedded", "ADIN1110", "embassy-net", "embedded-hal-async", "ethernet", "async"]
|
keywords = ["embedded", "ADIN1110", "embassy-net", "embedded-hal-async", "ethernet", "async"]
|
||||||
categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"]
|
categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"]
|
||||||
@ -12,30 +12,31 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
heapless = "0.7.16"
|
heapless = "0.7.16"
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
log = { version = "0.4.4", default-features = false, optional = true }
|
log = { version = "0.4", default-features = false, optional = true }
|
||||||
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" }
|
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" }
|
||||||
embedded-hal-async = { version = "=1.0.0-rc.1" }
|
embedded-hal-async = { version = "=1.0.0-rc.1" }
|
||||||
embedded-hal-bus = { version = "=0.1.0-rc.1", features = ["async"] }
|
embedded-hal-bus = { version = "=0.1.0-rc.1", features = ["async"] }
|
||||||
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
|
embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" }
|
||||||
embassy-time = { version = "0.1.0" }
|
embassy-time = { version = "0.1.5", path = "../embassy-time" }
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
bitfield = "0.14.0"
|
bitfield = "0.14.0"
|
||||||
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
# reenable when https://github.com/dbrgn/embedded-hal-mock/pull/86 is merged.
|
# reenable when https://github.com/dbrgn/embedded-hal-mock/pull/86 is merged.
|
||||||
#embedded-hal-mock = { git = "https://github.com/dbrgn/embedded-hal-mock", branch = "1-alpha", features = ["embedded-hal-async", "eh1"] }] }
|
#embedded-hal-mock = { git = "https://github.com/dbrgn/embedded-hal-mock", branch = "1-alpha", features = ["embedded-hal-async", "eh1"] }] }
|
||||||
embedded-hal-mock = { git = "https://github.com/newAM/embedded-hal-mock", branch = "eh1-rc.1", features = ["embedded-hal-async", "eh1"] }
|
embedded-hal-mock = { git = "https://github.com/newAM/embedded-hal-mock", branch = "eh1-rc.1", features = ["embedded-hal-async", "eh1"] }
|
||||||
crc = "3.0.1"
|
crc = "3.0.1"
|
||||||
env_logger = "0.10"
|
env_logger = "0.10"
|
||||||
critical-section = { version = "1.1.1", features = ["std"] }
|
critical-section = { version = "1.1.2", features = ["std"] }
|
||||||
futures-test = "0.3.17"
|
futures-test = "0.3.28"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [ ]
|
default = [ ]
|
||||||
defmt = [ "dep:defmt" ]
|
defmt = [ "dep:defmt", "embedded-hal-1/defmt-03" ]
|
||||||
|
log = ["dep:log"]
|
||||||
|
|
||||||
[package.metadata.embassy_docs]
|
[package.metadata.embassy_docs]
|
||||||
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-adin1110-v$VERSION/embassy-net-adin1110/src/"
|
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-adin1110-v$VERSION/embassy-net-adin1110/src/"
|
||||||
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-adin1110/src/"
|
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-adin1110/src/"
|
||||||
target = "thumbv7em-none-eabi"
|
target = "thumbv7em-none-eabi"
|
||||||
|
features = ["defmt"]
|
||||||
|
@ -30,8 +30,8 @@ Currently only `Generic` SPI with or without CRC is supported.
|
|||||||
|
|
||||||
## Hardware
|
## Hardware
|
||||||
|
|
||||||
- Tested on [`Analog Devices EVAL-ADIN1110EBZ`](https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/eval-adin1110.html) with an `STM32L4S5QII3P`, see [`spe_adin1110_http_server`](../examples/stm32l4/src/bin/spe_adin1110_http_server.rs) dor an example.
|
- Tested on [`Analog Devices EVAL-ADIN1110EBZ`](https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/eval-adin1110.html) with an `STM32L4S5QII3P`, see [`spe_adin1110_http_server`](../examples/stm32l4/src/bin/spe_adin1110_http_server.rs) for an example.
|
||||||
- [`SparkFun MicroMod Single Pair Ethernet Function Board`](https://www.sparkfun.com/products/19038) or [`SparkFun MicroMod Single Pair Ethernet Kit`](https://www.sparkfun.com/products/19628), supporting multiple microcontrollers. **Make sure to check if it's a microcontroller that is supported by Embassy!**
|
- [`SparkFun MicroMod Single Pair Ethernet Function Board`](https://www.sparkfun.com/products/19038) or [`SparkFun MicroMod Single Pair Ethernet Kit (End Of Life)`](https://www.sparkfun.com/products/19628), supporting multiple microcontrollers. **Make sure to check if it's a microcontroller that is supported by Embassy!**
|
||||||
|
|
||||||
## Other SPE chips
|
## Other SPE chips
|
||||||
|
|
||||||
@ -44,6 +44,39 @@ ADIN1110 library can tested on the host with a mock SPI driver.
|
|||||||
|
|
||||||
$ `cargo test --target x86_64-unknown-linux-gnu`
|
$ `cargo test --target x86_64-unknown-linux-gnu`
|
||||||
|
|
||||||
|
## Benchmark
|
||||||
|
|
||||||
|
- Benchmarked on [`Analog Devices EVAL-ADIN1110EBZ`](https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/eval-adin1110.html), with [`spe_adin1110_http_server`](../examples/stm32l4/src/bin/spe_adin1110_http_server.rs) example.
|
||||||
|
|
||||||
|
Basic `ping` benchmark
|
||||||
|
```rust,ignore
|
||||||
|
# ping <IP> -c 60
|
||||||
|
|
||||||
|
60 packets transmitted, 60 received, 0% packet loss, time 59066ms
|
||||||
|
rtt min/avg/max/mdev = 1.089/1.161/1.237/0.018 ms
|
||||||
|
|
||||||
|
# ping <IP> -s 1472 -M do -c 60
|
||||||
|
|
||||||
|
60 packets transmitted, 60 received, 0% packet loss, time 59066ms
|
||||||
|
rtt min/avg/max/mdev = 5.122/5.162/6.177/0.133 ms
|
||||||
|
```
|
||||||
|
|
||||||
|
HTTP load generator benchmark with [`oha`](https://github.com/hatoo/oha)
|
||||||
|
```rust,ignore
|
||||||
|
# oha -c 1 http://<IP> -z 60s
|
||||||
|
Summary:
|
||||||
|
Success rate: 50.00%
|
||||||
|
Total: 60.0005 secs
|
||||||
|
Slowest: 0.0055 secs
|
||||||
|
Fastest: 0.0033 secs
|
||||||
|
Average: 0.0034 secs
|
||||||
|
Requests/sec: 362.1971
|
||||||
|
|
||||||
|
Total data: 2.99 MiB
|
||||||
|
Size/request: 289 B
|
||||||
|
Size/sec: 51.11 KiB
|
||||||
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This work is licensed under either of
|
This work is licensed under either of
|
||||||
|
@ -257,29 +257,30 @@ pub const CRC32R_LOOKUP_TABLE: [u32; 256] = [
|
|||||||
0x2D02_EF8D,
|
0x2D02_EF8D,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/// Generate Ethernet Frame Check Sequence
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ETH_FSC(pub u32);
|
pub struct ETH_FCS(pub u32);
|
||||||
|
|
||||||
impl ETH_FSC {
|
impl ETH_FCS {
|
||||||
pub const CRC32_OK: u32 = 0x2144_df1c;
|
pub const CRC32_OK: u32 = 0x2144_df1c;
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(data: &[u8]) -> Self {
|
pub fn new(data: &[u8]) -> Self {
|
||||||
let fsc = data.iter().fold(u32::MAX, |crc, byte| {
|
let fcs = data.iter().fold(u32::MAX, |crc, byte| {
|
||||||
let idx = u8::try_from(crc & 0xFF).unwrap() ^ byte;
|
let idx = u8::try_from(crc & 0xFF).unwrap() ^ byte;
|
||||||
CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8)
|
CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8)
|
||||||
}) ^ u32::MAX;
|
}) ^ u32::MAX;
|
||||||
Self(fsc)
|
Self(fcs)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn update(self, data: &[u8]) -> Self {
|
pub fn update(self, data: &[u8]) -> Self {
|
||||||
let fsc = data.iter().fold(self.0 ^ u32::MAX, |crc, byte| {
|
let fcs = data.iter().fold(self.0 ^ u32::MAX, |crc, byte| {
|
||||||
let idx = u8::try_from(crc & 0xFF).unwrap() ^ byte;
|
let idx = u8::try_from(crc & 0xFF).unwrap() ^ byte;
|
||||||
CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8)
|
CRC32R_LOOKUP_TABLE[usize::from(idx)] ^ (crc >> 8)
|
||||||
}) ^ u32::MAX;
|
}) ^ u32::MAX;
|
||||||
Self(fsc)
|
Self(fcs)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -319,24 +320,24 @@ mod tests {
|
|||||||
];
|
];
|
||||||
|
|
||||||
// Packet A
|
// Packet A
|
||||||
let own_crc = ETH_FSC::new(&packet_a[0..60]);
|
let own_crc = ETH_FCS::new(&packet_a[0..60]);
|
||||||
let crc_bytes = own_crc.hton_bytes();
|
let crc_bytes = own_crc.hton_bytes();
|
||||||
println!("{:08x} {:02x?}", own_crc.0, crc_bytes);
|
println!("{:08x} {:02x?}", own_crc.0, crc_bytes);
|
||||||
assert_eq!(&crc_bytes, &packet_a[60..64]);
|
assert_eq!(&crc_bytes, &packet_a[60..64]);
|
||||||
|
|
||||||
let own_crc = ETH_FSC::new(packet_a);
|
let own_crc = ETH_FCS::new(packet_a);
|
||||||
println!("{:08x}", own_crc.0);
|
println!("{:08x}", own_crc.0);
|
||||||
assert_eq!(own_crc.0, ETH_FSC::CRC32_OK);
|
assert_eq!(own_crc.0, ETH_FCS::CRC32_OK);
|
||||||
|
|
||||||
// Packet B
|
// Packet B
|
||||||
let own_crc = ETH_FSC::new(&packet_b[0..60]);
|
let own_crc = ETH_FCS::new(&packet_b[0..60]);
|
||||||
let crc_bytes = own_crc.hton_bytes();
|
let crc_bytes = own_crc.hton_bytes();
|
||||||
println!("{:08x} {:02x?}", own_crc.0, crc_bytes);
|
println!("{:08x} {:02x?}", own_crc.0, crc_bytes);
|
||||||
assert_eq!(&crc_bytes, &packet_b[60..64]);
|
assert_eq!(&crc_bytes, &packet_b[60..64]);
|
||||||
|
|
||||||
let own_crc = ETH_FSC::new(packet_b);
|
let own_crc = ETH_FCS::new(packet_b);
|
||||||
println!("{:08x}", own_crc.0);
|
println!("{:08x}", own_crc.0);
|
||||||
assert_eq!(own_crc.0, ETH_FSC::CRC32_OK);
|
assert_eq!(own_crc.0, ETH_FCS::CRC32_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -349,9 +350,9 @@ mod tests {
|
|||||||
];
|
];
|
||||||
|
|
||||||
let (part_a, part_b) = full_data.split_at(16);
|
let (part_a, part_b) = full_data.split_at(16);
|
||||||
let crc_partially = ETH_FSC::new(part_a).update(part_b);
|
let crc_partially = ETH_FCS::new(part_a).update(part_b);
|
||||||
|
|
||||||
let crc_full = ETH_FSC::new(full_data);
|
let crc_full = ETH_FCS::new(full_data);
|
||||||
|
|
||||||
assert_eq!(crc_full.0, crc_partially.0);
|
assert_eq!(crc_full.0, crc_partially.0);
|
||||||
}
|
}
|
||||||
|
254
embassy-net-adin1110/src/fmt.rs
Normal file
254
embassy-net-adin1110/src/fmt.rs
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
#![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 _ignored = ($( & $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 _ignored = ($( & $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 _ignored = ($( & $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 _ignored = ($( & $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 _ignored = ($( & $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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
pub struct NoneError;
|
||||||
|
|
||||||
|
pub trait Try {
|
||||||
|
type Ok;
|
||||||
|
type Error;
|
||||||
|
fn into_result(self) -> Result<Self::Ok, Self::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Try for Option<T> {
|
||||||
|
type Ok = T;
|
||||||
|
type Error = NoneError;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn into_result(self) -> Result<T, NoneError> {
|
||||||
|
self.ok_or(NoneError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E> Try for Result<T, E> {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -32,11 +32,12 @@ enum Reg13Op {
|
|||||||
PostReadIncAddr = 0b10 << 14,
|
PostReadIncAddr = 0b10 << 14,
|
||||||
Read = 0b11 << 14,
|
Read = 0b11 << 14,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `MdioBus` trait
|
/// `MdioBus` trait
|
||||||
/// Driver needs to implement the Clause 22
|
/// Driver needs to implement the Clause 22
|
||||||
/// Optional Clause 45 is the device supports this.
|
/// Optional Clause 45 is the device supports this.
|
||||||
///
|
///
|
||||||
/// Claus 45 methodes are bases on <https://www.ieee802.org/3/efm/public/nov02/oam/pannell_oam_1_1102.pdf>
|
/// Clause 45 methodes are bases on <https://www.ieee802.org/3/efm/public/nov02/oam/pannell_oam_1_1102.pdf>
|
||||||
pub trait MdioBus {
|
pub trait MdioBus {
|
||||||
type Error;
|
type Error;
|
||||||
|
|
||||||
@ -87,89 +88,89 @@ pub trait MdioBus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[cfg(test)]
|
#[cfg(test)]
|
||||||
// mod tests {
|
mod tests {
|
||||||
// use core::convert::Infallible;
|
use core::convert::Infallible;
|
||||||
|
|
||||||
// use super::{MdioBus, PhyAddr, RegC22, RegVal};
|
use super::{MdioBus, PhyAddr, RegC22, RegVal};
|
||||||
|
|
||||||
// #[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
// enum A {
|
enum A {
|
||||||
// Read(PhyAddr, RegC22),
|
Read(PhyAddr, RegC22),
|
||||||
// Write(PhyAddr, RegC22, RegVal),
|
Write(PhyAddr, RegC22, RegVal),
|
||||||
// }
|
}
|
||||||
|
|
||||||
// struct MockMdioBus(Vec<A>);
|
struct MockMdioBus(Vec<A>);
|
||||||
|
|
||||||
// impl MockMdioBus {
|
impl MockMdioBus {
|
||||||
// pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
// self.0.clear();
|
self.0.clear();
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// impl MdioBus for MockMdioBus {
|
impl MdioBus for MockMdioBus {
|
||||||
// type Error = Infallible;
|
type Error = Infallible;
|
||||||
|
|
||||||
// fn write_cl22(
|
async fn write_cl22(
|
||||||
// &mut self,
|
&mut self,
|
||||||
// phy_id: super::PhyAddr,
|
phy_id: super::PhyAddr,
|
||||||
// reg: super::RegC22,
|
reg: super::RegC22,
|
||||||
// reg_val: super::RegVal,
|
reg_val: super::RegVal,
|
||||||
// ) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
// self.0.push(A::Write(phy_id, reg, reg_val));
|
self.0.push(A::Write(phy_id, reg, reg_val));
|
||||||
// Ok(())
|
Ok(())
|
||||||
// }
|
}
|
||||||
|
|
||||||
// fn read_cl22(
|
async fn read_cl22(
|
||||||
// &mut self,
|
&mut self,
|
||||||
// phy_id: super::PhyAddr,
|
phy_id: super::PhyAddr,
|
||||||
// reg: super::RegC22,
|
reg: super::RegC22,
|
||||||
// ) -> Result<super::RegVal, Self::Error> {
|
) -> Result<super::RegVal, Self::Error> {
|
||||||
// self.0.push(A::Read(phy_id, reg));
|
self.0.push(A::Read(phy_id, reg));
|
||||||
// Ok(0)
|
Ok(0)
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// #[test]
|
#[futures_test::test]
|
||||||
// fn read_test() {
|
async fn read_test() {
|
||||||
// let mut mdiobus = MockMdioBus(Vec::with_capacity(20));
|
let mut mdiobus = MockMdioBus(Vec::with_capacity(20));
|
||||||
|
|
||||||
// mdiobus.clear();
|
mdiobus.clear();
|
||||||
// mdiobus.read_cl22(0x01, 0x00).unwrap();
|
mdiobus.read_cl22(0x01, 0x00).await.unwrap();
|
||||||
// assert_eq!(mdiobus.0, vec![A::Read(0x01, 0x00)]);
|
assert_eq!(mdiobus.0, vec![A::Read(0x01, 0x00)]);
|
||||||
|
|
||||||
// mdiobus.clear();
|
mdiobus.clear();
|
||||||
// mdiobus.read_cl45(0x01, (0xBB, 0x1234)).unwrap();
|
mdiobus.read_cl45(0x01, (0xBB, 0x1234)).await.unwrap();
|
||||||
// assert_eq!(
|
assert_eq!(
|
||||||
// mdiobus.0,
|
mdiobus.0,
|
||||||
// vec![
|
vec![
|
||||||
// #[allow(clippy::identity_op)]
|
#[allow(clippy::identity_op)]
|
||||||
// A::Write(0x01, 13, (0b00 << 14) | 27),
|
A::Write(0x01, 13, (0b00 << 14) | 27),
|
||||||
// A::Write(0x01, 14, 0x1234),
|
A::Write(0x01, 14, 0x1234),
|
||||||
// A::Write(0x01, 13, (0b11 << 14) | 27),
|
A::Write(0x01, 13, (0b11 << 14) | 27),
|
||||||
// A::Read(0x01, 14)
|
A::Read(0x01, 14)
|
||||||
// ]
|
]
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// #[test]
|
#[futures_test::test]
|
||||||
// fn write_test() {
|
async fn write_test() {
|
||||||
// let mut mdiobus = MockMdioBus(Vec::with_capacity(20));
|
let mut mdiobus = MockMdioBus(Vec::with_capacity(20));
|
||||||
|
|
||||||
// mdiobus.clear();
|
mdiobus.clear();
|
||||||
// mdiobus.write_cl22(0x01, 0x00, 0xABCD).unwrap();
|
mdiobus.write_cl22(0x01, 0x00, 0xABCD).await.unwrap();
|
||||||
// assert_eq!(mdiobus.0, vec![A::Write(0x01, 0x00, 0xABCD)]);
|
assert_eq!(mdiobus.0, vec![A::Write(0x01, 0x00, 0xABCD)]);
|
||||||
|
|
||||||
// mdiobus.clear();
|
mdiobus.clear();
|
||||||
// mdiobus.write_cl45(0x01, (0xBB, 0x1234), 0xABCD).unwrap();
|
mdiobus.write_cl45(0x01, (0xBB, 0x1234), 0xABCD).await.unwrap();
|
||||||
// assert_eq!(
|
assert_eq!(
|
||||||
// mdiobus.0,
|
mdiobus.0,
|
||||||
// vec![
|
vec![
|
||||||
// A::Write(0x01, 13, 27),
|
A::Write(0x01, 13, 27),
|
||||||
// A::Write(0x01, 14, 0x1234),
|
A::Write(0x01, 14, 0x1234),
|
||||||
// A::Write(0x01, 13, (0b01 << 14) | 27),
|
A::Write(0x01, 13, (0b01 << 14) | 27),
|
||||||
// A::Write(0x01, 14, 0xABCD)
|
A::Write(0x01, 14, 0xABCD)
|
||||||
// ]
|
]
|
||||||
// );
|
);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
@ -111,6 +111,7 @@ pub mod RegsC45 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 10-BASE-T1x PHY functions.
|
||||||
pub struct Phy10BaseT1x(u8);
|
pub struct Phy10BaseT1x(u8);
|
||||||
|
|
||||||
impl Default for Phy10BaseT1x {
|
impl Default for Phy10BaseT1x {
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use core::fmt::{Debug, Display};
|
||||||
|
|
||||||
use bitfield::{bitfield, bitfield_bitrange, bitfield_fields};
|
use bitfield::{bitfield, bitfield_bitrange, bitfield_fields};
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
@ -34,6 +36,12 @@ pub enum SpiRegisters {
|
|||||||
RX = 0x91,
|
RX = 0x91,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for SpiRegisters {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
write!(f, "{self:?}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<SpiRegisters> for u16 {
|
impl From<SpiRegisters> for u16 {
|
||||||
fn from(val: SpiRegisters) -> Self {
|
fn from(val: SpiRegisters) -> Self {
|
||||||
val as u16
|
val as u16
|
||||||
@ -68,7 +76,7 @@ impl From<u16> for SpiRegisters {
|
|||||||
0x73 => Self::ADDR_MSK_UPR1,
|
0x73 => Self::ADDR_MSK_UPR1,
|
||||||
0x90 => Self::RX_FSIZE,
|
0x90 => Self::RX_FSIZE,
|
||||||
0x91 => Self::RX,
|
0x91 => Self::RX,
|
||||||
e => panic!("Unknown value {e}"),
|
e => panic!("Unknown value {}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,7 +182,7 @@ bitfield! {
|
|||||||
pub sdf_detect_src, set_sdf_detect_src : 7;
|
pub sdf_detect_src, set_sdf_detect_src : 7;
|
||||||
/// Statistics Clear on Reading
|
/// Statistics Clear on Reading
|
||||||
pub stats_clr_on_rd, set_stats_clr_on_rd : 6;
|
pub stats_clr_on_rd, set_stats_clr_on_rd : 6;
|
||||||
/// Enable CRC Append
|
/// Enable SPI CRC
|
||||||
pub crc_append, set_crc_append : 5;
|
pub crc_append, set_crc_append : 5;
|
||||||
/// Admit Frames with IFG Errors on Port 1 (P1)
|
/// Admit Frames with IFG Errors on Port 1 (P1)
|
||||||
pub p1_rcv_ifg_err_frm, set_p1_rcv_ifg_err_frm : 4;
|
pub p1_rcv_ifg_err_frm, set_p1_rcv_ifg_err_frm : 4;
|
||||||
@ -313,7 +321,7 @@ impl From<u8> for LedFunc {
|
|||||||
26 => LedFunc::Clk25Ref,
|
26 => LedFunc::Clk25Ref,
|
||||||
27 => LedFunc::TxTCLK,
|
27 => LedFunc::TxTCLK,
|
||||||
28 => LedFunc::Clk120MHz,
|
28 => LedFunc::Clk120MHz,
|
||||||
e => panic!("Invalid value {e}"),
|
e => panic!("Invalid value {}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -369,7 +377,7 @@ impl From<u8> for LedPol {
|
|||||||
0 => LedPol::AutoSense,
|
0 => LedPol::AutoSense,
|
||||||
1 => LedPol::ActiveHigh,
|
1 => LedPol::ActiveHigh,
|
||||||
2 => LedPol::ActiveLow,
|
2 => LedPol::ActiveLow,
|
||||||
e => panic!("Invalid value {e}"),
|
e => panic!("Invalid value {}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
16
embassy-net-driver-channel/CHANGELOG.md
Normal file
16
embassy-net-driver-channel/CHANGELOG.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## 0.2.0 - 2023-10-18
|
||||||
|
|
||||||
|
- Update `embassy-net-driver` to v0.2
|
||||||
|
- `Runner::new` now takes an `embassy_net_driver::HardwareAddress` parameter.
|
||||||
|
- `Runner::set_ethernet_address` is now `set_hardware_address`.
|
||||||
|
|
||||||
|
## 0.1.0 - 2023-06-29
|
||||||
|
|
||||||
|
- First release
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "embassy-net-driver-channel"
|
name = "embassy-net-driver-channel"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "High-level channel-based driver for the `embassy-net` async TCP/IP network stack."
|
description = "High-level channel-based driver for the `embassy-net` async TCP/IP network stack."
|
||||||
@ -24,6 +24,6 @@ features = ["defmt"]
|
|||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
log = { version = "0.4.14", optional = true }
|
log = { version = "0.4.14", optional = true }
|
||||||
|
|
||||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.4.0", path = "../embassy-sync" }
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
|
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
|
||||||
|
@ -7,7 +7,9 @@ The `embassy-net-driver` trait is polling-based. To implement it, you must write
|
|||||||
hand, and hook up the `Waker`s provided by `embassy-net` to the right interrupt handlers so that `embassy-net`
|
hand, and hook up the `Waker`s provided by `embassy-net` to the right interrupt handlers so that `embassy-net`
|
||||||
knows when to poll your driver again to make more progress.
|
knows when to poll your driver again to make more progress.
|
||||||
|
|
||||||
With `embassy-net-driver-channel`
|
With `embassy-net-driver-channel` you get a "channel-like" interface instead, where you can send/receive packets
|
||||||
|
to/from embassy-net. The intended usage is to spawn a "driver task" in the background that does this, passing
|
||||||
|
packets between the hardware and the channel.
|
||||||
|
|
||||||
## A note about deadlocks
|
## A note about deadlocks
|
||||||
|
|
||||||
@ -18,19 +20,19 @@ loop {
|
|||||||
// Wait for either..
|
// Wait for either..
|
||||||
match select(
|
match select(
|
||||||
// ... the chip signaling an interrupt, indicating a packet is available to receive, or
|
// ... the chip signaling an interrupt, indicating a packet is available to receive, or
|
||||||
irq_pin.wait_for_low(),
|
irq_pin.wait_for_low(),
|
||||||
// ... a TX buffer becoming available, i.e. embassy-net wants to send a packet
|
// ... a TX buffer becoming available, i.e. embassy-net wants to send a packet
|
||||||
tx_chan.tx_buf(),
|
tx_chan.tx_buf(),
|
||||||
).await {
|
).await {
|
||||||
Either::First(_) => {
|
Either::First(_) => {
|
||||||
// a packet is ready to be received!
|
// a packet is ready to be received!
|
||||||
let buf = rx_chan.rx_buf().await; // allocate a rx buf from the packet queue
|
let buf = rx_chan.rx_buf().await; // allocate a rx buf from the packet queue
|
||||||
let n = receive_packet_over_spi(buf).await;
|
let n = receive_packet_over_spi(buf).await;
|
||||||
rx_chan.rx_done(n);
|
rx_chan.rx_done(n);
|
||||||
}
|
}
|
||||||
Either::Second(buf) => {
|
Either::Second(buf) => {
|
||||||
// a packet is ready to be sent!
|
// a packet is ready to be sent!
|
||||||
send_packet_over_spi(buf).await;
|
send_packet_over_spi(buf).await;
|
||||||
tx_chan.tx_done();
|
tx_chan.tx_done();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -41,7 +43,7 @@ However, this code has a latent deadlock bug. The symptom is it can hang at `rx_
|
|||||||
|
|
||||||
The reason is that, under load, both the TX and RX queues can get full at the same time. When this happens, the `embassy-net` task stalls trying to send because the TX queue is full, therefore it stops processing packets in the RX queue. Your driver task also stalls because the RX queue is full, therefore it stops processing packets in the TX queue.
|
The reason is that, under load, both the TX and RX queues can get full at the same time. When this happens, the `embassy-net` task stalls trying to send because the TX queue is full, therefore it stops processing packets in the RX queue. Your driver task also stalls because the RX queue is full, therefore it stops processing packets in the TX queue.
|
||||||
|
|
||||||
The fix is to make sure to always service the TX queue while you're waiting for space to become available in the TX queue. For example, select on either "tx_chan.tx_buf() available" or "INT is low AND rx_chan.rx_buf() available":
|
The fix is to make sure to always service the TX queue while you're waiting for space to become available in the RX queue. For example, select on either "tx_chan.tx_buf() available" or "INT is low AND rx_chan.rx_buf() available":
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
loop {
|
loop {
|
||||||
@ -58,12 +60,12 @@ loop {
|
|||||||
).await {
|
).await {
|
||||||
Either::First(buf) => {
|
Either::First(buf) => {
|
||||||
// a packet is ready to be received!
|
// a packet is ready to be received!
|
||||||
let n = receive_packet_over_spi(buf).await;
|
let n = receive_packet_over_spi(buf).await;
|
||||||
rx_chan.rx_done(n);
|
rx_chan.rx_done(n);
|
||||||
}
|
}
|
||||||
Either::Second(buf) => {
|
Either::Second(buf) => {
|
||||||
// a packet is ready to be sent!
|
// a packet is ready to be sent!
|
||||||
send_packet_over_spi(buf).await;
|
send_packet_over_spi(buf).await;
|
||||||
tx_chan.tx_done();
|
tx_chan.tx_done();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,12 +81,10 @@ These `embassy-net` drivers are implemented using this crate. You can look at th
|
|||||||
- [`embassy-net-wiznet`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-wiznet) for Wiznet SPI Ethernet MAC+PHY chips.
|
- [`embassy-net-wiznet`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-wiznet) for Wiznet SPI Ethernet MAC+PHY chips.
|
||||||
- [`embassy-net-esp-hosted`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-esp-hosted) for using ESP32 chips with the [`esp-hosted`](https://github.com/espressif/esp-hosted) firmware as WiFi adapters for another non-ESP32 MCU.
|
- [`embassy-net-esp-hosted`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-esp-hosted) for using ESP32 chips with the [`esp-hosted`](https://github.com/espressif/esp-hosted) firmware as WiFi adapters for another non-ESP32 MCU.
|
||||||
|
|
||||||
|
|
||||||
## Interoperability
|
## Interoperability
|
||||||
|
|
||||||
This crate can run on any executor.
|
This crate can run on any executor.
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This work is licensed under either of
|
This work is licensed under either of
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
#![allow(unused_macros)]
|
#![allow(unused_macros)]
|
||||||
|
|
||||||
|
use core::fmt::{Debug, Display, LowerHex};
|
||||||
|
|
||||||
#[cfg(all(feature = "defmt", feature = "log"))]
|
#[cfg(all(feature = "defmt", feature = "log"))]
|
||||||
compile_error!("You may not enable both `defmt` and `log` features.");
|
compile_error!("You may not enable both `defmt` and `log` features.");
|
||||||
|
|
||||||
@ -81,14 +83,17 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
{
|
::core::unreachable!($($x)*)
|
||||||
#[cfg(not(feature = "defmt"))]
|
};
|
||||||
::core::unreachable!($($x)*);
|
}
|
||||||
#[cfg(feature = "defmt")]
|
|
||||||
::defmt::unreachable!($($x)*);
|
#[cfg(feature = "defmt")]
|
||||||
}
|
macro_rules! unreachable {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
::defmt::unreachable!($($x)*)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub(crate) 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -8,12 +8,12 @@ use core::cell::RefCell;
|
|||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
use core::task::{Context, Poll};
|
use core::task::{Context, Poll};
|
||||||
|
|
||||||
use driver::HardwareAddress;
|
|
||||||
pub use embassy_net_driver as driver;
|
pub use embassy_net_driver as driver;
|
||||||
use embassy_net_driver::{Capabilities, LinkState, Medium};
|
use embassy_net_driver::{Capabilities, LinkState};
|
||||||
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
||||||
use embassy_sync::blocking_mutex::Mutex;
|
use embassy_sync::blocking_mutex::Mutex;
|
||||||
use embassy_sync::waitqueue::WakerRegistration;
|
use embassy_sync::waitqueue::WakerRegistration;
|
||||||
|
use embassy_sync::zerocopy_channel;
|
||||||
|
|
||||||
pub struct State<const MTU: usize, const N_RX: usize, const N_TX: usize> {
|
pub struct State<const MTU: usize, const N_RX: usize, const N_TX: usize> {
|
||||||
rx: [PacketBuf<MTU>; N_RX],
|
rx: [PacketBuf<MTU>; N_RX],
|
||||||
@ -130,24 +130,24 @@ impl<'d, const MTU: usize> Runner<'d, MTU> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn tx_buf(&mut self) -> &mut [u8] {
|
pub async fn tx_buf(&mut self) -> &mut [u8] {
|
||||||
let p = self.tx_chan.recv().await;
|
let p = self.tx_chan.receive().await;
|
||||||
&mut p.buf[..p.len]
|
&mut p.buf[..p.len]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> {
|
pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> {
|
||||||
let p = self.tx_chan.try_recv()?;
|
let p = self.tx_chan.try_receive()?;
|
||||||
Some(&mut p.buf[..p.len])
|
Some(&mut p.buf[..p.len])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> {
|
pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> {
|
||||||
match self.tx_chan.poll_recv(cx) {
|
match self.tx_chan.poll_receive(cx) {
|
||||||
Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]),
|
Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]),
|
||||||
Poll::Pending => Poll::Pending,
|
Poll::Pending => Poll::Pending,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tx_done(&mut self) {
|
pub fn tx_done(&mut self) {
|
||||||
self.tx_chan.recv_done();
|
self.tx_chan.receive_done();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,18 +160,10 @@ impl<'d> StateRunner<'d> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_ethernet_address(&self, address: [u8; 6]) {
|
pub fn set_hardware_address(&self, address: driver::HardwareAddress) {
|
||||||
self.shared.lock(|s| {
|
self.shared.lock(|s| {
|
||||||
let s = &mut *s.borrow_mut();
|
let s = &mut *s.borrow_mut();
|
||||||
s.hardware_address = driver::HardwareAddress::Ethernet(address);
|
s.hardware_address = address;
|
||||||
s.waker.wake();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_ieee802154_address(&self, address: [u8; 8]) {
|
|
||||||
self.shared.lock(|s| {
|
|
||||||
let s = &mut *s.borrow_mut();
|
|
||||||
s.hardware_address = driver::HardwareAddress::Ieee802154(address);
|
|
||||||
s.waker.wake();
|
s.waker.wake();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -204,24 +196,24 @@ impl<'d, const MTU: usize> RxRunner<'d, MTU> {
|
|||||||
|
|
||||||
impl<'d, const MTU: usize> TxRunner<'d, MTU> {
|
impl<'d, const MTU: usize> TxRunner<'d, MTU> {
|
||||||
pub async fn tx_buf(&mut self) -> &mut [u8] {
|
pub async fn tx_buf(&mut self) -> &mut [u8] {
|
||||||
let p = self.tx_chan.recv().await;
|
let p = self.tx_chan.receive().await;
|
||||||
&mut p.buf[..p.len]
|
&mut p.buf[..p.len]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> {
|
pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> {
|
||||||
let p = self.tx_chan.try_recv()?;
|
let p = self.tx_chan.try_receive()?;
|
||||||
Some(&mut p.buf[..p.len])
|
Some(&mut p.buf[..p.len])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> {
|
pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> {
|
||||||
match self.tx_chan.poll_recv(cx) {
|
match self.tx_chan.poll_receive(cx) {
|
||||||
Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]),
|
Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]),
|
||||||
Poll::Pending => Poll::Pending,
|
Poll::Pending => Poll::Pending,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tx_done(&mut self) {
|
pub fn tx_done(&mut self) {
|
||||||
self.tx_chan.recv_done();
|
self.tx_chan.receive_done();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,11 +223,6 @@ pub fn new<'d, const MTU: usize, const N_RX: usize, const N_TX: usize>(
|
|||||||
) -> (Runner<'d, MTU>, Device<'d, MTU>) {
|
) -> (Runner<'d, MTU>, Device<'d, MTU>) {
|
||||||
let mut caps = Capabilities::default();
|
let mut caps = Capabilities::default();
|
||||||
caps.max_transmission_unit = MTU;
|
caps.max_transmission_unit = MTU;
|
||||||
caps.medium = match &hardware_address {
|
|
||||||
HardwareAddress::Ethernet(_) => Medium::Ethernet,
|
|
||||||
HardwareAddress::Ieee802154(_) => Medium::Ieee802154,
|
|
||||||
HardwareAddress::Ip => Medium::Ip,
|
|
||||||
};
|
|
||||||
|
|
||||||
// safety: this is a self-referential struct, however:
|
// safety: this is a self-referential struct, however:
|
||||||
// - it can't move while the `'d` borrow is active.
|
// - it can't move while the `'d` borrow is active.
|
||||||
@ -293,7 +280,7 @@ impl<'d, const MTU: usize> embassy_net_driver::Driver for Device<'d, MTU> {
|
|||||||
type TxToken<'a> = TxToken<'a, MTU> where Self: 'a ;
|
type TxToken<'a> = TxToken<'a, MTU> where Self: 'a ;
|
||||||
|
|
||||||
fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
|
fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
|
||||||
if self.rx.poll_recv(cx).is_ready() && self.tx.poll_send(cx).is_ready() {
|
if self.rx.poll_receive(cx).is_ready() && self.tx.poll_send(cx).is_ready() {
|
||||||
Some((RxToken { rx: self.rx.borrow() }, TxToken { tx: self.tx.borrow() }))
|
Some((RxToken { rx: self.rx.borrow() }, TxToken { tx: self.tx.borrow() }))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -337,9 +324,9 @@ impl<'a, const MTU: usize> embassy_net_driver::RxToken for RxToken<'a, MTU> {
|
|||||||
F: FnOnce(&mut [u8]) -> R,
|
F: FnOnce(&mut [u8]) -> R,
|
||||||
{
|
{
|
||||||
// NOTE(unwrap): we checked the queue wasn't full when creating the token.
|
// NOTE(unwrap): we checked the queue wasn't full when creating the token.
|
||||||
let pkt = unwrap!(self.rx.try_recv());
|
let pkt = unwrap!(self.rx.try_receive());
|
||||||
let r = f(&mut pkt.buf[..pkt.len]);
|
let r = f(&mut pkt.buf[..pkt.len]);
|
||||||
self.rx.recv_done();
|
self.rx.receive_done();
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -361,215 +348,3 @@ impl<'a, const MTU: usize> embassy_net_driver::TxToken for TxToken<'a, MTU> {
|
|||||||
r
|
r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod zerocopy_channel {
|
|
||||||
use core::cell::RefCell;
|
|
||||||
use core::future::poll_fn;
|
|
||||||
use core::marker::PhantomData;
|
|
||||||
use core::task::{Context, Poll};
|
|
||||||
|
|
||||||
use embassy_sync::blocking_mutex::raw::RawMutex;
|
|
||||||
use embassy_sync::blocking_mutex::Mutex;
|
|
||||||
use embassy_sync::waitqueue::WakerRegistration;
|
|
||||||
|
|
||||||
pub struct Channel<'a, M: RawMutex, T> {
|
|
||||||
buf: *mut T,
|
|
||||||
phantom: PhantomData<&'a mut T>,
|
|
||||||
state: Mutex<M, RefCell<State>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, M: RawMutex, T> Channel<'a, M, T> {
|
|
||||||
pub fn new(buf: &'a mut [T]) -> Self {
|
|
||||||
let len = buf.len();
|
|
||||||
assert!(len != 0);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
buf: buf.as_mut_ptr(),
|
|
||||||
phantom: PhantomData,
|
|
||||||
state: Mutex::new(RefCell::new(State {
|
|
||||||
len,
|
|
||||||
front: 0,
|
|
||||||
back: 0,
|
|
||||||
full: false,
|
|
||||||
send_waker: WakerRegistration::new(),
|
|
||||||
recv_waker: WakerRegistration::new(),
|
|
||||||
})),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn split(&mut self) -> (Sender<'_, M, T>, Receiver<'_, M, T>) {
|
|
||||||
(Sender { channel: self }, Receiver { channel: self })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Sender<'a, M: RawMutex, T> {
|
|
||||||
channel: &'a Channel<'a, M, T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, M: RawMutex, T> Sender<'a, M, T> {
|
|
||||||
pub fn borrow(&mut self) -> Sender<'_, M, T> {
|
|
||||||
Sender { channel: self.channel }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_send(&mut self) -> Option<&mut T> {
|
|
||||||
self.channel.state.lock(|s| {
|
|
||||||
let s = &mut *s.borrow_mut();
|
|
||||||
match s.push_index() {
|
|
||||||
Some(i) => Some(unsafe { &mut *self.channel.buf.add(i) }),
|
|
||||||
None => None,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn poll_send(&mut self, cx: &mut Context) -> Poll<&mut T> {
|
|
||||||
self.channel.state.lock(|s| {
|
|
||||||
let s = &mut *s.borrow_mut();
|
|
||||||
match s.push_index() {
|
|
||||||
Some(i) => Poll::Ready(unsafe { &mut *self.channel.buf.add(i) }),
|
|
||||||
None => {
|
|
||||||
s.recv_waker.register(cx.waker());
|
|
||||||
Poll::Pending
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn send(&mut self) -> &mut T {
|
|
||||||
let i = poll_fn(|cx| {
|
|
||||||
self.channel.state.lock(|s| {
|
|
||||||
let s = &mut *s.borrow_mut();
|
|
||||||
match s.push_index() {
|
|
||||||
Some(i) => Poll::Ready(i),
|
|
||||||
None => {
|
|
||||||
s.recv_waker.register(cx.waker());
|
|
||||||
Poll::Pending
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
unsafe { &mut *self.channel.buf.add(i) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_done(&mut self) {
|
|
||||||
self.channel.state.lock(|s| s.borrow_mut().push_done())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub struct Receiver<'a, M: RawMutex, T> {
|
|
||||||
channel: &'a Channel<'a, M, T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, M: RawMutex, T> Receiver<'a, M, T> {
|
|
||||||
pub fn borrow(&mut self) -> Receiver<'_, M, T> {
|
|
||||||
Receiver { channel: self.channel }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_recv(&mut self) -> Option<&mut T> {
|
|
||||||
self.channel.state.lock(|s| {
|
|
||||||
let s = &mut *s.borrow_mut();
|
|
||||||
match s.pop_index() {
|
|
||||||
Some(i) => Some(unsafe { &mut *self.channel.buf.add(i) }),
|
|
||||||
None => None,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn poll_recv(&mut self, cx: &mut Context) -> Poll<&mut T> {
|
|
||||||
self.channel.state.lock(|s| {
|
|
||||||
let s = &mut *s.borrow_mut();
|
|
||||||
match s.pop_index() {
|
|
||||||
Some(i) => Poll::Ready(unsafe { &mut *self.channel.buf.add(i) }),
|
|
||||||
None => {
|
|
||||||
s.send_waker.register(cx.waker());
|
|
||||||
Poll::Pending
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn recv(&mut self) -> &mut T {
|
|
||||||
let i = poll_fn(|cx| {
|
|
||||||
self.channel.state.lock(|s| {
|
|
||||||
let s = &mut *s.borrow_mut();
|
|
||||||
match s.pop_index() {
|
|
||||||
Some(i) => Poll::Ready(i),
|
|
||||||
None => {
|
|
||||||
s.send_waker.register(cx.waker());
|
|
||||||
Poll::Pending
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
unsafe { &mut *self.channel.buf.add(i) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn recv_done(&mut self) {
|
|
||||||
self.channel.state.lock(|s| s.borrow_mut().pop_done())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct State {
|
|
||||||
len: usize,
|
|
||||||
|
|
||||||
/// Front index. Always 0..=(N-1)
|
|
||||||
front: usize,
|
|
||||||
/// Back index. Always 0..=(N-1).
|
|
||||||
back: usize,
|
|
||||||
|
|
||||||
/// Used to distinguish "empty" and "full" cases when `front == back`.
|
|
||||||
/// May only be `true` if `front == back`, always `false` otherwise.
|
|
||||||
full: bool,
|
|
||||||
|
|
||||||
send_waker: WakerRegistration,
|
|
||||||
recv_waker: WakerRegistration,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl State {
|
|
||||||
fn increment(&self, i: usize) -> usize {
|
|
||||||
if i + 1 == self.len {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
i + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_full(&self) -> bool {
|
|
||||||
self.full
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_empty(&self) -> bool {
|
|
||||||
self.front == self.back && !self.full
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_index(&mut self) -> Option<usize> {
|
|
||||||
match self.is_full() {
|
|
||||||
true => None,
|
|
||||||
false => Some(self.back),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_done(&mut self) {
|
|
||||||
assert!(!self.is_full());
|
|
||||||
self.back = self.increment(self.back);
|
|
||||||
if self.back == self.front {
|
|
||||||
self.full = true;
|
|
||||||
}
|
|
||||||
self.send_waker.wake();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pop_index(&mut self) -> Option<usize> {
|
|
||||||
match self.is_empty() {
|
|
||||||
true => None,
|
|
||||||
false => Some(self.front),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pop_done(&mut self) {
|
|
||||||
assert!(!self.is_empty());
|
|
||||||
self.front = self.increment(self.front);
|
|
||||||
self.full = false;
|
|
||||||
self.recv_waker.wake();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
17
embassy-net-driver/CHANGELOG.md
Normal file
17
embassy-net-driver/CHANGELOG.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## 0.2.0 - 2023-10-18
|
||||||
|
|
||||||
|
- Added support for IEEE 802.15.4 mediums.
|
||||||
|
- Added `Driver::hardware_address()`, `HardwareAddress`.
|
||||||
|
- Removed `Medium` enum. The medium is deduced out of the hardware address.
|
||||||
|
- Removed `Driver::ethernet_address()`. Replacement is `hardware_address()`.
|
||||||
|
|
||||||
|
## 0.1.0 - 2023-06-29
|
||||||
|
|
||||||
|
- First release
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "embassy-net-driver"
|
name = "embassy-net-driver"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "Driver trait for the `embassy-net` async TCP/IP network stack."
|
description = "Driver trait for the `embassy-net` async TCP/IP network stack."
|
||||||
|
@ -7,12 +7,23 @@ use core::task::Context;
|
|||||||
/// Representation of an hardware address, such as an Ethernet address or an IEEE802.15.4 address.
|
/// Representation of an hardware address, such as an Ethernet address or an IEEE802.15.4 address.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
#[non_exhaustive]
|
||||||
pub enum HardwareAddress {
|
pub enum HardwareAddress {
|
||||||
/// A six-octet Ethernet address
|
/// Ethernet medium, with a A six-octet Ethernet address.
|
||||||
|
///
|
||||||
|
/// Devices of this type send and receive Ethernet frames,
|
||||||
|
/// and interfaces using it must do neighbor discovery via ARP or NDISC.
|
||||||
|
///
|
||||||
|
/// Examples of devices of this type are Ethernet, WiFi (802.11), Linux `tap`, and VPNs in tap (layer 2) mode.
|
||||||
Ethernet([u8; 6]),
|
Ethernet([u8; 6]),
|
||||||
/// An eight-octet IEEE802.15.4 address
|
/// 6LoWPAN over IEEE802.15.4, with an eight-octet address.
|
||||||
Ieee802154([u8; 8]),
|
Ieee802154([u8; 8]),
|
||||||
/// Indicates that a Driver is IP-native, and has no hardware address
|
/// Indicates that a Driver is IP-native, and has no hardware address.
|
||||||
|
///
|
||||||
|
/// Devices of this type send and receive IP frames, without an
|
||||||
|
/// Ethernet header. MAC addresses are not used, and no neighbor discovery (ARP, NDISC) is done.
|
||||||
|
///
|
||||||
|
/// Examples of devices of this type are the Linux `tun`, PPP interfaces, VPNs in tun (layer 3) mode.
|
||||||
Ip,
|
Ip,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,6 +75,10 @@ pub trait Driver {
|
|||||||
fn capabilities(&self) -> Capabilities;
|
fn capabilities(&self) -> Capabilities;
|
||||||
|
|
||||||
/// Get the device's hardware address.
|
/// Get the device's hardware address.
|
||||||
|
///
|
||||||
|
/// The returned hardware address also determines the "medium" of this driver. This indicates
|
||||||
|
/// what kind of packet the sent/received bytes are, and determines some behaviors of
|
||||||
|
/// the interface. For example, ARP/NDISC address resolution is only done for Ethernet mediums.
|
||||||
fn hardware_address(&self) -> HardwareAddress;
|
fn hardware_address(&self) -> HardwareAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,13 +139,6 @@ pub trait TxToken {
|
|||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct Capabilities {
|
pub struct Capabilities {
|
||||||
/// Medium of the device.
|
|
||||||
///
|
|
||||||
/// This indicates what kind of packet the sent/received bytes are, and determines
|
|
||||||
/// some behaviors of Interface. For example, ARP/NDISC address resolution is only done
|
|
||||||
/// for Ethernet mediums.
|
|
||||||
pub medium: Medium,
|
|
||||||
|
|
||||||
/// Maximum transmission unit.
|
/// Maximum transmission unit.
|
||||||
///
|
///
|
||||||
/// The network device is unable to send or receive frames larger than the value returned
|
/// The network device is unable to send or receive frames larger than the value returned
|
||||||
@ -161,32 +169,6 @@ pub struct Capabilities {
|
|||||||
pub checksum: ChecksumCapabilities,
|
pub checksum: ChecksumCapabilities,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type of medium of a device.
|
|
||||||
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
|
||||||
pub enum Medium {
|
|
||||||
/// Ethernet medium. Devices of this type send and receive Ethernet frames,
|
|
||||||
/// and interfaces using it must do neighbor discovery via ARP or NDISC.
|
|
||||||
///
|
|
||||||
/// Examples of devices of this type are Ethernet, WiFi (802.11), Linux `tap`, and VPNs in tap (layer 2) mode.
|
|
||||||
Ethernet,
|
|
||||||
|
|
||||||
/// IP medium. Devices of this type send and receive IP frames, without an
|
|
||||||
/// Ethernet header. MAC addresses are not used, and no neighbor discovery (ARP, NDISC) is done.
|
|
||||||
///
|
|
||||||
/// Examples of devices of this type are the Linux `tun`, PPP interfaces, VPNs in tun (layer 3) mode.
|
|
||||||
Ip,
|
|
||||||
|
|
||||||
/// IEEE 802_15_4 medium
|
|
||||||
Ieee802154,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Medium {
|
|
||||||
fn default() -> Medium {
|
|
||||||
Medium::Ethernet
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A description of checksum behavior for every supported protocol.
|
/// A description of checksum behavior for every supported protocol.
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
@ -10,8 +10,8 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
embedded-hal = { version = "1.0.0-rc.1" }
|
embedded-hal = { version = "1.0.0-rc.1" }
|
||||||
embedded-hal-async = { version = "=1.0.0-rc.1" }
|
embedded-hal-async = { version = "=1.0.0-rc.1" }
|
||||||
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
|
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
|
||||||
embassy-time = { version = "0.1.3", path = "../embassy-time" }
|
embassy-time = { version = "0.1.5", path = "../embassy-time" }
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
|
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
#![allow(unused_macros)]
|
#![allow(unused_macros)]
|
||||||
|
|
||||||
|
use core::fmt::{Debug, Display, LowerHex};
|
||||||
|
|
||||||
#[cfg(all(feature = "defmt", feature = "log"))]
|
#[cfg(all(feature = "defmt", feature = "log"))]
|
||||||
compile_error!("You may not enable both `defmt` and `log` features.");
|
compile_error!("You may not enable both `defmt` and `log` features.");
|
||||||
|
|
||||||
@ -81,14 +83,17 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
{
|
::core::unreachable!($($x)*)
|
||||||
#[cfg(not(feature = "defmt"))]
|
};
|
||||||
::core::unreachable!($($x)*);
|
}
|
||||||
#[cfg(feature = "defmt")]
|
|
||||||
::defmt::unreachable!($($x)*);
|
#[cfg(feature = "defmt")]
|
||||||
}
|
macro_rules! unreachable {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
::defmt::unreachable!($($x)*)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub(crate) 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -19,7 +19,7 @@ mod traits;
|
|||||||
use core::cmp;
|
use core::cmp;
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
|
|
||||||
use embassy_net_driver::{Capabilities, HardwareAddress, LinkState, Medium};
|
use embassy_net_driver::{Capabilities, HardwareAddress, LinkState};
|
||||||
use embassy_time::Duration;
|
use embassy_time::Duration;
|
||||||
use embedded_hal::digital::OutputPin;
|
use embedded_hal::digital::OutputPin;
|
||||||
use embedded_hal::spi::{Operation, SpiDevice};
|
use embedded_hal::spi::{Operation, SpiDevice};
|
||||||
@ -194,10 +194,15 @@ where
|
|||||||
self.bit_field_set(common::Register::ECON1, common::ECON1::mask().rxen());
|
self.bit_field_set(common::Register::ECON1, common::ECON1::mask().rxen());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the device's MAC address
|
||||||
|
pub fn address(&self) -> [u8; 6] {
|
||||||
|
self.mac_addr
|
||||||
|
}
|
||||||
|
|
||||||
/// Flushes the transmit buffer, ensuring all pending transmissions have completed
|
/// Flushes the transmit buffer, ensuring all pending transmissions have completed
|
||||||
/// NOTE: The returned packet *must* be `read` or `ignore`-d, otherwise this method will always
|
/// NOTE: The returned packet *must* be `read` or `ignore`-d, otherwise this method will always
|
||||||
/// return `None` on subsequent invocations
|
/// return `None` on subsequent invocations
|
||||||
pub fn receive<'a>(&mut self, buf: &'a mut [u8]) -> Option<&'a mut [u8]> {
|
pub fn receive(&mut self, buf: &mut [u8]) -> Option<usize> {
|
||||||
if self.pending_packets() == 0 {
|
if self.pending_packets() == 0 {
|
||||||
// Errata #6: we can't rely on PKTIF so we check PKTCNT
|
// Errata #6: we can't rely on PKTIF so we check PKTCNT
|
||||||
return None;
|
return None;
|
||||||
@ -241,7 +246,7 @@ where
|
|||||||
|
|
||||||
self.next_packet = next_packet;
|
self.next_packet = next_packet;
|
||||||
|
|
||||||
Some(&mut buf[..len as usize])
|
Some(len as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait_tx_ready(&mut self) {
|
fn wait_tx_ready(&mut self) {
|
||||||
@ -642,9 +647,8 @@ where
|
|||||||
fn receive(&mut self, cx: &mut core::task::Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
|
fn receive(&mut self, cx: &mut core::task::Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
|
||||||
let rx_buf = unsafe { &mut RX_BUF };
|
let rx_buf = unsafe { &mut RX_BUF };
|
||||||
let tx_buf = unsafe { &mut TX_BUF };
|
let tx_buf = unsafe { &mut TX_BUF };
|
||||||
if let Some(pkt) = self.receive(rx_buf) {
|
if let Some(n) = self.receive(rx_buf) {
|
||||||
let n = pkt.len();
|
Some((RxToken { buf: &mut rx_buf[..n] }, TxToken { buf: tx_buf, eth: self }))
|
||||||
Some((RxToken { buf: &mut pkt[..n] }, TxToken { buf: tx_buf, eth: self }))
|
|
||||||
} else {
|
} else {
|
||||||
cx.waker().wake_by_ref();
|
cx.waker().wake_by_ref();
|
||||||
None
|
None
|
||||||
@ -667,7 +671,6 @@ where
|
|||||||
fn capabilities(&self) -> Capabilities {
|
fn capabilities(&self) -> Capabilities {
|
||||||
let mut caps = Capabilities::default();
|
let mut caps = Capabilities::default();
|
||||||
caps.max_transmission_unit = MTU;
|
caps.max_transmission_unit = MTU;
|
||||||
caps.medium = Medium::Ethernet;
|
|
||||||
caps
|
caps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,10 +7,10 @@ edition = "2021"
|
|||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
log = { version = "0.4.14", optional = true }
|
log = { version = "0.4.14", optional = true }
|
||||||
|
|
||||||
embassy-time = { version = "0.1.3", path = "../embassy-time" }
|
embassy-time = { version = "0.1.5", path = "../embassy-time" }
|
||||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync"}
|
embassy-sync = { version = "0.4.0", path = "../embassy-sync"}
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
|
||||||
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"}
|
embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"}
|
||||||
|
|
||||||
embedded-hal = { version = "1.0.0-rc.1" }
|
embedded-hal = { version = "1.0.0-rc.1" }
|
||||||
embedded-hal-async = { version = "=1.0.0-rc.1" }
|
embedded-hal-async = { version = "=1.0.0-rc.1" }
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use ch::driver::LinkState;
|
|
||||||
use embassy_net_driver_channel as ch;
|
use embassy_net_driver_channel as ch;
|
||||||
|
use embassy_net_driver_channel::driver::{HardwareAddress, LinkState};
|
||||||
use heapless::String;
|
use heapless::String;
|
||||||
|
|
||||||
use crate::ioctl::Shared;
|
use crate::ioctl::Shared;
|
||||||
@ -19,6 +19,8 @@ pub struct Control<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
enum WifiMode {
|
enum WifiMode {
|
||||||
None = 0,
|
None = 0,
|
||||||
Sta = 1,
|
Sta = 1,
|
||||||
@ -26,6 +28,18 @@ enum WifiMode {
|
|||||||
ApSta = 3,
|
ApSta = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use proto::CtrlWifiSecProt as Security;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub struct Status {
|
||||||
|
pub ssid: String<32>,
|
||||||
|
pub bssid: [u8; 6],
|
||||||
|
pub rssi: i32,
|
||||||
|
pub channel: u32,
|
||||||
|
pub security: Security,
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! ioctl {
|
macro_rules! ioctl {
|
||||||
($self:ident, $req_variant:ident, $resp_variant:ident, $req:ident, $resp:ident) => {
|
($self:ident, $req_variant:ident, $resp_variant:ident, $req:ident, $resp:ident) => {
|
||||||
let mut msg = proto::CtrlMsg {
|
let mut msg = proto::CtrlMsg {
|
||||||
@ -34,7 +48,9 @@ macro_rules! ioctl {
|
|||||||
payload: Some(proto::CtrlMsgPayload::$req_variant($req)),
|
payload: Some(proto::CtrlMsgPayload::$req_variant($req)),
|
||||||
};
|
};
|
||||||
$self.ioctl(&mut msg).await?;
|
$self.ioctl(&mut msg).await?;
|
||||||
let Some(proto::CtrlMsgPayload::$resp_variant($resp)) = msg.payload else {
|
#[allow(unused_mut)]
|
||||||
|
let Some(proto::CtrlMsgPayload::$resp_variant(mut $resp)) = msg.payload
|
||||||
|
else {
|
||||||
warn!("unexpected response variant");
|
warn!("unexpected response variant");
|
||||||
return Err(Error::Internal);
|
return Err(Error::Internal);
|
||||||
};
|
};
|
||||||
@ -61,11 +77,24 @@ impl<'a> Control<'a> {
|
|||||||
|
|
||||||
let mac_addr = self.get_mac_addr().await?;
|
let mac_addr = self.get_mac_addr().await?;
|
||||||
debug!("mac addr: {:02x}", mac_addr);
|
debug!("mac addr: {:02x}", mac_addr);
|
||||||
self.state_ch.set_ethernet_address(mac_addr);
|
self.state_ch.set_hardware_address(HardwareAddress::Ethernet(mac_addr));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_status(&mut self) -> Result<Status, Error> {
|
||||||
|
let req = proto::CtrlMsgReqGetApConfig {};
|
||||||
|
ioctl!(self, ReqGetApConfig, RespGetApConfig, req, resp);
|
||||||
|
trim_nulls(&mut resp.ssid);
|
||||||
|
Ok(Status {
|
||||||
|
ssid: resp.ssid,
|
||||||
|
bssid: parse_mac(&resp.bssid)?,
|
||||||
|
rssi: resp.rssi as _,
|
||||||
|
channel: resp.chnl,
|
||||||
|
security: resp.sec_prot,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn connect(&mut self, ssid: &str, password: &str) -> Result<(), Error> {
|
pub async fn connect(&mut self, ssid: &str, password: &str) -> Result<(), Error> {
|
||||||
let req = proto::CtrlMsgReqConnectAp {
|
let req = proto::CtrlMsgReqConnectAp {
|
||||||
ssid: String::from(ssid),
|
ssid: String::from(ssid),
|
||||||
@ -98,27 +127,7 @@ impl<'a> Control<'a> {
|
|||||||
mode: WifiMode::Sta as _,
|
mode: WifiMode::Sta as _,
|
||||||
};
|
};
|
||||||
ioctl!(self, ReqGetMacAddress, RespGetMacAddress, req, resp);
|
ioctl!(self, ReqGetMacAddress, RespGetMacAddress, req, resp);
|
||||||
|
parse_mac(&resp.mac)
|
||||||
// WHY IS THIS A STRING? WHYYYY
|
|
||||||
fn nibble_from_hex(b: u8) -> u8 {
|
|
||||||
match b {
|
|
||||||
b'0'..=b'9' => b - b'0',
|
|
||||||
b'a'..=b'f' => b + 0xa - b'a',
|
|
||||||
b'A'..=b'F' => b + 0xa - b'A',
|
|
||||||
_ => panic!("invalid hex digit {}", b),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mac = resp.mac.as_bytes();
|
|
||||||
let mut res = [0; 6];
|
|
||||||
if mac.len() != 17 {
|
|
||||||
warn!("unexpected MAC respnse length");
|
|
||||||
return Err(Error::Internal);
|
|
||||||
}
|
|
||||||
for (i, b) in res.iter_mut().enumerate() {
|
|
||||||
*b = (nibble_from_hex(mac[i * 3]) << 4) | nibble_from_hex(mac[i * 3 + 1])
|
|
||||||
}
|
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_wifi_mode(&mut self, mode: u32) -> Result<(), Error> {
|
async fn set_wifi_mode(&mut self, mode: u32) -> Result<(), Error> {
|
||||||
@ -167,3 +176,35 @@ impl<'a> Control<'a> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WHY IS THIS A STRING? WHYYYY
|
||||||
|
fn parse_mac(mac: &str) -> Result<[u8; 6], Error> {
|
||||||
|
fn nibble_from_hex(b: u8) -> Result<u8, Error> {
|
||||||
|
match b {
|
||||||
|
b'0'..=b'9' => Ok(b - b'0'),
|
||||||
|
b'a'..=b'f' => Ok(b + 0xa - b'a'),
|
||||||
|
b'A'..=b'F' => Ok(b + 0xa - b'A'),
|
||||||
|
_ => {
|
||||||
|
warn!("invalid hex digit {}", b);
|
||||||
|
Err(Error::Internal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mac = mac.as_bytes();
|
||||||
|
let mut res = [0; 6];
|
||||||
|
if mac.len() != 17 {
|
||||||
|
warn!("unexpected MAC length");
|
||||||
|
return Err(Error::Internal);
|
||||||
|
}
|
||||||
|
for (i, b) in res.iter_mut().enumerate() {
|
||||||
|
*b = (nibble_from_hex(mac[i * 3])? << 4) | nibble_from_hex(mac[i * 3 + 1])?
|
||||||
|
}
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trim_nulls<const N: usize>(s: &mut String<N>) {
|
||||||
|
while s.chars().rev().next() == Some(0 as char) {
|
||||||
|
s.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -93,7 +93,7 @@ macro_rules! unreachable {
|
|||||||
#[cfg(feature = "defmt")]
|
#[cfg(feature = "defmt")]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
::defmt::unreachable!($($x)*);
|
::defmt::unreachable!($($x)*)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,7 +229,8 @@ impl<T, E> Try for Result<T, E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Bytes<'a>(pub &'a [u8]);
|
#[allow(unused)]
|
||||||
|
pub(crate) struct Bytes<'a>(pub &'a [u8]);
|
||||||
|
|
||||||
impl<'a> Debug for Bytes<'a> {
|
impl<'a> Debug for Bytes<'a> {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
@ -169,9 +169,9 @@ where
|
|||||||
pub async fn run(mut self) -> ! {
|
pub async fn run(mut self) -> ! {
|
||||||
debug!("resetting...");
|
debug!("resetting...");
|
||||||
self.reset.set_low().unwrap();
|
self.reset.set_low().unwrap();
|
||||||
Timer::after(Duration::from_millis(100)).await;
|
Timer::after_millis(100).await;
|
||||||
self.reset.set_high().unwrap();
|
self.reset.set_high().unwrap();
|
||||||
Timer::after(Duration::from_millis(1000)).await;
|
Timer::after_millis(1000).await;
|
||||||
|
|
||||||
let mut tx_buf = [0u8; MAX_SPI_BUFFER_SIZE];
|
let mut tx_buf = [0u8; MAX_SPI_BUFFER_SIZE];
|
||||||
let mut rx_buf = [0u8; MAX_SPI_BUFFER_SIZE];
|
let mut rx_buf = [0u8; MAX_SPI_BUFFER_SIZE];
|
||||||
|
@ -15,11 +15,11 @@ log = ["dep:log", "ppproto/log"]
|
|||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
log = { version = "0.4.14", optional = true }
|
log = { version = "0.4.14", optional = true }
|
||||||
|
|
||||||
embedded-io-async = { version = "0.5.0" }
|
embedded-io-async = { version = "0.6.0" }
|
||||||
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
|
embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" }
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
ppproto = { version = "0.1.1"}
|
ppproto = { version = "0.1.2"}
|
||||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.4.0", path = "../embassy-sync" }
|
||||||
|
|
||||||
[package.metadata.embassy_docs]
|
[package.metadata.embassy_docs]
|
||||||
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-ppp-v$VERSION/embassy-net-ppp/src/"
|
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-ppp-v$VERSION/embassy-net-ppp/src/"
|
||||||
|
@ -93,7 +93,7 @@ macro_rules! unreachable {
|
|||||||
#[cfg(feature = "defmt")]
|
#[cfg(feature = "defmt")]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
::defmt::unreachable!($($x)*);
|
::defmt::unreachable!($($x)*)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,7 +229,8 @@ impl<T, E> Try for Result<T, E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Bytes<'a>(pub &'a [u8]);
|
#[allow(unused)]
|
||||||
|
pub(crate) struct Bytes<'a>(pub &'a [u8]);
|
||||||
|
|
||||||
impl<'a> Debug for Bytes<'a> {
|
impl<'a> Debug for Bytes<'a> {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
@ -11,7 +11,7 @@ use core::mem::MaybeUninit;
|
|||||||
use embassy_futures::select::{select, Either};
|
use embassy_futures::select::{select, Either};
|
||||||
use embassy_net_driver_channel as ch;
|
use embassy_net_driver_channel as ch;
|
||||||
use embassy_net_driver_channel::driver::LinkState;
|
use embassy_net_driver_channel::driver::LinkState;
|
||||||
use embedded_io_async::{BufRead, Write, WriteAllError};
|
use embedded_io_async::{BufRead, Write};
|
||||||
use ppproto::pppos::{BufferFullError, PPPoS, PPPoSAction};
|
use ppproto::pppos::{BufferFullError, PPPoS, PPPoSAction};
|
||||||
pub use ppproto::{Config, Ipv4Status};
|
pub use ppproto::{Config, Ipv4Status};
|
||||||
|
|
||||||
@ -49,19 +49,10 @@ pub enum RunError<E> {
|
|||||||
Read(E),
|
Read(E),
|
||||||
/// Writing to the serial port failed.
|
/// Writing to the serial port failed.
|
||||||
Write(E),
|
Write(E),
|
||||||
/// Writing to the serial port wrote zero bytes, indicating it can't accept more data.
|
|
||||||
WriteZero,
|
|
||||||
/// Writing to the serial got EOF.
|
/// Writing to the serial got EOF.
|
||||||
Eof,
|
Eof,
|
||||||
}
|
/// PPP protocol was terminated by the peer
|
||||||
|
Terminated,
|
||||||
impl<E> From<WriteAllError<E>> for RunError<E> {
|
|
||||||
fn from(value: WriteAllError<E>) -> Self {
|
|
||||||
match value {
|
|
||||||
WriteAllError::Other(e) => Self::Write(e),
|
|
||||||
WriteAllError::WriteZero => Self::WriteZero,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d> Runner<'d> {
|
impl<'d> Runner<'d> {
|
||||||
@ -123,11 +114,14 @@ impl<'d> Runner<'d> {
|
|||||||
buf[..pkt.len()].copy_from_slice(pkt);
|
buf[..pkt.len()].copy_from_slice(pkt);
|
||||||
rx_chan.rx_done(pkt.len());
|
rx_chan.rx_done(pkt.len());
|
||||||
}
|
}
|
||||||
PPPoSAction::Transmit(n) => rw.write_all(&tx_buf[..n]).await?,
|
PPPoSAction::Transmit(n) => rw.write_all(&tx_buf[..n]).await.map_err(RunError::Write)?,
|
||||||
}
|
}
|
||||||
|
|
||||||
let status = ppp.status();
|
let status = ppp.status();
|
||||||
match status.phase {
|
match status.phase {
|
||||||
|
ppproto::Phase::Dead => {
|
||||||
|
return Err(RunError::Terminated);
|
||||||
|
}
|
||||||
ppproto::Phase::Open => {
|
ppproto::Phase::Open => {
|
||||||
if !was_up {
|
if !was_up {
|
||||||
on_ipv4_up(status.ipv4.unwrap());
|
on_ipv4_up(status.ipv4.unwrap());
|
||||||
@ -143,7 +137,7 @@ impl<'d> Runner<'d> {
|
|||||||
}
|
}
|
||||||
Either::Second(pkt) => {
|
Either::Second(pkt) => {
|
||||||
match ppp.send(pkt, &mut tx_buf) {
|
match ppp.send(pkt, &mut tx_buf) {
|
||||||
Ok(n) => rw.write_all(&tx_buf[..n]).await?,
|
Ok(n) => rw.write_all(&tx_buf[..n]).await.map_err(RunError::Write)?,
|
||||||
Err(BufferFullError) => unreachable!(),
|
Err(BufferFullError) => unreachable!(),
|
||||||
}
|
}
|
||||||
tx_chan.tx_done();
|
tx_chan.tx_done();
|
||||||
|
@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
|
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
|
||||||
async-io = "1.6.0"
|
async-io = "1.6.0"
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
libc = "0.2.101"
|
libc = "0.2.101"
|
||||||
|
@ -10,8 +10,8 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
embedded-hal = { version = "1.0.0-rc.1" }
|
embedded-hal = { version = "1.0.0-rc.1" }
|
||||||
embedded-hal-async = { version = "=1.0.0-rc.1" }
|
embedded-hal-async = { version = "=1.0.0-rc.1" }
|
||||||
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
|
embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" }
|
||||||
embassy-time = { version = "0.1.3", path = "../embassy-time" }
|
embassy-time = { version = "0.1.5", path = "../embassy-time" }
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
|
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
//! [`embassy-net`](https://crates.io/crates/embassy-net) driver for WIZnet ethernet chips.
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(async_fn_in_trait)]
|
#![feature(async_fn_in_trait)]
|
||||||
|
#![doc = include_str!("../README.md")]
|
||||||
|
|
||||||
pub mod chip;
|
pub mod chip;
|
||||||
mod device;
|
mod device;
|
||||||
|
|
||||||
use embassy_futures::select::{select, Either};
|
use embassy_futures::select::{select3, Either3};
|
||||||
use embassy_net_driver_channel as ch;
|
use embassy_net_driver_channel as ch;
|
||||||
use embassy_net_driver_channel::driver::LinkState;
|
use embassy_net_driver_channel::driver::LinkState;
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Ticker, Timer};
|
||||||
use embedded_hal::digital::OutputPin;
|
use embedded_hal::digital::OutputPin;
|
||||||
use embedded_hal_async::digital::Wait;
|
use embedded_hal_async::digital::Wait;
|
||||||
use embedded_hal_async::spi::SpiDevice;
|
use embedded_hal_async::spi::SpiDevice;
|
||||||
@ -49,32 +49,34 @@ pub struct Runner<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> {
|
|||||||
impl<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, C, SPI, INT, RST> {
|
impl<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, C, SPI, INT, RST> {
|
||||||
pub async fn run(mut self) -> ! {
|
pub async fn run(mut self) -> ! {
|
||||||
let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split();
|
let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split();
|
||||||
|
let mut tick = Ticker::every(Duration::from_millis(500));
|
||||||
loop {
|
loop {
|
||||||
if self.mac.is_link_up().await {
|
match select3(
|
||||||
state_chan.set_link_state(LinkState::Up);
|
async {
|
||||||
loop {
|
self.int.wait_for_low().await.ok();
|
||||||
match select(
|
rx_chan.rx_buf().await
|
||||||
async {
|
},
|
||||||
self.int.wait_for_low().await.ok();
|
tx_chan.tx_buf(),
|
||||||
rx_chan.rx_buf().await
|
tick.next(),
|
||||||
},
|
)
|
||||||
tx_chan.tx_buf(),
|
.await
|
||||||
)
|
{
|
||||||
.await
|
Either3::First(p) => {
|
||||||
{
|
if let Ok(n) = self.mac.read_frame(p).await {
|
||||||
Either::First(p) => {
|
rx_chan.rx_done(n);
|
||||||
if let Ok(n) = self.mac.read_frame(p).await {
|
}
|
||||||
rx_chan.rx_done(n);
|
}
|
||||||
}
|
Either3::Second(p) => {
|
||||||
}
|
self.mac.write_frame(p).await.ok();
|
||||||
Either::Second(p) => {
|
tx_chan.tx_done();
|
||||||
self.mac.write_frame(p).await.ok();
|
}
|
||||||
tx_chan.tx_done();
|
Either3::Third(()) => {
|
||||||
}
|
if self.mac.is_link_up().await {
|
||||||
|
state_chan.set_link_state(LinkState::Up);
|
||||||
|
} else {
|
||||||
|
state_chan.set_link_state(LinkState::Down);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
state_chan.set_link_state(LinkState::Down);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,12 +97,12 @@ pub async fn new<'a, const N_RX: usize, const N_TX: usize, C: Chip, SPI: SpiDevi
|
|||||||
// Reset the chip.
|
// Reset the chip.
|
||||||
reset.set_low().ok();
|
reset.set_low().ok();
|
||||||
// Ensure the reset is registered.
|
// Ensure the reset is registered.
|
||||||
Timer::after(Duration::from_millis(1)).await;
|
Timer::after_millis(1).await;
|
||||||
reset.set_high().ok();
|
reset.set_high().ok();
|
||||||
|
|
||||||
// Wait for PLL lock. Some chips are slower than others.
|
// Wait for PLL lock. Some chips are slower than others.
|
||||||
// Slowest is w5100s which is 100ms, so let's just wait that.
|
// Slowest is w5100s which is 100ms, so let's just wait that.
|
||||||
Timer::after(Duration::from_millis(100)).await;
|
Timer::after_millis(100).await;
|
||||||
|
|
||||||
let mac = WiznetDevice::new(spi_dev, mac_addr).await.unwrap();
|
let mac = WiznetDevice::new(spi_dev, mac_addr).await.unwrap();
|
||||||
|
|
||||||
|
34
embassy-net/CHANGELOG.md
Normal file
34
embassy-net/CHANGELOG.md
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## 0.2.1 - 2023-10-31
|
||||||
|
|
||||||
|
- Re-add impl_trait_projections
|
||||||
|
- Fix: Reset DHCP socket when the link up is detected
|
||||||
|
|
||||||
|
## 0.2.0 - 2023-10-18
|
||||||
|
|
||||||
|
- Re-export `smoltcp::wire::IpEndpoint`
|
||||||
|
- Add poll functions on UdpSocket
|
||||||
|
- Make dual-stack work in embassy-net
|
||||||
|
- Fix multicast support
|
||||||
|
- Allow ethernet and 802.15.4 to coexist
|
||||||
|
- Add IEEE802.15.4 address to embassy net Stack
|
||||||
|
- Use HardwareAddress in Driver
|
||||||
|
- Add async versions of smoltcp's `send` and `recv` closure based API
|
||||||
|
- add error translation to tcp errors
|
||||||
|
- Forward TCP/UDP socket capacity impls
|
||||||
|
- allow changing IP config at runtime
|
||||||
|
- allow non-'static drivers
|
||||||
|
- Remove impl_trait_projections
|
||||||
|
- update embedded-io, embedded-nal-async
|
||||||
|
- add support for dhcp hostname option
|
||||||
|
- Wake stack's task after queueing a DNS query
|
||||||
|
|
||||||
|
## 0.1.0 - 2023-06-29
|
||||||
|
|
||||||
|
- First release
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "embassy-net"
|
name = "embassy-net"
|
||||||
version = "0.1.0"
|
version = "0.2.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "Async TCP/IP network stack for embedded systems"
|
description = "Async TCP/IP network stack for embedded systems"
|
||||||
@ -33,6 +33,7 @@ udp = ["smoltcp/socket-udp"]
|
|||||||
tcp = ["smoltcp/socket-tcp"]
|
tcp = ["smoltcp/socket-tcp"]
|
||||||
dns = ["smoltcp/socket-dns", "smoltcp/proto-dns"]
|
dns = ["smoltcp/socket-dns", "smoltcp/proto-dns"]
|
||||||
dhcpv4 = ["proto-ipv4", "medium-ethernet", "smoltcp/socket-dhcpv4"]
|
dhcpv4 = ["proto-ipv4", "medium-ethernet", "smoltcp/socket-dhcpv4"]
|
||||||
|
dhcpv4-hostname = ["dhcpv4"]
|
||||||
proto-ipv4 = ["smoltcp/proto-ipv4"]
|
proto-ipv4 = ["smoltcp/proto-ipv4"]
|
||||||
proto-ipv6 = ["smoltcp/proto-ipv6"]
|
proto-ipv6 = ["smoltcp/proto-ipv6"]
|
||||||
medium-ethernet = ["smoltcp/medium-ethernet"]
|
medium-ethernet = ["smoltcp/medium-ethernet"]
|
||||||
@ -50,10 +51,10 @@ smoltcp = { version = "0.10.0", default-features = false, features = [
|
|||||||
"async",
|
"async",
|
||||||
] }
|
] }
|
||||||
|
|
||||||
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
|
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
|
||||||
embassy-time = { version = "0.1.3", path = "../embassy-time" }
|
embassy-time = { version = "0.1.5", path = "../embassy-time" }
|
||||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.4.0", path = "../embassy-sync" }
|
||||||
embedded-io-async = { version = "0.5.0", optional = true }
|
embedded-io-async = { version = "0.6.0", optional = true }
|
||||||
|
|
||||||
managed = { version = "0.8.0", default-features = false, features = [ "map" ] }
|
managed = { version = "0.8.0", default-features = false, features = [ "map" ] }
|
||||||
heapless = { version = "0.7.5", default-features = false }
|
heapless = { version = "0.7.5", default-features = false }
|
||||||
@ -62,5 +63,4 @@ generic-array = { version = "0.14.4", default-features = false }
|
|||||||
stable_deref_trait = { version = "1.2.0", default-features = false }
|
stable_deref_trait = { version = "1.2.0", default-features = false }
|
||||||
futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] }
|
futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] }
|
||||||
atomic-pool = "1.0"
|
atomic-pool = "1.0"
|
||||||
embedded-nal-async = { version = "0.5.0", optional = true }
|
embedded-nal-async = { version = "0.6.0", optional = true }
|
||||||
atomic-polyfill = { version = "1.0" }
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use core::task::Context;
|
use core::task::Context;
|
||||||
|
|
||||||
use embassy_net_driver::{Capabilities, Checksum, Driver, Medium, RxToken, TxToken};
|
use embassy_net_driver::{Capabilities, Checksum, Driver, RxToken, TxToken};
|
||||||
use smoltcp::phy;
|
use smoltcp::phy::{self, Medium};
|
||||||
use smoltcp::time::Instant;
|
use smoltcp::time::Instant;
|
||||||
|
|
||||||
pub(crate) struct DriverAdapter<'d, 'c, T>
|
pub(crate) struct DriverAdapter<'d, 'c, T>
|
||||||
@ -11,6 +11,7 @@ where
|
|||||||
// must be Some when actually using this to rx/tx
|
// must be Some when actually using this to rx/tx
|
||||||
pub cx: Option<&'d mut Context<'c>>,
|
pub cx: Option<&'d mut Context<'c>>,
|
||||||
pub inner: &'d mut T,
|
pub inner: &'d mut T,
|
||||||
|
pub medium: Medium,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, 'c, T> phy::Device for DriverAdapter<'d, 'c, T>
|
impl<'d, 'c, T> phy::Device for DriverAdapter<'d, 'c, T>
|
||||||
@ -22,13 +23,13 @@ where
|
|||||||
|
|
||||||
fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
|
fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
|
||||||
self.inner
|
self.inner
|
||||||
.receive(self.cx.as_deref_mut().unwrap())
|
.receive(unwrap!(self.cx.as_deref_mut()))
|
||||||
.map(|(rx, tx)| (RxTokenAdapter(rx), TxTokenAdapter(tx)))
|
.map(|(rx, tx)| (RxTokenAdapter(rx), TxTokenAdapter(tx)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a transmit token.
|
/// Construct a transmit token.
|
||||||
fn transmit(&mut self, _timestamp: Instant) -> Option<Self::TxToken<'_>> {
|
fn transmit(&mut self, _timestamp: Instant) -> Option<Self::TxToken<'_>> {
|
||||||
self.inner.transmit(self.cx.as_deref_mut().unwrap()).map(TxTokenAdapter)
|
self.inner.transmit(unwrap!(self.cx.as_deref_mut())).map(TxTokenAdapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a description of device capabilities.
|
/// Get a description of device capabilities.
|
||||||
@ -46,19 +47,7 @@ where
|
|||||||
|
|
||||||
smolcaps.max_transmission_unit = caps.max_transmission_unit;
|
smolcaps.max_transmission_unit = caps.max_transmission_unit;
|
||||||
smolcaps.max_burst_size = caps.max_burst_size;
|
smolcaps.max_burst_size = caps.max_burst_size;
|
||||||
smolcaps.medium = match caps.medium {
|
smolcaps.medium = self.medium;
|
||||||
#[cfg(feature = "medium-ethernet")]
|
|
||||||
Medium::Ethernet => phy::Medium::Ethernet,
|
|
||||||
#[cfg(feature = "medium-ip")]
|
|
||||||
Medium::Ip => phy::Medium::Ip,
|
|
||||||
#[cfg(feature = "medium-ieee802154")]
|
|
||||||
Medium::Ieee802154 => phy::Medium::Ieee802154,
|
|
||||||
#[allow(unreachable_patterns)]
|
|
||||||
_ => panic!(
|
|
||||||
"Unsupported medium {:?}. Make sure to enable it in embassy-net's Cargo features.",
|
|
||||||
caps.medium
|
|
||||||
),
|
|
||||||
};
|
|
||||||
smolcaps.checksum.ipv4 = convert(caps.checksum.ipv4);
|
smolcaps.checksum.ipv4 = convert(caps.checksum.ipv4);
|
||||||
smolcaps.checksum.tcp = convert(caps.checksum.tcp);
|
smolcaps.checksum.tcp = convert(caps.checksum.tcp);
|
||||||
smolcaps.checksum.udp = convert(caps.checksum.udp);
|
smolcaps.checksum.udp = convert(caps.checksum.udp);
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
#![allow(unused_macros)]
|
#![allow(unused_macros)]
|
||||||
|
|
||||||
|
use core::fmt::{Debug, Display, LowerHex};
|
||||||
|
|
||||||
#[cfg(all(feature = "defmt", feature = "log"))]
|
#[cfg(all(feature = "defmt", feature = "log"))]
|
||||||
compile_error!("You may not enable both `defmt` and `log` features.");
|
compile_error!("You may not enable both `defmt` and `log` features.");
|
||||||
|
|
||||||
@ -81,14 +83,17 @@ macro_rules! todo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "defmt"))]
|
||||||
macro_rules! unreachable {
|
macro_rules! unreachable {
|
||||||
($($x:tt)*) => {
|
($($x:tt)*) => {
|
||||||
{
|
::core::unreachable!($($x)*)
|
||||||
#[cfg(not(feature = "defmt"))]
|
};
|
||||||
::core::unreachable!($($x)*);
|
}
|
||||||
#[cfg(feature = "defmt")]
|
|
||||||
::defmt::unreachable!($($x)*);
|
#[cfg(feature = "defmt")]
|
||||||
}
|
macro_rules! unreachable {
|
||||||
|
($($x:tt)*) => {
|
||||||
|
::defmt::unreachable!($($x)*)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,3 +228,31 @@ impl<T, E> Try for Result<T, E> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub(crate) 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections))]
|
#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections))]
|
||||||
|
#![cfg_attr(feature = "nightly", allow(stable_features, unknown_lints, async_fn_in_trait))]
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
#![doc = include_str!("../README.md")]
|
#![doc = include_str!("../README.md")]
|
||||||
|
|
||||||
@ -33,13 +34,14 @@ use heapless::Vec;
|
|||||||
pub use smoltcp::iface::MulticastError;
|
pub use smoltcp::iface::MulticastError;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use smoltcp::iface::{Interface, SocketHandle, SocketSet, SocketStorage};
|
use smoltcp::iface::{Interface, SocketHandle, SocketSet, SocketStorage};
|
||||||
|
use smoltcp::phy::Medium;
|
||||||
#[cfg(feature = "dhcpv4")]
|
#[cfg(feature = "dhcpv4")]
|
||||||
use smoltcp::socket::dhcpv4::{self, RetryConfig};
|
use smoltcp::socket::dhcpv4::{self, RetryConfig};
|
||||||
#[cfg(feature = "medium-ethernet")]
|
#[cfg(feature = "medium-ethernet")]
|
||||||
pub use smoltcp::wire::EthernetAddress;
|
pub use smoltcp::wire::EthernetAddress;
|
||||||
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154", feature = "medium-ip"))]
|
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154", feature = "medium-ip"))]
|
||||||
pub use smoltcp::wire::HardwareAddress;
|
pub use smoltcp::wire::HardwareAddress;
|
||||||
#[cfg(feature = "udp")]
|
#[cfg(any(feature = "udp", feature = "tcp"))]
|
||||||
pub use smoltcp::wire::IpListenEndpoint;
|
pub use smoltcp::wire::IpListenEndpoint;
|
||||||
#[cfg(feature = "medium-ieee802154")]
|
#[cfg(feature = "medium-ieee802154")]
|
||||||
pub use smoltcp::wire::{Ieee802154Address, Ieee802154Frame};
|
pub use smoltcp::wire::{Ieee802154Address, Ieee802154Frame};
|
||||||
@ -56,12 +58,22 @@ const LOCAL_PORT_MIN: u16 = 1025;
|
|||||||
const LOCAL_PORT_MAX: u16 = 65535;
|
const LOCAL_PORT_MAX: u16 = 65535;
|
||||||
#[cfg(feature = "dns")]
|
#[cfg(feature = "dns")]
|
||||||
const MAX_QUERIES: usize = 4;
|
const MAX_QUERIES: usize = 4;
|
||||||
|
#[cfg(feature = "dhcpv4-hostname")]
|
||||||
|
const MAX_HOSTNAME_LEN: usize = 32;
|
||||||
|
|
||||||
/// Memory resources needed for a network stack.
|
/// Memory resources needed for a network stack.
|
||||||
pub struct StackResources<const SOCK: usize> {
|
pub struct StackResources<const SOCK: usize> {
|
||||||
sockets: [SocketStorage<'static>; SOCK],
|
sockets: [SocketStorage<'static>; SOCK],
|
||||||
#[cfg(feature = "dns")]
|
#[cfg(feature = "dns")]
|
||||||
queries: [Option<dns::DnsQuery>; MAX_QUERIES],
|
queries: [Option<dns::DnsQuery>; MAX_QUERIES],
|
||||||
|
#[cfg(feature = "dhcpv4-hostname")]
|
||||||
|
hostname: core::cell::UnsafeCell<HostnameResources>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "dhcpv4-hostname")]
|
||||||
|
struct HostnameResources {
|
||||||
|
option: smoltcp::wire::DhcpOption<'static>,
|
||||||
|
data: [u8; MAX_HOSTNAME_LEN],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const SOCK: usize> StackResources<SOCK> {
|
impl<const SOCK: usize> StackResources<SOCK> {
|
||||||
@ -73,6 +85,11 @@ impl<const SOCK: usize> StackResources<SOCK> {
|
|||||||
sockets: [SocketStorage::EMPTY; SOCK],
|
sockets: [SocketStorage::EMPTY; SOCK],
|
||||||
#[cfg(feature = "dns")]
|
#[cfg(feature = "dns")]
|
||||||
queries: [INIT; MAX_QUERIES],
|
queries: [INIT; MAX_QUERIES],
|
||||||
|
#[cfg(feature = "dhcpv4-hostname")]
|
||||||
|
hostname: core::cell::UnsafeCell::new(HostnameResources {
|
||||||
|
option: smoltcp::wire::DhcpOption { kind: 0, data: &[] },
|
||||||
|
data: [0; MAX_HOSTNAME_LEN],
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,6 +121,7 @@ pub struct StaticConfigV6 {
|
|||||||
/// DHCP configuration.
|
/// DHCP configuration.
|
||||||
#[cfg(feature = "dhcpv4")]
|
#[cfg(feature = "dhcpv4")]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
#[non_exhaustive]
|
||||||
pub struct DhcpConfig {
|
pub struct DhcpConfig {
|
||||||
/// Maximum lease duration.
|
/// Maximum lease duration.
|
||||||
///
|
///
|
||||||
@ -120,6 +138,9 @@ pub struct DhcpConfig {
|
|||||||
pub server_port: u16,
|
pub server_port: u16,
|
||||||
/// Client port. This is almost always 68. Do not change unless you know what you're doing.
|
/// Client port. This is almost always 68. Do not change unless you know what you're doing.
|
||||||
pub client_port: u16,
|
pub client_port: u16,
|
||||||
|
/// Our hostname. This will be sent to the DHCP server as Option 12.
|
||||||
|
#[cfg(feature = "dhcpv4-hostname")]
|
||||||
|
pub hostname: Option<heapless::String<MAX_HOSTNAME_LEN>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "dhcpv4")]
|
#[cfg(feature = "dhcpv4")]
|
||||||
@ -131,6 +152,8 @@ impl Default for DhcpConfig {
|
|||||||
ignore_naks: Default::default(),
|
ignore_naks: Default::default(),
|
||||||
server_port: smoltcp::wire::DHCP_SERVER_PORT,
|
server_port: smoltcp::wire::DHCP_SERVER_PORT,
|
||||||
client_port: smoltcp::wire::DHCP_CLIENT_PORT,
|
client_port: smoltcp::wire::DHCP_CLIENT_PORT,
|
||||||
|
#[cfg(feature = "dhcpv4-hostname")]
|
||||||
|
hostname: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,10 +191,11 @@ impl Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// IPv6 configuration with dynamic addressing.
|
/// IPv4 configuration with dynamic addressing.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```rust
|
/// ```rust
|
||||||
|
/// # use embassy_net::Config;
|
||||||
/// let _cfg = Config::dhcpv4(Default::default());
|
/// let _cfg = Config::dhcpv4(Default::default());
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(feature = "dhcpv4")]
|
#[cfg(feature = "dhcpv4")]
|
||||||
@ -226,10 +250,13 @@ struct Inner<D: Driver> {
|
|||||||
static_v6: Option<StaticConfigV6>,
|
static_v6: Option<StaticConfigV6>,
|
||||||
#[cfg(feature = "dhcpv4")]
|
#[cfg(feature = "dhcpv4")]
|
||||||
dhcp_socket: Option<SocketHandle>,
|
dhcp_socket: Option<SocketHandle>,
|
||||||
|
config_waker: WakerRegistration,
|
||||||
#[cfg(feature = "dns")]
|
#[cfg(feature = "dns")]
|
||||||
dns_socket: SocketHandle,
|
dns_socket: SocketHandle,
|
||||||
#[cfg(feature = "dns")]
|
#[cfg(feature = "dns")]
|
||||||
dns_waker: WakerRegistration,
|
dns_waker: WakerRegistration,
|
||||||
|
#[cfg(feature = "dhcpv4-hostname")]
|
||||||
|
hostname: &'static mut core::cell::UnsafeCell<HostnameResources>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct SocketStack {
|
pub(crate) struct SocketStack {
|
||||||
@ -239,14 +266,17 @@ pub(crate) struct SocketStack {
|
|||||||
next_local_port: u16,
|
next_local_port: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_smoltcp_hardware_address(addr: driver::HardwareAddress) -> HardwareAddress {
|
fn to_smoltcp_hardware_address(addr: driver::HardwareAddress) -> (HardwareAddress, Medium) {
|
||||||
match addr {
|
match addr {
|
||||||
#[cfg(feature = "medium-ethernet")]
|
#[cfg(feature = "medium-ethernet")]
|
||||||
driver::HardwareAddress::Ethernet(eth) => HardwareAddress::Ethernet(EthernetAddress(eth)),
|
driver::HardwareAddress::Ethernet(eth) => (HardwareAddress::Ethernet(EthernetAddress(eth)), Medium::Ethernet),
|
||||||
#[cfg(feature = "medium-ieee802154")]
|
#[cfg(feature = "medium-ieee802154")]
|
||||||
driver::HardwareAddress::Ieee802154(ieee) => HardwareAddress::Ieee802154(Ieee802154Address::Extended(ieee)),
|
driver::HardwareAddress::Ieee802154(ieee) => (
|
||||||
|
HardwareAddress::Ieee802154(Ieee802154Address::Extended(ieee)),
|
||||||
|
Medium::Ieee802154,
|
||||||
|
),
|
||||||
#[cfg(feature = "medium-ip")]
|
#[cfg(feature = "medium-ip")]
|
||||||
driver::HardwareAddress::Ip => HardwareAddress::Ip,
|
driver::HardwareAddress::Ip => (HardwareAddress::Ip, Medium::Ip),
|
||||||
|
|
||||||
#[allow(unreachable_patterns)]
|
#[allow(unreachable_patterns)]
|
||||||
_ => panic!(
|
_ => panic!(
|
||||||
@ -256,7 +286,7 @@ fn to_smoltcp_hardware_address(addr: driver::HardwareAddress) -> HardwareAddress
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: Driver + 'static> Stack<D> {
|
impl<D: Driver> Stack<D> {
|
||||||
/// Create a new network stack.
|
/// Create a new network stack.
|
||||||
pub fn new<const SOCK: usize>(
|
pub fn new<const SOCK: usize>(
|
||||||
mut device: D,
|
mut device: D,
|
||||||
@ -264,7 +294,8 @@ impl<D: Driver + 'static> Stack<D> {
|
|||||||
resources: &'static mut StackResources<SOCK>,
|
resources: &'static mut StackResources<SOCK>,
|
||||||
random_seed: u64,
|
random_seed: u64,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut iface_cfg = smoltcp::iface::Config::new(to_smoltcp_hardware_address(device.hardware_address()));
|
let (hardware_addr, medium) = to_smoltcp_hardware_address(device.hardware_address());
|
||||||
|
let mut iface_cfg = smoltcp::iface::Config::new(hardware_addr);
|
||||||
iface_cfg.random_seed = random_seed;
|
iface_cfg.random_seed = random_seed;
|
||||||
|
|
||||||
let iface = Interface::new(
|
let iface = Interface::new(
|
||||||
@ -272,6 +303,7 @@ impl<D: Driver + 'static> Stack<D> {
|
|||||||
&mut DriverAdapter {
|
&mut DriverAdapter {
|
||||||
inner: &mut device,
|
inner: &mut device,
|
||||||
cx: None,
|
cx: None,
|
||||||
|
medium,
|
||||||
},
|
},
|
||||||
instant_to_smoltcp(Instant::now()),
|
instant_to_smoltcp(Instant::now()),
|
||||||
);
|
);
|
||||||
@ -297,6 +329,7 @@ impl<D: Driver + 'static> Stack<D> {
|
|||||||
static_v6: None,
|
static_v6: None,
|
||||||
#[cfg(feature = "dhcpv4")]
|
#[cfg(feature = "dhcpv4")]
|
||||||
dhcp_socket: None,
|
dhcp_socket: None,
|
||||||
|
config_waker: WakerRegistration::new(),
|
||||||
#[cfg(feature = "dns")]
|
#[cfg(feature = "dns")]
|
||||||
dns_socket: socket.sockets.add(dns::Socket::new(
|
dns_socket: socket.sockets.add(dns::Socket::new(
|
||||||
&[],
|
&[],
|
||||||
@ -304,6 +337,8 @@ impl<D: Driver + 'static> Stack<D> {
|
|||||||
)),
|
)),
|
||||||
#[cfg(feature = "dns")]
|
#[cfg(feature = "dns")]
|
||||||
dns_waker: WakerRegistration::new(),
|
dns_waker: WakerRegistration::new(),
|
||||||
|
#[cfg(feature = "dhcpv4-hostname")]
|
||||||
|
hostname: &mut resources.hostname,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "proto-ipv4")]
|
#[cfg(feature = "proto-ipv4")]
|
||||||
@ -328,7 +363,7 @@ impl<D: Driver + 'static> Stack<D> {
|
|||||||
|
|
||||||
/// Get the hardware address of the network interface.
|
/// Get the hardware address of the network interface.
|
||||||
pub fn hardware_address(&self) -> HardwareAddress {
|
pub fn hardware_address(&self) -> HardwareAddress {
|
||||||
self.with(|_s, i| to_smoltcp_hardware_address(i.device.hardware_address()))
|
self.with(|_s, i| to_smoltcp_hardware_address(i.device.hardware_address()).0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get whether the link is up.
|
/// Get whether the link is up.
|
||||||
@ -363,6 +398,55 @@ impl<D: Driver + 'static> Stack<D> {
|
|||||||
v4_up || v6_up
|
v4_up || v6_up
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Wait for the network stack to obtain a valid IP configuration.
|
||||||
|
///
|
||||||
|
/// ## Notes:
|
||||||
|
/// - Ensure [`Stack::run`] has been called before using this function.
|
||||||
|
///
|
||||||
|
/// - This function may never return (e.g. if no configuration is obtained through DHCP).
|
||||||
|
/// The caller is supposed to handle a timeout for this case.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```ignore
|
||||||
|
/// let config = embassy_net::Config::dhcpv4(Default::default());
|
||||||
|
///// Init network stack
|
||||||
|
/// let stack = &*make_static!(embassy_net::Stack::new(
|
||||||
|
/// device,
|
||||||
|
/// config,
|
||||||
|
/// make_static!(embassy_net::StackResources::<2>::new()),
|
||||||
|
/// seed
|
||||||
|
/// ));
|
||||||
|
/// // Launch network task that runs `stack.run().await`
|
||||||
|
/// spawner.spawn(net_task(stack)).unwrap();
|
||||||
|
/// // Wait for DHCP config
|
||||||
|
/// stack.wait_config_up().await;
|
||||||
|
/// // use the network stack
|
||||||
|
/// // ...
|
||||||
|
/// ```
|
||||||
|
pub async fn wait_config_up(&self) {
|
||||||
|
// If the config is up already, we can return immediately.
|
||||||
|
if self.is_config_up() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
poll_fn(|cx| {
|
||||||
|
if self.is_config_up() {
|
||||||
|
Poll::Ready(())
|
||||||
|
} else {
|
||||||
|
// If the config is not up, we register a waker that is woken up
|
||||||
|
// when a config is applied (static or DHCP).
|
||||||
|
trace!("Waiting for config up");
|
||||||
|
|
||||||
|
self.with_mut(|_, i| {
|
||||||
|
i.config_waker.register(cx.waker());
|
||||||
|
});
|
||||||
|
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the current IPv4 configuration.
|
/// Get the current IPv4 configuration.
|
||||||
///
|
///
|
||||||
/// If using DHCP, this will be None if DHCP hasn't been able to
|
/// If using DHCP, this will be None if DHCP hasn't been able to
|
||||||
@ -432,7 +516,10 @@ impl<D: Driver + 'static> Stack<D> {
|
|||||||
self.with_mut(|s, i| {
|
self.with_mut(|s, i| {
|
||||||
let socket = s.sockets.get_mut::<dns::Socket>(i.dns_socket);
|
let socket = s.sockets.get_mut::<dns::Socket>(i.dns_socket);
|
||||||
match socket.start_query(s.iface.context(), name, qtype) {
|
match socket.start_query(s.iface.context(), name, qtype) {
|
||||||
Ok(handle) => Poll::Ready(Ok(handle)),
|
Ok(handle) => {
|
||||||
|
s.waker.wake();
|
||||||
|
Poll::Ready(Ok(handle))
|
||||||
|
}
|
||||||
Err(dns::StartQueryError::NoFreeSlot) => {
|
Err(dns::StartQueryError::NoFreeSlot) => {
|
||||||
i.dns_waker.register(cx.waker());
|
i.dns_waker.register(cx.waker());
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
@ -503,7 +590,7 @@ impl<D: Driver + 'static> Stack<D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "igmp")]
|
#[cfg(feature = "igmp")]
|
||||||
impl<D: Driver + 'static> Stack<D> {
|
impl<D: Driver> Stack<D> {
|
||||||
/// Join a multicast group.
|
/// Join a multicast group.
|
||||||
pub async fn join_multicast_group<T>(&self, addr: T) -> Result<bool, MulticastError>
|
pub async fn join_multicast_group<T>(&self, addr: T) -> Result<bool, MulticastError>
|
||||||
where
|
where
|
||||||
@ -593,7 +680,7 @@ impl SocketStack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: Driver + 'static> Inner<D> {
|
impl<D: Driver> Inner<D> {
|
||||||
#[cfg(feature = "proto-ipv4")]
|
#[cfg(feature = "proto-ipv4")]
|
||||||
pub fn set_config_v4(&mut self, _s: &mut SocketStack, config: ConfigV4) {
|
pub fn set_config_v4(&mut self, _s: &mut SocketStack, config: ConfigV4) {
|
||||||
// Handle static config.
|
// Handle static config.
|
||||||
@ -616,11 +703,30 @@ impl<D: Driver + 'static> Inner<D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Configure it
|
// Configure it
|
||||||
let socket = _s.sockets.get_mut::<dhcpv4::Socket>(self.dhcp_socket.unwrap());
|
let socket = _s.sockets.get_mut::<dhcpv4::Socket>(unwrap!(self.dhcp_socket));
|
||||||
socket.set_ignore_naks(c.ignore_naks);
|
socket.set_ignore_naks(c.ignore_naks);
|
||||||
socket.set_max_lease_duration(c.max_lease_duration.map(crate::time::duration_to_smoltcp));
|
socket.set_max_lease_duration(c.max_lease_duration.map(crate::time::duration_to_smoltcp));
|
||||||
socket.set_ports(c.server_port, c.client_port);
|
socket.set_ports(c.server_port, c.client_port);
|
||||||
socket.set_retry_config(c.retry_config);
|
socket.set_retry_config(c.retry_config);
|
||||||
|
|
||||||
|
socket.set_outgoing_options(&[]);
|
||||||
|
#[cfg(feature = "dhcpv4-hostname")]
|
||||||
|
if let Some(h) = c.hostname {
|
||||||
|
// safety: we just did set_outgoing_options([]) so we know the socket is no longer holding a reference.
|
||||||
|
let hostname = unsafe { &mut *self.hostname.get() };
|
||||||
|
|
||||||
|
// create data
|
||||||
|
// safety: we know the buffer lives forever, new borrows the StackResources for 'static.
|
||||||
|
// also we won't modify it until next call to this function.
|
||||||
|
hostname.data[..h.len()].copy_from_slice(h.as_bytes());
|
||||||
|
let data: &[u8] = &hostname.data[..h.len()];
|
||||||
|
let data: &'static [u8] = unsafe { core::mem::transmute(data) };
|
||||||
|
|
||||||
|
// set the option.
|
||||||
|
hostname.option = smoltcp::wire::DhcpOption { data, kind: 12 };
|
||||||
|
socket.set_outgoing_options(core::slice::from_ref(&hostname.option));
|
||||||
|
}
|
||||||
|
|
||||||
socket.reset();
|
socket.reset();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@ -656,12 +762,12 @@ impl<D: Driver + 'static> Inner<D> {
|
|||||||
debug!(" IP address: {:?}", config.address);
|
debug!(" IP address: {:?}", config.address);
|
||||||
debug!(" Default gateway: {:?}", config.gateway);
|
debug!(" Default gateway: {:?}", config.gateway);
|
||||||
|
|
||||||
addrs.push(IpCidr::Ipv4(config.address)).unwrap();
|
unwrap!(addrs.push(IpCidr::Ipv4(config.address)).ok());
|
||||||
gateway_v4 = config.gateway.into();
|
gateway_v4 = config.gateway.into();
|
||||||
#[cfg(feature = "dns")]
|
#[cfg(feature = "dns")]
|
||||||
for s in &config.dns_servers {
|
for s in &config.dns_servers {
|
||||||
debug!(" DNS server: {:?}", s);
|
debug!(" DNS server: {:?}", s);
|
||||||
dns_servers.push(s.clone().into()).unwrap();
|
unwrap!(dns_servers.push(s.clone().into()).ok());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
info!("IPv4: DOWN");
|
info!("IPv4: DOWN");
|
||||||
@ -673,12 +779,12 @@ impl<D: Driver + 'static> Inner<D> {
|
|||||||
debug!(" IP address: {:?}", config.address);
|
debug!(" IP address: {:?}", config.address);
|
||||||
debug!(" Default gateway: {:?}", config.gateway);
|
debug!(" Default gateway: {:?}", config.gateway);
|
||||||
|
|
||||||
addrs.push(IpCidr::Ipv6(config.address)).unwrap();
|
unwrap!(addrs.push(IpCidr::Ipv6(config.address)).ok());
|
||||||
gateway_v6 = config.gateway.into();
|
gateway_v6 = config.gateway.into();
|
||||||
#[cfg(feature = "dns")]
|
#[cfg(feature = "dns")]
|
||||||
for s in &config.dns_servers {
|
for s in &config.dns_servers {
|
||||||
debug!(" DNS server: {:?}", s);
|
debug!(" DNS server: {:?}", s);
|
||||||
dns_servers.push(s.clone().into()).unwrap();
|
unwrap!(dns_servers.push(s.clone().into()).ok());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
info!("IPv6: DOWN");
|
info!("IPv6: DOWN");
|
||||||
@ -690,13 +796,13 @@ impl<D: Driver + 'static> Inner<D> {
|
|||||||
// Apply gateways
|
// Apply gateways
|
||||||
#[cfg(feature = "proto-ipv4")]
|
#[cfg(feature = "proto-ipv4")]
|
||||||
if let Some(gateway) = gateway_v4 {
|
if let Some(gateway) = gateway_v4 {
|
||||||
s.iface.routes_mut().add_default_ipv4_route(gateway).unwrap();
|
unwrap!(s.iface.routes_mut().add_default_ipv4_route(gateway));
|
||||||
} else {
|
} else {
|
||||||
s.iface.routes_mut().remove_default_ipv4_route();
|
s.iface.routes_mut().remove_default_ipv4_route();
|
||||||
}
|
}
|
||||||
#[cfg(feature = "proto-ipv6")]
|
#[cfg(feature = "proto-ipv6")]
|
||||||
if let Some(gateway) = gateway_v6 {
|
if let Some(gateway) = gateway_v6 {
|
||||||
s.iface.routes_mut().add_default_ipv6_route(gateway).unwrap();
|
unwrap!(s.iface.routes_mut().add_default_ipv6_route(gateway));
|
||||||
} else {
|
} else {
|
||||||
s.iface.routes_mut().remove_default_ipv6_route();
|
s.iface.routes_mut().remove_default_ipv6_route();
|
||||||
}
|
}
|
||||||
@ -706,23 +812,35 @@ impl<D: Driver + 'static> Inner<D> {
|
|||||||
s.sockets
|
s.sockets
|
||||||
.get_mut::<smoltcp::socket::dns::Socket>(self.dns_socket)
|
.get_mut::<smoltcp::socket::dns::Socket>(self.dns_socket)
|
||||||
.update_servers(&dns_servers[..]);
|
.update_servers(&dns_servers[..]);
|
||||||
|
|
||||||
|
self.config_waker.wake();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) {
|
fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) {
|
||||||
s.waker.register(cx.waker());
|
s.waker.register(cx.waker());
|
||||||
|
|
||||||
|
let (_hardware_addr, medium) = to_smoltcp_hardware_address(self.device.hardware_address());
|
||||||
|
|
||||||
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
|
||||||
if self.device.capabilities().medium == embassy_net_driver::Medium::Ethernet
|
|
||||||
|| self.device.capabilities().medium == embassy_net_driver::Medium::Ieee802154
|
|
||||||
{
|
{
|
||||||
s.iface
|
let do_set = match medium {
|
||||||
.set_hardware_addr(to_smoltcp_hardware_address(self.device.hardware_address()));
|
#[cfg(feature = "medium-ethernet")]
|
||||||
|
Medium::Ethernet => true,
|
||||||
|
#[cfg(feature = "medium-ieee802154")]
|
||||||
|
Medium::Ieee802154 => true,
|
||||||
|
#[allow(unreachable_patterns)]
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if do_set {
|
||||||
|
s.iface.set_hardware_addr(_hardware_addr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let timestamp = instant_to_smoltcp(Instant::now());
|
let timestamp = instant_to_smoltcp(Instant::now());
|
||||||
let mut smoldev = DriverAdapter {
|
let mut smoldev = DriverAdapter {
|
||||||
cx: Some(cx),
|
cx: Some(cx),
|
||||||
inner: &mut self.device,
|
inner: &mut self.device,
|
||||||
|
medium,
|
||||||
};
|
};
|
||||||
s.iface.poll(timestamp, &mut smoldev, &mut s.sockets);
|
s.iface.poll(timestamp, &mut smoldev, &mut s.sockets);
|
||||||
|
|
||||||
@ -743,6 +861,9 @@ impl<D: Driver + 'static> Inner<D> {
|
|||||||
let socket = s.sockets.get_mut::<dhcpv4::Socket>(dhcp_handle);
|
let socket = s.sockets.get_mut::<dhcpv4::Socket>(dhcp_handle);
|
||||||
|
|
||||||
if self.link_up {
|
if self.link_up {
|
||||||
|
if old_link_up != self.link_up {
|
||||||
|
socket.reset();
|
||||||
|
}
|
||||||
match socket.poll() {
|
match socket.poll() {
|
||||||
None => {}
|
None => {}
|
||||||
Some(dhcpv4::Event::Deconfigured) => {
|
Some(dhcpv4::Event::Deconfigured) => {
|
||||||
|
@ -440,7 +440,7 @@ impl<'d> TcpIo<'d> {
|
|||||||
Poll::Ready(Err(Error::ConnectionReset))
|
Poll::Ready(Err(Error::ConnectionReset))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Poll::Ready(match s.send(f.take().unwrap()) {
|
Poll::Ready(match s.send(unwrap!(f.take())) {
|
||||||
// Connection reset. TODO: this can also be timeouts etc, investigate.
|
// Connection reset. TODO: this can also be timeouts etc, investigate.
|
||||||
Err(tcp::SendError::InvalidState) => Err(Error::ConnectionReset),
|
Err(tcp::SendError::InvalidState) => Err(Error::ConnectionReset),
|
||||||
Ok(r) => Ok(r),
|
Ok(r) => Ok(r),
|
||||||
@ -468,7 +468,7 @@ impl<'d> TcpIo<'d> {
|
|||||||
Poll::Ready(Err(Error::ConnectionReset))
|
Poll::Ready(Err(Error::ConnectionReset))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Poll::Ready(match s.recv(f.take().unwrap()) {
|
Poll::Ready(match s.recv(unwrap!(f.take())) {
|
||||||
// Connection reset. TODO: this can also be timeouts etc, investigate.
|
// Connection reset. TODO: this can also be timeouts etc, investigate.
|
||||||
Err(tcp::RecvError::Finished) | Err(tcp::RecvError::InvalidState) => {
|
Err(tcp::RecvError::Finished) | Err(tcp::RecvError::InvalidState) => {
|
||||||
Err(Error::ConnectionReset)
|
Err(Error::ConnectionReset)
|
||||||
@ -579,11 +579,10 @@ mod embedded_io_impls {
|
|||||||
/// TCP client compatible with `embedded-nal-async` traits.
|
/// TCP client compatible with `embedded-nal-async` traits.
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
pub mod client {
|
pub mod client {
|
||||||
use core::cell::UnsafeCell;
|
use core::cell::{Cell, UnsafeCell};
|
||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
use core::ptr::NonNull;
|
use core::ptr::NonNull;
|
||||||
|
|
||||||
use atomic_polyfill::{AtomicBool, Ordering};
|
|
||||||
use embedded_nal_async::IpAddr;
|
use embedded_nal_async::IpAddr;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -702,15 +701,13 @@ pub mod client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize> Sync for TcpClientState<N, TX_SZ, RX_SZ> {}
|
|
||||||
|
|
||||||
struct Pool<T, const N: usize> {
|
struct Pool<T, const N: usize> {
|
||||||
used: [AtomicBool; N],
|
used: [Cell<bool>; N],
|
||||||
data: [UnsafeCell<MaybeUninit<T>>; N],
|
data: [UnsafeCell<MaybeUninit<T>>; N],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, const N: usize> Pool<T, N> {
|
impl<T, const N: usize> Pool<T, N> {
|
||||||
const VALUE: AtomicBool = AtomicBool::new(false);
|
const VALUE: Cell<bool> = Cell::new(false);
|
||||||
const UNINIT: UnsafeCell<MaybeUninit<T>> = UnsafeCell::new(MaybeUninit::uninit());
|
const UNINIT: UnsafeCell<MaybeUninit<T>> = UnsafeCell::new(MaybeUninit::uninit());
|
||||||
|
|
||||||
const fn new() -> Self {
|
const fn new() -> Self {
|
||||||
@ -724,7 +721,9 @@ pub mod client {
|
|||||||
impl<T, const N: usize> Pool<T, N> {
|
impl<T, const N: usize> Pool<T, N> {
|
||||||
fn alloc(&self) -> Option<NonNull<T>> {
|
fn alloc(&self) -> Option<NonNull<T>> {
|
||||||
for n in 0..N {
|
for n in 0..N {
|
||||||
if self.used[n].swap(true, Ordering::SeqCst) == false {
|
// this can't race because Pool is not Sync.
|
||||||
|
if !self.used[n].get() {
|
||||||
|
self.used[n].set(true);
|
||||||
let p = self.data[n].get() as *mut T;
|
let p = self.data[n].get() as *mut T;
|
||||||
return Some(unsafe { NonNull::new_unchecked(p) });
|
return Some(unsafe { NonNull::new_unchecked(p) });
|
||||||
}
|
}
|
||||||
@ -738,7 +737,7 @@ pub mod client {
|
|||||||
let n = p.as_ptr().offset_from(origin);
|
let n = p.as_ptr().offset_from(origin);
|
||||||
assert!(n >= 0);
|
assert!(n >= 0);
|
||||||
assert!((n as usize) < N);
|
assert!((n as usize) < N);
|
||||||
self.used[n as usize].store(false, Ordering::SeqCst);
|
self.used[n as usize].set(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,8 @@ pub enum BindError {
|
|||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// No route to host.
|
/// No route to host.
|
||||||
NoRoute,
|
NoRoute,
|
||||||
|
/// Socket not bound to an outgoing port.
|
||||||
|
SocketNotBound,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An UDP socket.
|
/// An UDP socket.
|
||||||
@ -155,7 +157,14 @@ impl<'a> UdpSocket<'a> {
|
|||||||
s.register_send_waker(cx.waker());
|
s.register_send_waker(cx.waker());
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
}
|
}
|
||||||
Err(udp::SendError::Unaddressable) => Poll::Ready(Err(Error::NoRoute)),
|
Err(udp::SendError::Unaddressable) => {
|
||||||
|
// If no sender/outgoing port is specified, there is not really "no route"
|
||||||
|
if s.endpoint().port == 0 {
|
||||||
|
Poll::Ready(Err(Error::SocketNotBound))
|
||||||
|
} else {
|
||||||
|
Poll::Ready(Err(Error::NoRoute))
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ nrf52805 = ["nrf52805-pac", "_nrf52"]
|
|||||||
nrf52810 = ["nrf52810-pac", "_nrf52"]
|
nrf52810 = ["nrf52810-pac", "_nrf52"]
|
||||||
nrf52811 = ["nrf52811-pac", "_nrf52"]
|
nrf52811 = ["nrf52811-pac", "_nrf52"]
|
||||||
nrf52820 = ["nrf52820-pac", "_nrf52"]
|
nrf52820 = ["nrf52820-pac", "_nrf52"]
|
||||||
nrf52832 = ["nrf52832-pac", "_nrf52"]
|
nrf52832 = ["nrf52832-pac", "_nrf52", "_nrf52832_anomaly_109"]
|
||||||
nrf52833 = ["nrf52833-pac", "_nrf52", "_gpio-p1"]
|
nrf52833 = ["nrf52833-pac", "_nrf52", "_gpio-p1"]
|
||||||
nrf52840 = ["nrf52840-pac", "_nrf52", "_gpio-p1"]
|
nrf52840 = ["nrf52840-pac", "_nrf52", "_gpio-p1"]
|
||||||
nrf5340-app-s = ["_nrf5340-app", "_s"]
|
nrf5340-app-s = ["_nrf5340-app", "_s"]
|
||||||
@ -90,9 +90,12 @@ _ppi = []
|
|||||||
_dppi = []
|
_dppi = []
|
||||||
_gpio-p1 = []
|
_gpio-p1 = []
|
||||||
|
|
||||||
|
# Errata workarounds
|
||||||
|
_nrf52832_anomaly_109 = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
|
embassy-time = { version = "0.1.5", path = "../embassy-time", optional = true }
|
||||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.4.0", path = "../embassy-sync" }
|
||||||
embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] }
|
embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] }
|
||||||
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||||
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true }
|
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true }
|
||||||
@ -100,14 +103,13 @@ embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optiona
|
|||||||
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
|
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
|
||||||
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1", optional = true}
|
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1", optional = true}
|
||||||
embedded-hal-async = { version = "=1.0.0-rc.1", optional = true}
|
embedded-hal-async = { version = "=1.0.0-rc.1", optional = true}
|
||||||
embedded-io = { version = "0.5.0" }
|
embedded-io = { version = "0.6.0" }
|
||||||
embedded-io-async = { version = "0.5.0", optional = true }
|
embedded-io-async = { version = "0.6.0", optional = true }
|
||||||
|
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
log = { version = "0.4.14", optional = true }
|
log = { version = "0.4.14", optional = true }
|
||||||
cortex-m-rt = ">=0.6.15,<0.8"
|
cortex-m-rt = ">=0.6.15,<0.8"
|
||||||
cortex-m = "0.7.6"
|
cortex-m = "0.7.6"
|
||||||
futures = { version = "0.3.17", default-features = false }
|
|
||||||
critical-section = "1.1"
|
critical-section = "1.1"
|
||||||
rand_core = "0.6.3"
|
rand_core = "0.6.3"
|
||||||
fixed = "1.10.0"
|
fixed = "1.10.0"
|
||||||
|
@ -6,10 +6,13 @@ pub mod pac {
|
|||||||
// To avoid cfg spam, we remove _ns or _s suffixes here.
|
// To avoid cfg spam, we remove _ns or _s suffixes here.
|
||||||
|
|
||||||
pub use nrf5340_app_pac::NVIC_PRIO_BITS;
|
pub use nrf5340_app_pac::NVIC_PRIO_BITS;
|
||||||
|
|
||||||
|
#[cfg(feature="rt")]
|
||||||
|
#[doc(no_inline)]
|
||||||
|
pub use nrf5340_app_pac::interrupt;
|
||||||
|
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use nrf5340_app_pac::{
|
pub use nrf5340_app_pac::{
|
||||||
interrupt,
|
|
||||||
Interrupt,
|
Interrupt,
|
||||||
Peripherals,
|
Peripherals,
|
||||||
|
|
||||||
@ -60,156 +63,167 @@ pub mod pac {
|
|||||||
wdt0_ns as wdt0,
|
wdt0_ns as wdt0,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "nrf5340-app-ns")]
|
/// Non-Secure mode (NS) peripherals
|
||||||
#[doc(no_inline)]
|
pub mod ns {
|
||||||
pub use nrf5340_app_pac::{
|
#[cfg(feature = "nrf5340-app-ns")]
|
||||||
CLOCK_NS as CLOCK,
|
#[doc(no_inline)]
|
||||||
COMP_NS as COMP,
|
pub use nrf5340_app_pac::{
|
||||||
CTRLAP_NS as CTRLAP,
|
CLOCK_NS as CLOCK,
|
||||||
DCNF_NS as DCNF,
|
COMP_NS as COMP,
|
||||||
DPPIC_NS as DPPIC,
|
CTRLAP_NS as CTRLAP,
|
||||||
EGU0_NS as EGU0,
|
DCNF_NS as DCNF,
|
||||||
EGU1_NS as EGU1,
|
DPPIC_NS as DPPIC,
|
||||||
EGU2_NS as EGU2,
|
EGU0_NS as EGU0,
|
||||||
EGU3_NS as EGU3,
|
EGU1_NS as EGU1,
|
||||||
EGU4_NS as EGU4,
|
EGU2_NS as EGU2,
|
||||||
EGU5_NS as EGU5,
|
EGU3_NS as EGU3,
|
||||||
FPU_NS as FPU,
|
EGU4_NS as EGU4,
|
||||||
GPIOTE1_NS as GPIOTE1,
|
EGU5_NS as EGU5,
|
||||||
I2S0_NS as I2S0,
|
FPU_NS as FPU,
|
||||||
IPC_NS as IPC,
|
GPIOTE1_NS as GPIOTE1,
|
||||||
KMU_NS as KMU,
|
I2S0_NS as I2S0,
|
||||||
LPCOMP_NS as LPCOMP,
|
IPC_NS as IPC,
|
||||||
MUTEX_NS as MUTEX,
|
KMU_NS as KMU,
|
||||||
NFCT_NS as NFCT,
|
LPCOMP_NS as LPCOMP,
|
||||||
NVMC_NS as NVMC,
|
MUTEX_NS as MUTEX,
|
||||||
OSCILLATORS_NS as OSCILLATORS,
|
NFCT_NS as NFCT,
|
||||||
P0_NS as P0,
|
NVMC_NS as NVMC,
|
||||||
P1_NS as P1,
|
OSCILLATORS_NS as OSCILLATORS,
|
||||||
PDM0_NS as PDM0,
|
P0_NS as P0,
|
||||||
POWER_NS as POWER,
|
P1_NS as P1,
|
||||||
PWM0_NS as PWM0,
|
PDM0_NS as PDM0,
|
||||||
PWM1_NS as PWM1,
|
POWER_NS as POWER,
|
||||||
PWM2_NS as PWM2,
|
PWM0_NS as PWM0,
|
||||||
PWM3_NS as PWM3,
|
PWM1_NS as PWM1,
|
||||||
QDEC0_NS as QDEC0,
|
PWM2_NS as PWM2,
|
||||||
QDEC1_NS as QDEC1,
|
PWM3_NS as PWM3,
|
||||||
QSPI_NS as QSPI,
|
QDEC0_NS as QDEC0,
|
||||||
REGULATORS_NS as REGULATORS,
|
QDEC1_NS as QDEC1,
|
||||||
RESET_NS as RESET,
|
QSPI_NS as QSPI,
|
||||||
RTC0_NS as RTC0,
|
REGULATORS_NS as REGULATORS,
|
||||||
RTC1_NS as RTC1,
|
RESET_NS as RESET,
|
||||||
SAADC_NS as SAADC,
|
RTC0_NS as RTC0,
|
||||||
SPIM0_NS as SPIM0,
|
RTC1_NS as RTC1,
|
||||||
SPIM1_NS as SPIM1,
|
SAADC_NS as SAADC,
|
||||||
SPIM2_NS as SPIM2,
|
SPIM0_NS as SPIM0,
|
||||||
SPIM3_NS as SPIM3,
|
SPIM1_NS as SPIM1,
|
||||||
SPIM4_NS as SPIM4,
|
SPIM2_NS as SPIM2,
|
||||||
SPIS0_NS as SPIS0,
|
SPIM3_NS as SPIM3,
|
||||||
SPIS1_NS as SPIS1,
|
SPIM4_NS as SPIM4,
|
||||||
SPIS2_NS as SPIS2,
|
SPIS0_NS as SPIS0,
|
||||||
SPIS3_NS as SPIS3,
|
SPIS1_NS as SPIS1,
|
||||||
TIMER0_NS as TIMER0,
|
SPIS2_NS as SPIS2,
|
||||||
TIMER1_NS as TIMER1,
|
SPIS3_NS as SPIS3,
|
||||||
TIMER2_NS as TIMER2,
|
TIMER0_NS as TIMER0,
|
||||||
TWIM0_NS as TWIM0,
|
TIMER1_NS as TIMER1,
|
||||||
TWIM1_NS as TWIM1,
|
TIMER2_NS as TIMER2,
|
||||||
TWIM2_NS as TWIM2,
|
TWIM0_NS as TWIM0,
|
||||||
TWIM3_NS as TWIM3,
|
TWIM1_NS as TWIM1,
|
||||||
TWIS0_NS as TWIS0,
|
TWIM2_NS as TWIM2,
|
||||||
TWIS1_NS as TWIS1,
|
TWIM3_NS as TWIM3,
|
||||||
TWIS2_NS as TWIS2,
|
TWIS0_NS as TWIS0,
|
||||||
TWIS3_NS as TWIS3,
|
TWIS1_NS as TWIS1,
|
||||||
UARTE0_NS as UARTE0,
|
TWIS2_NS as TWIS2,
|
||||||
UARTE1_NS as UARTE1,
|
TWIS3_NS as TWIS3,
|
||||||
UARTE2_NS as UARTE2,
|
UARTE0_NS as UARTE0,
|
||||||
UARTE3_NS as UARTE3,
|
UARTE1_NS as UARTE1,
|
||||||
USBD_NS as USBD,
|
UARTE2_NS as UARTE2,
|
||||||
USBREGULATOR_NS as USBREGULATOR,
|
UARTE3_NS as UARTE3,
|
||||||
VMC_NS as VMC,
|
USBD_NS as USBD,
|
||||||
WDT0_NS as WDT0,
|
USBREGULATOR_NS as USBREGULATOR,
|
||||||
WDT1_NS as WDT1,
|
VMC_NS as VMC,
|
||||||
};
|
WDT0_NS as WDT0,
|
||||||
|
WDT1_NS as WDT1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "nrf5340-app-s")]
|
/// Secure mode (S) peripherals
|
||||||
#[doc(no_inline)]
|
pub mod s {
|
||||||
pub use nrf5340_app_pac::{
|
#[cfg(feature = "nrf5340-app-s")]
|
||||||
CACHEDATA_S as CACHEDATA,
|
#[doc(no_inline)]
|
||||||
CACHEINFO_S as CACHEINFO,
|
pub use nrf5340_app_pac::{
|
||||||
CACHE_S as CACHE,
|
CACHEDATA_S as CACHEDATA,
|
||||||
CLOCK_S as CLOCK,
|
CACHEINFO_S as CACHEINFO,
|
||||||
COMP_S as COMP,
|
CACHE_S as CACHE,
|
||||||
CRYPTOCELL_S as CRYPTOCELL,
|
CLOCK_S as CLOCK,
|
||||||
CTI_S as CTI,
|
COMP_S as COMP,
|
||||||
CTRLAP_S as CTRLAP,
|
CRYPTOCELL_S as CRYPTOCELL,
|
||||||
DCNF_S as DCNF,
|
CTI_S as CTI,
|
||||||
DPPIC_S as DPPIC,
|
CTRLAP_S as CTRLAP,
|
||||||
EGU0_S as EGU0,
|
DCNF_S as DCNF,
|
||||||
EGU1_S as EGU1,
|
DPPIC_S as DPPIC,
|
||||||
EGU2_S as EGU2,
|
EGU0_S as EGU0,
|
||||||
EGU3_S as EGU3,
|
EGU1_S as EGU1,
|
||||||
EGU4_S as EGU4,
|
EGU2_S as EGU2,
|
||||||
EGU5_S as EGU5,
|
EGU3_S as EGU3,
|
||||||
FICR_S as FICR,
|
EGU4_S as EGU4,
|
||||||
FPU_S as FPU,
|
EGU5_S as EGU5,
|
||||||
GPIOTE0_S as GPIOTE0,
|
FICR_S as FICR,
|
||||||
I2S0_S as I2S0,
|
FPU_S as FPU,
|
||||||
IPC_S as IPC,
|
GPIOTE0_S as GPIOTE0,
|
||||||
KMU_S as KMU,
|
I2S0_S as I2S0,
|
||||||
LPCOMP_S as LPCOMP,
|
IPC_S as IPC,
|
||||||
MUTEX_S as MUTEX,
|
KMU_S as KMU,
|
||||||
NFCT_S as NFCT,
|
LPCOMP_S as LPCOMP,
|
||||||
NVMC_S as NVMC,
|
MUTEX_S as MUTEX,
|
||||||
OSCILLATORS_S as OSCILLATORS,
|
NFCT_S as NFCT,
|
||||||
P0_S as P0,
|
NVMC_S as NVMC,
|
||||||
P1_S as P1,
|
OSCILLATORS_S as OSCILLATORS,
|
||||||
PDM0_S as PDM0,
|
P0_S as P0,
|
||||||
POWER_S as POWER,
|
P1_S as P1,
|
||||||
PWM0_S as PWM0,
|
PDM0_S as PDM0,
|
||||||
PWM1_S as PWM1,
|
POWER_S as POWER,
|
||||||
PWM2_S as PWM2,
|
PWM0_S as PWM0,
|
||||||
PWM3_S as PWM3,
|
PWM1_S as PWM1,
|
||||||
QDEC0_S as QDEC0,
|
PWM2_S as PWM2,
|
||||||
QDEC1_S as QDEC1,
|
PWM3_S as PWM3,
|
||||||
QSPI_S as QSPI,
|
QDEC0_S as QDEC0,
|
||||||
REGULATORS_S as REGULATORS,
|
QDEC1_S as QDEC1,
|
||||||
RESET_S as RESET,
|
QSPI_S as QSPI,
|
||||||
RTC0_S as RTC0,
|
REGULATORS_S as REGULATORS,
|
||||||
RTC1_S as RTC1,
|
RESET_S as RESET,
|
||||||
SAADC_S as SAADC,
|
RTC0_S as RTC0,
|
||||||
SPIM0_S as SPIM0,
|
RTC1_S as RTC1,
|
||||||
SPIM1_S as SPIM1,
|
SAADC_S as SAADC,
|
||||||
SPIM2_S as SPIM2,
|
SPIM0_S as SPIM0,
|
||||||
SPIM3_S as SPIM3,
|
SPIM1_S as SPIM1,
|
||||||
SPIM4_S as SPIM4,
|
SPIM2_S as SPIM2,
|
||||||
SPIS0_S as SPIS0,
|
SPIM3_S as SPIM3,
|
||||||
SPIS1_S as SPIS1,
|
SPIM4_S as SPIM4,
|
||||||
SPIS2_S as SPIS2,
|
SPIS0_S as SPIS0,
|
||||||
SPIS3_S as SPIS3,
|
SPIS1_S as SPIS1,
|
||||||
SPU_S as SPU,
|
SPIS2_S as SPIS2,
|
||||||
TAD_S as TAD,
|
SPIS3_S as SPIS3,
|
||||||
TIMER0_S as TIMER0,
|
SPU_S as SPU,
|
||||||
TIMER1_S as TIMER1,
|
TAD_S as TAD,
|
||||||
TIMER2_S as TIMER2,
|
TIMER0_S as TIMER0,
|
||||||
TWIM0_S as TWIM0,
|
TIMER1_S as TIMER1,
|
||||||
TWIM1_S as TWIM1,
|
TIMER2_S as TIMER2,
|
||||||
TWIM2_S as TWIM2,
|
TWIM0_S as TWIM0,
|
||||||
TWIM3_S as TWIM3,
|
TWIM1_S as TWIM1,
|
||||||
TWIS0_S as TWIS0,
|
TWIM2_S as TWIM2,
|
||||||
TWIS1_S as TWIS1,
|
TWIM3_S as TWIM3,
|
||||||
TWIS2_S as TWIS2,
|
TWIS0_S as TWIS0,
|
||||||
TWIS3_S as TWIS3,
|
TWIS1_S as TWIS1,
|
||||||
UARTE0_S as UARTE0,
|
TWIS2_S as TWIS2,
|
||||||
UARTE1_S as UARTE1,
|
TWIS3_S as TWIS3,
|
||||||
UARTE2_S as UARTE2,
|
UARTE0_S as UARTE0,
|
||||||
UARTE3_S as UARTE3,
|
UARTE1_S as UARTE1,
|
||||||
UICR_S as UICR,
|
UARTE2_S as UARTE2,
|
||||||
USBD_S as USBD,
|
UARTE3_S as UARTE3,
|
||||||
USBREGULATOR_S as USBREGULATOR,
|
UICR_S as UICR,
|
||||||
VMC_S as VMC,
|
USBD_S as USBD,
|
||||||
WDT0_S as WDT0,
|
USBREGULATOR_S as USBREGULATOR,
|
||||||
WDT1_S as WDT1,
|
VMC_S as VMC,
|
||||||
};
|
WDT0_S as WDT0,
|
||||||
|
WDT1_S as WDT1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "_ns")]
|
||||||
|
pub use ns::*;
|
||||||
|
#[cfg(feature = "_s")]
|
||||||
|
pub use s::*;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The maximum buffer size that the EasyDMA can send/recv in one operation.
|
/// The maximum buffer size that the EasyDMA can send/recv in one operation.
|
||||||
|
@ -7,9 +7,12 @@ pub mod pac {
|
|||||||
|
|
||||||
pub use nrf5340_net_pac::NVIC_PRIO_BITS;
|
pub use nrf5340_net_pac::NVIC_PRIO_BITS;
|
||||||
|
|
||||||
|
#[cfg(feature="rt")]
|
||||||
|
#[doc(no_inline)]
|
||||||
|
pub use nrf5340_net_pac::interrupt;
|
||||||
|
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use nrf5340_net_pac::{
|
pub use nrf5340_net_pac::{
|
||||||
interrupt,
|
|
||||||
Interrupt,
|
Interrupt,
|
||||||
Peripherals,
|
Peripherals,
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user