mirror of
https://github.com/espressif/esp-protocols.git
synced 2025-06-25 17:31:33 +02:00
Compare commits
824 Commits
websocket-
...
console_si
Author | SHA1 | Date | |
---|---|---|---|
93dd56750e | |||
1ac4e41771 | |||
e63d4e3bd8 | |||
b310abef7a | |||
842b2b22eb | |||
c1c93501b0 | |||
60d7145630 | |||
ea54eef0d0 | |||
ea14e15a6f | |||
fae80e2f3f | |||
af1f39e70d | |||
b8f3423dc0 | |||
4e178735cd | |||
8d5947e5f1 | |||
4f2ebaa753 | |||
0db29f28db | |||
223647e975 | |||
c48e44205d | |||
b9bdcf612a | |||
19baa7d43e | |||
c89d42f272 | |||
3dadce2d5e | |||
8edbac6974 | |||
163122ff54 | |||
4b7d1943ac | |||
bac742df80 | |||
5287432197 | |||
25a35e20a3 | |||
12bacdc3a0 | |||
839c79d460 | |||
13b29c2291 | |||
0cb1156480 | |||
6c7259fa7a | |||
24f7031012 | |||
62d809ac60 | |||
b992ef6914 | |||
9cc594afaa | |||
4cf9e505e1 | |||
c8c05075fb | |||
cb6e03ac62 | |||
2e42b9bb49 | |||
86f7a8bbe3 | |||
7b5a41deea | |||
38d50eede0 | |||
27303d28b2 | |||
d273e10819 | |||
60c87ddf26 | |||
a95891e211 | |||
411dced3e2 | |||
d4925f2bd6 | |||
ae629ed3a9 | |||
42fe60828f | |||
36899f1135 | |||
0714e100ee | |||
cbfee945a0 | |||
71bb461ed8 | |||
5143f5ac01 | |||
7e83741615 | |||
b880fc0367 | |||
f6d5186e5b | |||
8eb3a0feea | |||
28cd898eca | |||
a22391ae2c | |||
f5a0d5fb40 | |||
ecc465daa3 | |||
181b6e4013 | |||
40e3875f76 | |||
ddc3eb62d0 | |||
3625889049 | |||
2bd6163ec8 | |||
f1eb46580e | |||
1c20328dcf | |||
6de22f3893 | |||
e280b3b541 | |||
00d7c40848 | |||
4f1769ec71 | |||
20dd910b3a | |||
3635e2fabc | |||
84035d8f3b | |||
e620eb5fb1 | |||
7d4755f119 | |||
588465d9db | |||
c443326a34 | |||
79a0e57ca1 | |||
68392f0ba9 | |||
a67cbbcab9 | |||
b5177cb23a | |||
cab0e1d10e | |||
fbc79a846b | |||
a50f91f422 | |||
4910e89249 | |||
c562461711 | |||
8b9c957fe0 | |||
f0df12dad3 | |||
9637517192 | |||
e085826dbb | |||
c974c14220 | |||
247baeed22 | |||
613d67d1cf | |||
441f79022e | |||
4de52981cb | |||
ef1c5eb28a | |||
9a3aa1d23f | |||
64b0e4ef1a | |||
fcff00740a | |||
1102133458 | |||
4f54c49912 | |||
910f6ffadc | |||
9836a8620f | |||
af0ed62ecf | |||
217a96a2e4 | |||
6a94e61a7e | |||
c8fe4092c4 | |||
31187b7d17 | |||
ab94566995 | |||
f67511c2c1 | |||
05348534a6 | |||
18ea910f02 | |||
62be981c92 | |||
6daf6c6ba6 | |||
b0d3b41aae | |||
f48d9b2fcf | |||
6c299c068b | |||
ea5d3cee29 | |||
7330597586 | |||
1a0a41fa2d | |||
2f7cbd16db | |||
87dcd7dc7d | |||
8e5a27f4b7 | |||
6528f446bc | |||
4fa3023ea2 | |||
10f8200564 | |||
a547ec8147 | |||
db0e20f446 | |||
ca3fce003e | |||
f6ff132eb1 | |||
8bb207e9bb | |||
76047a4cc6 | |||
ee9b04f598 | |||
d238e9311b | |||
a838af46a6 | |||
5ed3e9a6a1 | |||
5b3346f5c5 | |||
a06fb7714b | |||
e69a9ebb3d | |||
2e607e8ffb | |||
0a9765626b | |||
537d170f1d | |||
0a682e7f12 | |||
afb69308df | |||
284cdeb2ed | |||
97d52495d4 | |||
423e965c88 | |||
e762ada551 | |||
31d4323f53 | |||
97831c62b1 | |||
ceedcfca23 | |||
7547267336 | |||
bf114d3624 | |||
574738b8d3 | |||
ee09ff45e5 | |||
895a72b27d | |||
bf32e452d6 | |||
4c7720a2c1 | |||
c92ce075fd | |||
f29719fa0b | |||
2d1990614a | |||
2863e94a11 | |||
ba45e9a07e | |||
610372f5a7 | |||
13eca128fb | |||
c492d87316 | |||
200cbb3383 | |||
a96f17d9a1 | |||
cbda15724c | |||
d0814bf963 | |||
a089e0d680 | |||
ef4985cce6 | |||
01c26c82fa | |||
08f1f0175d | |||
a6817e0c7f | |||
a2050ac041 | |||
6015c19c31 | |||
5df8fdb713 | |||
ef3f0ee688 | |||
996fef7fcf | |||
9f87a8ca77 | |||
3bf0511938 | |||
319fce018e | |||
44bae24c78 | |||
d047ff569c | |||
02be2b76f8 | |||
1c850ddacf | |||
9ae88aab48 | |||
c6db3ea84c | |||
b23eedac3a | |||
1407dfc2e7 | |||
34c6f52f70 | |||
c674b8855d | |||
256389613f | |||
2865255ec0 | |||
7b2470ddd6 | |||
dda2722563 | |||
36db37ea2b | |||
4f013e3522 | |||
231392d0c6 | |||
9fb01ca534 | |||
d464ed7d30 | |||
b94a211e4b | |||
73f2800b59 | |||
e00e056162 | |||
1b134486db | |||
7ba1085e9f | |||
3bdb2067e0 | |||
1d6888445d | |||
d68624ec4f | |||
d4825f5c53 | |||
de1480a072 | |||
b9b4a75000 | |||
cc259aa035 | |||
91134f10ff | |||
fb8a2f0198 | |||
b87bef52e5 | |||
28813148b2 | |||
ae38f27997 | |||
d0c9070715 | |||
a8339e4618 | |||
12cfcb5aed | |||
2cfffb056e | |||
0247926219 | |||
05fff94b91 | |||
8958d5e37c | |||
f71192b876 | |||
f9b47900f2 | |||
0e215b118f | |||
dc8b916561 | |||
a01096f621 | |||
3de4727385 | |||
59053b8c98 | |||
2956477353 | |||
1d9b6f7e90 | |||
6b684ceb0f | |||
5304a6ec0e | |||
c7f20ee98e | |||
7d47ec3b6b | |||
e4c8a5932c | |||
b56b1c577b | |||
4e212c31fe | |||
9a7bd90ad9 | |||
4314c78ca0 | |||
457f8335bb | |||
42565ff5d7 | |||
6e2bb518fd | |||
2180ab17d8 | |||
ac5d43882b | |||
3f0262dfe5 | |||
74787c9aa8 | |||
045009bb82 | |||
79c11e9ecd | |||
c73c797595 | |||
3330b96b10 | |||
1547aa8c03 | |||
1ca139109a | |||
55c1223a1e | |||
0643613eee | |||
55dc56462f | |||
698fb3ae00 | |||
23a537b19b | |||
aee016d6e4 | |||
f1ae14f263 | |||
65c0e0e195 | |||
f71f61ff0a | |||
652314e73d | |||
71a2388acb | |||
ebc36a3519 | |||
5097065a22 | |||
193ac643e4 | |||
945bd17701 | |||
9d45d505d5 | |||
96fcbc0694 | |||
6b4767cba0 | |||
f148c98b13 | |||
06103e4bb4 | |||
c6fc267e5f | |||
52b7f001a2 | |||
cf504ec900 | |||
ab2e08f96c | |||
511ed541b8 | |||
8d0e2aab6b | |||
a02bf05eed | |||
85a2e25093 | |||
a9b5e66d0f | |||
988b3f9905 | |||
53b59332dc | |||
bf84ae940a | |||
a89a0ab7a3 | |||
fe536e476c | |||
afafcb7c24 | |||
55b4775ca8 | |||
1c6c610f20 | |||
9b48b0a5e0 | |||
25ac2d98c6 | |||
ce175df376 | |||
9d9d0db1ee | |||
b704aaa33b | |||
7a21db23ad | |||
fcd6f0bb14 | |||
52d7458b99 | |||
56cb58ced7 | |||
77a7538a02 | |||
c8d0a13f0e | |||
582f5b5ff6 | |||
06dd536d52 | |||
e66b19c414 | |||
0ad6cad8b2 | |||
ffa13e4b90 | |||
0fc1fc6b23 | |||
f1d1d79daf | |||
36d0d32b35 | |||
3bf488eb86 | |||
061885ad23 | |||
ab70791625 | |||
62cb235aa9 | |||
04c711f757 | |||
467fec5c9b | |||
5193ebc6ea | |||
3498e86d8b | |||
07a347f907 | |||
d9c9681094 | |||
7310a7a0bc | |||
accf9244ca | |||
290197c210 | |||
b8d1e58778 | |||
cc4d33d871 | |||
ef0e48a678 | |||
187ef7676e | |||
a8714730fb | |||
d2f519f9e5 | |||
a045c1c885 | |||
543521a220 | |||
85be67e708 | |||
5b1b2cce75 | |||
1029078541 | |||
0015e5411c | |||
65b64e1fc1 | |||
d07237b2ce | |||
3c65fde2a7 | |||
35833d2730 | |||
bbb4b7e686 | |||
64e31dae48 | |||
63ce3a5d59 | |||
5dd138c883 | |||
088f7ac3f8 | |||
e079f8ba98 | |||
ff2b0734ea | |||
330332a0fb | |||
48c157bc46 | |||
98bf3efeb6 | |||
ae8479c77e | |||
444fae9066 | |||
bb4c002841 | |||
656ab21c9b | |||
2099434b3f | |||
8f00fc182a | |||
d74c296182 | |||
c4e85bd099 | |||
85ba60e405 | |||
89e1bd27b3 | |||
341fcb0f40 | |||
469f953b28 | |||
381eb314dc | |||
1ffc20c8e3 | |||
5c245dbdb5 | |||
134a9a9eee | |||
010f98ca80 | |||
6e4e4fab1d | |||
b6852a0588 | |||
415e04a55f | |||
3456781494 | |||
d1129f3d19 | |||
973837dd66 | |||
36de9afe0c | |||
0d5081b841 | |||
85c7282641 | |||
57afa38f49 | |||
238ee96783 | |||
10e6348e09 | |||
a286634359 | |||
4cdfc857ad | |||
371a32d4ae | |||
dc4e54e99a | |||
d66f9dc158 | |||
4980ac85b7 | |||
626eb52d04 | |||
82b1aa9280 | |||
e8145fcede | |||
9c3e24b6cf | |||
b4d85d6aae | |||
0b102f6286 | |||
06e7baf2c2 | |||
3662c149fb | |||
a243d7e878 | |||
ef1bae5cdd | |||
4cefcd3606 | |||
a177b3d024 | |||
b7e73d25a7 | |||
9b403d477f | |||
d723fb7a5a | |||
9905fe4cf6 | |||
055f051f53 | |||
8dc3e5835c | |||
0cf08fb676 | |||
ac7bf465d2 | |||
2cf7518114 | |||
057a5d2db8 | |||
63bff632df | |||
938ddf16b9 | |||
0c84c9750c | |||
952e5df477 | |||
e3c4391246 | |||
98138189c9 | |||
30dae8f7ed | |||
b76d3fbff9 | |||
f605fdd632 | |||
abbc8d9c5a | |||
a0297743dd | |||
3bcc46276a | |||
f0d0698582 | |||
91262baede | |||
cb2375827b | |||
cc0f2b3cf0 | |||
47d57a5b14 | |||
278b7bef3c | |||
a165452ca1 | |||
55f95fb790 | |||
9b76388163 | |||
0d1d73eb35 | |||
88d3eda156 | |||
622a360e97 | |||
4358c3ceab | |||
f00c3be139 | |||
c05558ba28 | |||
c0c1a65598 | |||
dab12309e2 | |||
789670e8c5 | |||
131613c5cc | |||
919091766d | |||
4e4ab0908d | |||
54e3a85983 | |||
98dfb691b6 | |||
ff7d214f9c | |||
ee6dbbfeaa | |||
a14331ad01 | |||
f3754a3683 | |||
c1176ccdcc | |||
df51e60ac0 | |||
9e83b1eb0e | |||
f82cbfde7b | |||
96d13293ab | |||
3b49d1f559 | |||
3e7591e92a | |||
de830e51d4 | |||
21c0878f0e | |||
a96c890f97 | |||
86d107635b | |||
57672d5add | |||
e8ea8786d2 | |||
142200c7ca | |||
6c47cfe30a | |||
0ae8c3ca33 | |||
5472d5c52f | |||
51a50db0fd | |||
e1660a1806 | |||
84f18bddfb | |||
609594a849 | |||
66e6d4cbf8 | |||
4868689111 | |||
f3ff98bb82 | |||
58a0b57e12 | |||
3fd4391c38 | |||
a16aab6979 | |||
1e0aefd72a | |||
ebf122bd36 | |||
5addf9e885 | |||
6dbfc69627 | |||
128c0a2d87 | |||
1f91d248f5 | |||
8fe2a3a661 | |||
417591b99f | |||
d56b5d90ea | |||
b6b20ad399 | |||
8863ed944d | |||
78001ec871 | |||
4a52cf23f5 | |||
00e7675913 | |||
87c269911d | |||
eb536a74a0 | |||
b720d02fca | |||
3e93ea9b76 | |||
2c764b1b7a | |||
f836ae7f65 | |||
e9a1c26e0c | |||
4b5f24f5b8 | |||
05675c7d63 | |||
30f37c0565 | |||
ddc58e8220 | |||
fa951bf320 | |||
605d1fab73 | |||
58bf2186f7 | |||
d39a4c744e | |||
ec491ec536 | |||
defdfd59b6 | |||
7f42c31252 | |||
94ae672041 | |||
e5a3a3df1d | |||
7710ea9a11 | |||
034c55e18a | |||
ec03fec3d3 | |||
5909e9e54c | |||
82e2a5dcc1 | |||
48e4d4035c | |||
ba3fa24a96 | |||
869f5b75af | |||
ac6dcb6830 | |||
085dbd8c4e | |||
f78e8cfce8 | |||
6cdf5ee074 | |||
fcb5515f1e | |||
9fdbe5f130 | |||
20e6e9e7fe | |||
3c5b13ea0d | |||
c588263b45 | |||
6258edf23b | |||
c8b0d5ea9d | |||
5252b1d801 | |||
4e11cc86fe | |||
7af91ec490 | |||
01256d3e34 | |||
5a2d4eab6d | |||
9de3f534e2 | |||
bcabc8ea16 | |||
dfb27b39cc | |||
076c095aec | |||
7dd0bc1fff | |||
7e82a7cef7 | |||
ae381b779f | |||
d0f4e68c7a | |||
941dc5c42f | |||
525c64915e | |||
f0839d909b | |||
69902ea8e1 | |||
d5001e894f | |||
145a8d2291 | |||
d0bbe880b6 | |||
4a9d55edf7 | |||
be2a924674 | |||
76fcd4128a | |||
fd8499c874 | |||
38b4fe2353 | |||
eb7eeb58d3 | |||
b26606252f | |||
5e087d82d6 | |||
91a3d95f96 | |||
6d6dd2b75e | |||
0611b0cb67 | |||
cf6ed1cc53 | |||
52306e914f | |||
d37ab6dd25 | |||
05dcd8f0ee | |||
5c55ea6e02 | |||
0c71c7bfe1 | |||
4c368c0090 | |||
c2abeff476 | |||
6a92d3253f | |||
af2275341e | |||
b0957e70fd | |||
47c7266103 | |||
40da0d29be | |||
5f6b6f9273 | |||
8a120829e2 | |||
46f28a8011 | |||
5a81eaea3f | |||
2ddaee2b6e | |||
73b1763029 | |||
27fc285000 | |||
93e6efedc7 | |||
bc4cda8ea7 | |||
8a8d58d4dc | |||
402baebfee | |||
9fa25ef3b6 | |||
121b525108 | |||
418fb60dd9 | |||
4049b3b5ed | |||
c8821199a2 | |||
1eb5df9780 | |||
b62b4b3e25 | |||
4d8aec1ad3 | |||
6d649102ab | |||
3ad559bf3f | |||
ab3fa69b8f | |||
c3a5826d60 | |||
cbcbe4ffd7 | |||
adc34309dc | |||
7a8329cb5c | |||
c30617d872 | |||
1e5eeb16ec | |||
22c7c0a195 | |||
eda5d72acf | |||
1623c0e729 | |||
b114ed69de | |||
49a00c2455 | |||
dec1d7dcf8 | |||
2ffd22382d | |||
487287157d | |||
1fe901f70f | |||
2cf9fd8891 | |||
89439e0a9b | |||
becd5d0266 | |||
0d7a30944e | |||
e2653e7fb0 | |||
df6a208f45 | |||
1fdffbbbab | |||
d5566971fb | |||
988d120902 | |||
fd47df3e30 | |||
2cb3a6e35e | |||
ccd48bc9a9 | |||
825652f3e1 | |||
fc53888115 | |||
7635c0479b | |||
d5fe42bffb | |||
e0bc60a586 | |||
9772e49b26 | |||
110f1f652d | |||
ed77d65a82 | |||
6021a88657 | |||
78f71ecdf6 | |||
07f57523c8 | |||
ad67a23097 | |||
078abd8161 | |||
f1f6c5de05 | |||
12fb6d8e15 | |||
2258d5bcef | |||
54f5c6f29c | |||
3319844745 | |||
ac70c9aba8 | |||
123ae8db62 | |||
e24cc7d1ae | |||
9d9aac1569 | |||
ef9a758662 | |||
2a23f355c7 | |||
07399011f7 | |||
2b7d43e1f8 | |||
7bf23a7fe9 | |||
881ca095f0 | |||
d9fa457b4f | |||
4eb3e89841 | |||
74aee42f80 | |||
b5e5a64e7f | |||
6713ffedcc | |||
817c4fd2e8 | |||
8f0dc6d578 | |||
7a3aa26df8 | |||
c7ff8ba0c9 | |||
80ce63d73e | |||
d20666f3a0 | |||
cd3cc0be3b | |||
1734e59057 | |||
662a4ce050 | |||
fb1de80fd7 | |||
1f35e9a728 | |||
573855031d | |||
d1c62628b8 | |||
48b819bbc1 | |||
dfcefc38fd | |||
879a6cdfa3 | |||
53e2aa3241 | |||
3cc64469c1 | |||
248b11bb0a | |||
d52dddfea5 | |||
67d310b988 | |||
901124b7ee | |||
f6ff165be9 | |||
d8d6b35553 | |||
f44c569422 | |||
7dfe14c83d | |||
286c646725 | |||
0582187b9a | |||
28d5b74a00 | |||
c70d527d80 | |||
7cdf96cffa | |||
407875d9c5 | |||
3e753f5e2d | |||
aaba3fc47a | |||
144d4ad1d4 | |||
e431b6b7fe | |||
ed71a239a8 | |||
680bad646f | |||
271665e0cb | |||
7fb6686716 | |||
4912bef740 | |||
181a22ec2b | |||
4172219225 | |||
9a0803ad7e | |||
05ddd5f0e4 | |||
7e3b35efd9 | |||
98d2c1a073 | |||
84cbb1f3cf | |||
4c6818ee97 | |||
c440114d14 | |||
c0f65a6997 | |||
778eaa6ced | |||
25f8656fbc | |||
6ea0ea93fa | |||
d9aec9fc71 | |||
985e69117e | |||
75deebbf03 | |||
fdd27dc9fa | |||
2ec3b558ea | |||
450cbf03cf | |||
34f6d8dd33 | |||
b6efc688b5 | |||
11e4aebefd | |||
90e4babc61 | |||
c546ab8dea | |||
6582b41cd1 | |||
358d26c8a1 | |||
8d08e5ed95 | |||
2ac83d0f27 | |||
98e3171db6 | |||
2f85c075be | |||
b30a7fec27 | |||
7a4fdad16d | |||
b4e57424f9 | |||
2763bcdb8d | |||
dce0b26ef8 | |||
ade4aeffa5 | |||
8cd0e8a501 | |||
9b3b41c3f1 | |||
ea2300753e | |||
81c219d4ee | |||
0c17121ad7 | |||
67173f6770 | |||
fed787f54f | |||
b4ab30b5de | |||
dd714947d6 | |||
39de491597 | |||
19acac76eb | |||
0191d6fcd7 | |||
b26c8665f8 | |||
98069f9ca2 | |||
ad29d34bb6 | |||
9f1be3668e | |||
450c9de67b | |||
c7701d41f8 | |||
b9726db48e | |||
f1ccc4052e | |||
84bd1d7e88 | |||
259d3fc609 | |||
6d99957f2d | |||
7784d002fc | |||
9ebd9852ca | |||
26f00e8ddb | |||
bce7d5231c | |||
ef924f1aa5 | |||
ad8c92db52 | |||
3aa605fe24 | |||
00a72b8920 | |||
907e7ee29e | |||
b367484361 | |||
4a8582f500 | |||
75de31cea3 | |||
4acf639afc | |||
1a1cf71a84 | |||
5924dafd94 | |||
91bb5095f5 | |||
caa4884b3a | |||
441a53c604 | |||
7fbf8e5247 | |||
7346ed9765 | |||
76298ff70e | |||
0875008a46 | |||
a661e51f7e | |||
3ced2d9709 | |||
ba88d7fdbc | |||
4f3c4299d6 | |||
2a4e684848 | |||
541b391c3e | |||
279a3cb6e0 | |||
60bb0eea99 | |||
52de8f1b2a | |||
503218b3ba | |||
38149c8d9b | |||
1984da150d | |||
9e37f537bd | |||
e55f54b69e | |||
6e4d8a19ed | |||
e98cf16859 | |||
be3d2ece55 | |||
15ed885035 | |||
b72a9ae710 | |||
0733ea8ff4 | |||
15cbc9bd50 | |||
bb7f198bea | |||
d3f7ea67fb | |||
6e5bede4c7 | |||
d191a720d1 | |||
cc0d52793b | |||
804a8d5df6 | |||
74040cfd1a | |||
16ea3f7eb8 | |||
1f5eb396c5 | |||
827bebd2bc | |||
745201b188 | |||
ca266cabd0 | |||
e54b240870 | |||
4ccc32ffb5 | |||
91a177edd4 | |||
f303cdc70b | |||
ab8c2da395 | |||
04a7643d67 | |||
8b3d420055 | |||
50b083a58c | |||
5d27b2681a |
140
.flake8
Normal file
140
.flake8
Normal file
@ -0,0 +1,140 @@
|
||||
[flake8]
|
||||
|
||||
select =
|
||||
# Full lists are given in order to suppress all errors from other plugins
|
||||
# Full list of pyflakes error codes:
|
||||
F401, # module imported but unused
|
||||
F402, # import module from line N shadowed by loop variable
|
||||
F403, # 'from module import *' used; unable to detect undefined names
|
||||
F404, # future import(s) name after other statements
|
||||
F405, # name may be undefined, or defined from star imports: module
|
||||
F406, # 'from module import *' only allowed at module level
|
||||
F407, # an undefined __future__ feature name was imported
|
||||
F601, # dictionary key name repeated with different values
|
||||
F602, # dictionary key variable name repeated with different values
|
||||
F621, # too many expressions in an assignment with star-unpacking
|
||||
F622, # two or more starred expressions in an assignment (a, *b, *c = d)
|
||||
F631, # assertion test is a tuple, which are always True
|
||||
F701, # a break statement outside of a while or for loop
|
||||
F702, # a continue statement outside of a while or for loop
|
||||
F703, # a continue statement in a finally block in a loop
|
||||
F704, # a yield or yield from statement outside of a function
|
||||
F705, # a return statement with arguments inside a generator
|
||||
F706, # a return statement outside of a function/method
|
||||
F707, # an except: block as not the last exception handler
|
||||
F721, F722, # doctest syntax error syntax error in forward type annotation
|
||||
F811, # redefinition of unused name from line N
|
||||
F812, # list comprehension redefines name from line N
|
||||
F821, # undefined name name
|
||||
F822, # undefined name name in __all__
|
||||
F823, # local variable name referenced before assignment
|
||||
F831, # duplicate argument name in function definition
|
||||
F841, # local variable name is assigned to but never used
|
||||
F901, # raise NotImplemented should be raise NotImplementedError
|
||||
|
||||
# Full list of pycodestyle violations:
|
||||
E101, # indentation contains mixed spaces and tabs
|
||||
E111, # indentation is not a multiple of four
|
||||
E112, # expected an indented block
|
||||
E113, # unexpected indentation
|
||||
E114, # indentation is not a multiple of four (comment)
|
||||
E115, # expected an indented block (comment)
|
||||
E116, # unexpected indentation (comment)
|
||||
E121, # continuation line under-indented for hanging indent
|
||||
E122, # continuation line missing indentation or outdented
|
||||
E123, # closing bracket does not match indentation of opening bracket's line
|
||||
E124, # closing bracket does not match visual indentation
|
||||
E125, # continuation line with same indent as next logical line
|
||||
E126, # continuation line over-indented for hanging indent
|
||||
E127, # continuation line over-indented for visual indent
|
||||
E128, # continuation line under-indented for visual indent
|
||||
E129, # visually indented line with same indent as next logical line
|
||||
E131, # continuation line unaligned for hanging indent
|
||||
E133, # closing bracket is missing indentation
|
||||
E201, # whitespace after '('
|
||||
E202, # whitespace before ')'
|
||||
E203, # whitespace before ':'
|
||||
E211, # whitespace before '('
|
||||
E221, # multiple spaces before operator
|
||||
E222, # multiple spaces after operator
|
||||
E223, # tab before operator
|
||||
E224, # tab after operator
|
||||
E225, # missing whitespace around operator
|
||||
E226, # missing whitespace around arithmetic operator
|
||||
E227, # missing whitespace around bitwise or shift operator
|
||||
E228, # missing whitespace around modulo operator
|
||||
E231, # missing whitespace after ',', ';', or ':'
|
||||
E241, # multiple spaces after ','
|
||||
E242, # tab after ','
|
||||
E251, # unexpected spaces around keyword / parameter equals
|
||||
E261, # at least two spaces before inline comment
|
||||
E262, # inline comment should start with '# '
|
||||
E265, # block comment should start with '# '
|
||||
E266, # too many leading '#' for block comment
|
||||
E271, # multiple spaces after keyword
|
||||
E272, # multiple spaces before keyword
|
||||
E273, # tab after keyword
|
||||
E274, # tab before keyword
|
||||
E275, # missing whitespace after keyword
|
||||
E301, # expected 1 blank line, found 0
|
||||
E302, # expected 2 blank lines, found 0
|
||||
E303, # too many blank lines
|
||||
E304, # blank lines found after function decorator
|
||||
E305, # expected 2 blank lines after end of function or class
|
||||
E306, # expected 1 blank line before a nested definition
|
||||
E401, # multiple imports on one line
|
||||
E402, # module level import not at top of file
|
||||
E501, # line too long (82 > 79 characters)
|
||||
E502, # the backslash is redundant between brackets
|
||||
E701, # multiple statements on one line (colon)
|
||||
E702, # multiple statements on one line (semicolon)
|
||||
E703, # statement ends with a semicolon
|
||||
E704, # multiple statements on one line (def)
|
||||
E711, # comparison to None should be 'if cond is None:'
|
||||
E712, # comparison to True should be 'if cond is True:' or 'if cond:'
|
||||
E713, # test for membership should be 'not in'
|
||||
E714, # test for object identity should be 'is not'
|
||||
E721, # do not compare types, use 'isinstance()'
|
||||
E722, # do not use bare except, specify exception instead
|
||||
E731, # do not assign a lambda expression, use a def
|
||||
E741, # do not use variables named 'l', 'O', or 'I'
|
||||
E742, # do not define classes named 'l', 'O', or 'I'
|
||||
E743, # do not define functions named 'l', 'O', or 'I'
|
||||
E901, # SyntaxError or IndentationError
|
||||
E902, # IOError
|
||||
W191, # indentation contains tabs
|
||||
W291, # trailing whitespace
|
||||
W292, # no newline at end of file
|
||||
W293, # blank line contains whitespace
|
||||
W391, # blank line at end of file
|
||||
W503, # line break before binary operator
|
||||
W504, # line break after binary operator
|
||||
W505, # doc line too long (82 > 79 characters)
|
||||
W601, # .has_key() is deprecated, use 'in'
|
||||
W602, # deprecated form of raising exception
|
||||
W603, # '<>' is deprecated, use '!='
|
||||
W604, # backticks are deprecated, use 'repr()'
|
||||
W605, # invalid escape sequence 'x'
|
||||
W606, # 'async' and 'await' are reserved keywords starting with Python 3.7
|
||||
|
||||
# Full list of flake8 violations
|
||||
E999, # failed to compile a file into an Abstract Syntax Tree for the plugins that require it
|
||||
|
||||
# Full list of mccabe violations
|
||||
C901 # complexity value provided by the user
|
||||
|
||||
ignore =
|
||||
E221, # multiple spaces before operator
|
||||
E231, # missing whitespace after ',', ';', or ':'
|
||||
E241, # multiple spaces after ','
|
||||
W503, # line break before binary operator
|
||||
W504 # line break after binary operator
|
||||
|
||||
max-line-length = 160
|
||||
|
||||
show_source = True
|
||||
|
||||
statistics = True
|
||||
|
||||
exclude =
|
||||
docs/asio/conf_common.py
|
2
.git-blame-ignore-revs
Normal file
2
.git-blame-ignore-revs
Normal file
@ -0,0 +1,2 @@
|
||||
# Formating according pre-commit hooks
|
||||
945bd177011d984b705daee9b895f88212292a42
|
51
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
51
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
name: Installation or build bug report
|
||||
description: Report installation or build bugs
|
||||
labels: ['Type: Bug']
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Answers checklist.
|
||||
description: Before submitting a new issue, please follow the checklist and try to find the answer.
|
||||
options:
|
||||
- label: I have read the documentation for esp-protocols [components](https://github.com/espressif/esp-protocols#readme) and the issue is not addressed there.
|
||||
required: true
|
||||
- label: I have updated my esp-protocols branch (master or release) to the latest version and checked that the issue is present there.
|
||||
required: true
|
||||
- label: I have searched the issue tracker for a similar issue and not found a similar issue.
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: component
|
||||
attributes:
|
||||
label: What component are you using? If you choose Other, provide details in More Information.
|
||||
multiple: false
|
||||
options:
|
||||
- ASIO port
|
||||
- esp_modem
|
||||
- esp_websocket_client
|
||||
- mDNS
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: component_id
|
||||
attributes:
|
||||
label: component version
|
||||
description: Which component version does this issue occur on? (see your `idf_component.yml`)
|
||||
placeholder: ex. 1.0.0
|
||||
- type: input
|
||||
id: idf_version
|
||||
attributes:
|
||||
label: IDF version.
|
||||
description: On which IDF version does this issue occur on? Run `git describe --tags` to find it.
|
||||
placeholder: ex. v3.2-dev-1148-g96cd3b75c
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: more-info
|
||||
attributes:
|
||||
label: More Information.
|
||||
description: Do you have any other information from investigating this?
|
||||
placeholder: ex. I tried on my friend's Windows 10 PC and the command works there.
|
||||
validations:
|
||||
required: false
|
14
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
14
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: esp-protocols documentation links
|
||||
url: https://github.com/espressif/esp-protocols#readme
|
||||
about: Documenation for esp-protocols components.
|
||||
- name: ESP-IDF Programming Guide
|
||||
url: https://docs.espressif.com/projects/esp-idf/en/latest/
|
||||
about: Documentation for configuring and using ESP-IDF.
|
||||
- name: Espressif documentation page
|
||||
url: https://www.espressif.com/en/support/download/documents
|
||||
about: Hardware documentation (datasheets, Technical Reference Manual, etc).
|
||||
- name: Forum
|
||||
url: https://esp32.com
|
||||
about: For questions about using ESP-IDF and/or ESP32 series chips. Please submit all questions starting "How do I..." here.
|
33
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
33
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
name: Feature request
|
||||
description: Suggest an idea or new component for this project.
|
||||
labels: ['Type: Feature Request']
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
* We welcome any ideas or feature requests! It’s helpful if you can explain exactly why the feature would be useful.
|
||||
* There are usually some outstanding feature requests in the [existing issues list](https://github.com/espressif/esp-protocols/labels/Type%3A%20Feature%20Request), feel free to add comments to them.
|
||||
- type: textarea
|
||||
id: problem-related
|
||||
attributes:
|
||||
label: Is your feature request related to a problem?
|
||||
description: Please provide a clear and concise description of what the problem is.
|
||||
placeholder: ex. I'm always frustrated when ...
|
||||
- type: textarea
|
||||
id: solution
|
||||
attributes:
|
||||
label: Describe the solution you'd like.
|
||||
description: Please provide a clear and concise description of what you want to happen.
|
||||
placeholder: ex. When building my application ...
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: Describe alternatives you've considered.
|
||||
description: Please provide a clear and concise description of any alternative solutions or features you've considered.
|
||||
placeholder: ex. Choosing other approach wouldn't work, because ...
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional context.
|
||||
description: Please add any other context or screenshots about the feature request here.
|
||||
placeholder: ex. This would work only when ...
|
23
.github/ISSUE_TEMPLATE/other-issue.yml
vendored
Normal file
23
.github/ISSUE_TEMPLATE/other-issue.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
name: General issue report
|
||||
description: File an issue report
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Answers checklist.
|
||||
description: Before submitting a new issue, please follow the checklist and try to find the answer.
|
||||
options:
|
||||
- label: I have read the documentation for esp-protocols [components](https://github.com/espressif/esp-protocols#readme) and the issue is not addressed there.
|
||||
required: true
|
||||
- label: I have updated my esp-protocols branch (master or release) to the latest version and checked that the issue is present there.
|
||||
required: true
|
||||
- label: I have searched the issue tracker for a similar issue and not found a similar issue.
|
||||
required: true
|
||||
- type: textarea
|
||||
id: issue
|
||||
attributes:
|
||||
label: General issue report
|
||||
description: Your issue report goes here.
|
||||
placeholder: ex. How do I...
|
||||
validations:
|
||||
required: true
|
100
.github/workflows/asio__build-target-test.yml
vendored
Normal file
100
.github/workflows/asio__build-target-test.yml
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
name: "asio: build/target-tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
|
||||
jobs:
|
||||
build_asio:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'asio') || github.event_name == 'push'
|
||||
name: Build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.0", "release-v5.1"]
|
||||
idf_target: ["esp32", "esp32s2"]
|
||||
example: ["asio_chat", "async_request", "socks4", "ssl_client_server", "tcp_echo_server", "udp_echo_server"]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TEST_DIR: components/asio/examples
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
working-directory: ${{ env.TEST_DIR }}/${{ matrix.example }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
test -f sdkconfig.ci && cat sdkconfig.ci >> sdkconfig.defaults || echo "No sdkconfig.ci"
|
||||
idf.py set-target ${{ matrix.idf_target }}
|
||||
idf.py build
|
||||
- name: Merge binaries with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }} for ${{ matrix.example }}
|
||||
working-directory: ${{ env.TEST_DIR }}/${{ matrix.example }}/build
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
esptool.py --chip ${{ matrix.idf_target }} merge_bin --fill-flash-size 4MB -o flash_image.bin @flash_args
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.example }}
|
||||
path: |
|
||||
${{ env.TEST_DIR }}/${{ matrix.example }}/build/bootloader/bootloader.bin
|
||||
${{ env.TEST_DIR }}/${{ matrix.example }}/build//partition_table/partition-table.bin
|
||||
${{ env.TEST_DIR }}/${{ matrix.example }}/build/*.bin
|
||||
${{ env.TEST_DIR }}/${{ matrix.example }}/build/*.elf
|
||||
${{ env.TEST_DIR }}/${{ matrix.example }}/build/flasher_args.json
|
||||
${{ env.TEST_DIR }}/${{ matrix.example }}/build/config/sdkconfig.h
|
||||
${{ env.TEST_DIR }}/${{ matrix.example }}/build/config/sdkconfig.json
|
||||
if-no-files-found: error
|
||||
|
||||
target_tests_asio:
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: |
|
||||
github.repository == 'espressif/esp-protocols' &&
|
||||
( contains(github.event.pull_request.labels.*.name, 'asio') || github.event_name == 'push' )
|
||||
name: Target tests
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.0"]
|
||||
idf_target: ["esp32"]
|
||||
example: ["asio_chat", "tcp_echo_server", "udp_echo_server", "ssl_client_server"]
|
||||
needs: build_asio
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
env:
|
||||
TEST_DIR: components/asio/examples
|
||||
steps:
|
||||
- name: Clear repository
|
||||
run: sudo rm -fr $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: examples_app_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.example }}
|
||||
path: ${{ env.TEST_DIR }}/${{ matrix.example }}/build
|
||||
- name: Install Python packages
|
||||
env:
|
||||
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
|
||||
run: |
|
||||
sudo apt-get install -y dnsutils
|
||||
- name: Download Example Test to target ${{ matrix.config }}
|
||||
run: |
|
||||
python -m esptool --chip ${{ matrix.idf_target }} write_flash 0x0 ${{ env.TEST_DIR }}/${{ matrix.example }}/build/flash_image.bin
|
||||
- name: Run Example Test ${{ matrix.example }} on target
|
||||
working-directory: ${{ env.TEST_DIR }}/${{ matrix.example }}
|
||||
run: |
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.config }}.xml --target=${{ matrix.idf_target }}
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: examples_results_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.example }}
|
||||
path: ${{ env.TEST_DIR }}/${{ matrix.example }}/*.xml
|
26
.github/workflows/build-websockets.yml
vendored
26
.github/workflows/build-websockets.yml
vendored
@ -1,26 +0,0 @@
|
||||
name: Build Websockets
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32"]
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
path: esp-protocols
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/esp_websocket_client/examples/
|
||||
idf.py build
|
36
.github/workflows/build.yml
vendored
36
.github/workflows/build.yml
vendored
@ -1,36 +0,0 @@
|
||||
name: Build
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v4.1", "release-v4.2", "release-v4.3", "release-v4.4"]
|
||||
example: ["pppos_client", "modem_console", "ap_to_pppos", "simple_cmux_client"]
|
||||
idf_target: ["esp32"]
|
||||
exclude:
|
||||
- idf_ver: "release-v4.1"
|
||||
example: modem_console
|
||||
- idf_ver: "release-v4.1"
|
||||
example: ap_to_pppos
|
||||
- idf_ver: "release-v4.1"
|
||||
example: simple_cmux_client
|
||||
- idf_ver: "release-v4.2"
|
||||
example: simple_cmux_client
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
path: esp-protocols
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/esp_modem/examples/${{ matrix.example }}
|
||||
idf.py build
|
32
.github/workflows/console_simple_init__build.yml
vendored
Normal file
32
.github/workflows/console_simple_init__build.yml
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
name: "console_simple_init: build-tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
|
||||
jobs:
|
||||
build_console_simple_init:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'console') || github.event_name == 'push'
|
||||
name: Build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.0"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: example, path: "components/console_simple_init/examples" }]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
working-directory: ${{matrix.test.path}}
|
||||
run: |
|
||||
${IDF_PATH}/install.sh --enable-pytest
|
||||
. ${IDF_PATH}/export.sh
|
||||
python $IDF_PATH/tools/ci/ci_build_apps.py . --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app
|
48
.github/workflows/examples_build-host-test.yml
vendored
Normal file
48
.github/workflows/examples_build-host-test.yml
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
name: "examples: build/host-tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
|
||||
jobs:
|
||||
build_all_examples:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'examples') || github.event_name == 'push'
|
||||
name: Build examples
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.1"]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
- name: Build with IDF-${{ matrix.idf_ver }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
python -m pip install idf-build-apps
|
||||
# Build default configs for all targets
|
||||
python ./ci/build_apps.py examples -m examples/.build-test-rules.yml -d -c
|
||||
|
||||
build_and_run_on_host:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'examples') || github.event_name == 'push'
|
||||
name: Build and run examples on linux
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
- name: Build with IDF-${{ matrix.idf_ver }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
python -m pip install idf-build-apps
|
||||
python ./ci/build_apps.py examples/mqtt -l -t linux
|
||||
timeout 5 ./examples/mqtt/build_linux_default/esp_mqtt_demo.elf | tee test.log || true
|
||||
grep 'MQTT_EVENT_DATA' test.log
|
44
.github/workflows/host-test.yml
vendored
44
.github/workflows/host-test.yml
vendored
@ -1,44 +0,0 @@
|
||||
name: Host test
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
host_test:
|
||||
name: Build and test
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:release-v4.3
|
||||
env:
|
||||
lwip: lwip-2.1.2
|
||||
lwip_contrib: contrib-2.1.0
|
||||
lwip_uri: http://download.savannah.nongnu.org/releases/lwip
|
||||
|
||||
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
path: esp-protocols
|
||||
|
||||
- name: Build and Test
|
||||
shell: bash
|
||||
run: |
|
||||
apt-get update && apt-get install -y gcc-8 g++-8
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 800 --slave /usr/bin/g++ g++ /usr/bin/g++-8
|
||||
export LWIP_PATH=`pwd`/${{ env.lwip }}
|
||||
export LWIP_CONTRIB_PATH=`pwd`/${{ env.lwip_contrib }}
|
||||
wget --no-verbose ${lwip_uri}/${lwip}.zip
|
||||
unzip -oq ${lwip}.zip
|
||||
wget --no-verbose ${lwip_uri}/${lwip_contrib}.zip
|
||||
unzip -oq ${lwip_contrib}.zip
|
||||
. ${IDF_PATH}/export.sh
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/esp_modem/examples/linux_modem
|
||||
idf.py build
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/esp_modem/test/host_test
|
||||
idf.py build
|
||||
./build/host_modem_test.elf -r junit -o junit.xml
|
||||
|
||||
- name: Publish Results
|
||||
uses: EnricoMi/publish-unit-test-result-action@v1
|
||||
if: always()
|
||||
with:
|
||||
files: esp-protocols/components/esp_modem/test/host_test/junit.xml
|
84
.github/workflows/mdns__build-target-test.yml
vendored
Normal file
84
.github/workflows/mdns__build-target-test.yml
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
name: "mdns: build/target-tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
|
||||
jobs:
|
||||
build_mdns:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'mdns') || github.event_name == 'push'
|
||||
name: Build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.0"]
|
||||
test: [ { app: example, path: "examples" }, { app: unit_test, path: "tests/unit_test" }, { app: test_app, path: "tests/test_apps" } ]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
python -m pip install idf-build-apps
|
||||
# Build default configs for all targets
|
||||
python ./ci/build_apps.py components/mdns/${{ matrix.test.path }} -r default -m components/mdns/.build-test-rules.yml -d
|
||||
# Build specific configs for test targets
|
||||
python ./ci/build_apps.py components/mdns/${{ matrix.test.path }}
|
||||
cd components/mdns/${{ matrix.test.path }}
|
||||
for dir in `ls -d build_esp32_*`; do
|
||||
$GITHUB_WORKSPACE/ci/clean_build_artifacts.sh `pwd`/$dir
|
||||
zip -qur artifacts.zip $dir
|
||||
done
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mdns_bin_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: components/mdns/${{ matrix.test.path }}/artifacts.zip
|
||||
if-no-files-found: error
|
||||
|
||||
target_tests_mdns:
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: |
|
||||
github.repository == 'espressif/esp-protocols' &&
|
||||
( contains(github.event.pull_request.labels.*.name, 'mdns') || github.event_name == 'push' )
|
||||
name: Target Example and Unit tests
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: example, path: "examples" }, { app: unit_test, path: "tests/unit_test" }, { app: test_app, path: "tests/test_apps" } ]
|
||||
needs: build_mdns
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
steps:
|
||||
- name: Clear repository
|
||||
run: sudo rm -fr $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: mdns_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: components/mdns/${{ matrix.test.path }}/ci/
|
||||
- name: Install Python packages
|
||||
env:
|
||||
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
|
||||
run: |
|
||||
sudo apt-get install -y dnsutils
|
||||
- name: Run ${{ matrix.test.app }} application on ${{ matrix.idf_target }}
|
||||
working-directory: components/mdns/${{ matrix.test.path }}
|
||||
run: |
|
||||
unzip ci/artifacts.zip -d ci
|
||||
for dir in `ls -d ci/build_*`; do
|
||||
rm -rf build sdkconfig.defaults
|
||||
mv $dir build
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${dir#"ci/build_"}.xml --target=${{ matrix.idf_target }}
|
||||
done
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml
|
||||
path: components/mdns/${{ matrix.test.path }}/*.xml
|
61
.github/workflows/mdns__host-tests.yml
vendored
Normal file
61
.github/workflows/mdns__host-tests.yml
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
name: "mdns: host-tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
|
||||
jobs:
|
||||
host_test_mdns:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'mdns') || github.event_name == 'push'
|
||||
name: Host test
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:release-v5.1
|
||||
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
path: esp-protocols
|
||||
|
||||
- name: Build and Test
|
||||
shell: bash
|
||||
run: |
|
||||
apt-get update && apt-get install -y dnsutils gcc g++
|
||||
. ${IDF_PATH}/export.sh
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/mdns/tests/host_test
|
||||
idf.py build
|
||||
./build/mdns_host.elf &
|
||||
dig +short -p 5353 @224.0.0.251 myesp.local > ip.txt
|
||||
cat ip.txt | xargs dig +short -p 5353 @224.0.0.251 -x
|
||||
cat ip.txt
|
||||
|
||||
build_afl_host_test_mdns:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'mdns') || github.event_name == 'push'
|
||||
name: Build AFL host test
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32"]
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
path: esp-protocols
|
||||
- name: Install Necessary Libs
|
||||
run: |
|
||||
apt-get update -y
|
||||
apt-get install -y libbsd-dev
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/mdns/tests/test_afl_fuzz_host/
|
||||
make INSTR=off
|
158
.github/workflows/modem__build-host-tests.yml
vendored
Normal file
158
.github/workflows/modem__build-host-tests.yml
vendored
Normal file
@ -0,0 +1,158 @@
|
||||
name: "esp-modem: build/host-tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
|
||||
jobs:
|
||||
build_esp_modem:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'modem') || github.event_name == 'push'
|
||||
name: Build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v4.2", "release-v4.3", "release-v4.4", "release-v5.0"]
|
||||
example: ["pppos_client", "modem_console", "modem_tcp_client", "ap_to_pppos", "simple_cmux_client"]
|
||||
exclude:
|
||||
- idf_ver: "release-v4.2"
|
||||
example: simple_cmux_client
|
||||
- idf_ver: "release-v4.2"
|
||||
example: modem_tcp_client
|
||||
- idf_ver: "release-v4.3"
|
||||
example: modem_tcp_client
|
||||
- idf_ver: "release-v4.4"
|
||||
example: modem_tcp_client
|
||||
include:
|
||||
- idf_ver: "release-v4.2"
|
||||
skip_config: usb
|
||||
- idf_ver: "release-v4.3"
|
||||
skip_config: usb
|
||||
- idf_ver: "release-v5.0"
|
||||
example: "simple_cmux_client"
|
||||
warning: "Warning: The smallest app partition is nearly full"
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: protocols
|
||||
- if: ${{ matrix.skip_config }}
|
||||
run: rm -f $GITHUB_WORKSPACE/protocols/components/esp_modem/examples/${{ matrix.example }}/sdkconfig.ci.${{ matrix.skip_config }}*
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }}
|
||||
env:
|
||||
EXPECTED_WARNING: ${{ matrix.warning }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
python -m pip install idf-build-apps
|
||||
cd $GITHUB_WORKSPACE/protocols
|
||||
python ./ci/build_apps.py components/esp_modem/examples/${{ matrix.example }} -m components/esp_modem/examples/.build-test-rules.yml
|
||||
|
||||
host_test_esp_modem:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'modem') || github.event_name == 'push'
|
||||
name: Host Tests
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:release-v4.3
|
||||
env:
|
||||
lwip: lwip-2.1.2
|
||||
lwip_contrib: contrib-2.1.0
|
||||
lwip_uri: http://download.savannah.nongnu.org/releases/lwip
|
||||
COMP_DIR: esp-protocols/components/esp_modem
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: esp-protocols
|
||||
|
||||
- name: Build and Test
|
||||
shell: bash
|
||||
run: |
|
||||
apt-get update && apt-get install -y gcc-8 g++-8
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 800 --slave /usr/bin/g++ g++ /usr/bin/g++-8
|
||||
export LWIP_PATH=`pwd`/${{ env.lwip }}
|
||||
export LWIP_CONTRIB_PATH=`pwd`/${{ env.lwip_contrib }}
|
||||
. ${IDF_PATH}/export.sh
|
||||
$GITHUB_WORKSPACE/${{ env.COMP_DIR }}/test/host_test/env.sh $lwip $lwip_uri $lwip_contrib
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/esp_modem/examples/linux_modem
|
||||
idf.py build
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/esp_modem/test/host_test
|
||||
idf.py build
|
||||
./build/host_modem_test.elf -r junit -o junit.xml
|
||||
|
||||
- name: Publish Results
|
||||
uses: EnricoMi/publish-unit-test-result-action@v1
|
||||
if: always()
|
||||
with:
|
||||
files: esp-protocols/components/esp_modem/test/host_test/junit.xml
|
||||
|
||||
host_test_gcov_esp_modem:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'modem') || github.event_name == 'push'
|
||||
name: Run gcovr on esp modem host test
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
contents: write
|
||||
container: espressif/idf:release-v4.3
|
||||
env:
|
||||
lwip: lwip-2.1.2
|
||||
lwip_contrib: contrib-2.1.0
|
||||
lwip_uri: http://download.savannah.nongnu.org/releases/lwip
|
||||
COMP_DIR: esp-protocols/components/esp_modem
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: esp-protocols
|
||||
repository: ''
|
||||
persist-credentials: false
|
||||
- name: Build and Test
|
||||
shell: bash
|
||||
run: |
|
||||
apt-get update && apt-get install -y gcc-8 g++-8 python3-pip
|
||||
apt-get install -y rsync
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 800 --slave /usr/bin/g++ g++ /usr/bin/g++-8
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
export LWIP_PATH=`pwd`/${{ env.lwip }}
|
||||
export LWIP_CONTRIB_PATH=`pwd`/${{ env.lwip_contrib }}
|
||||
. ${IDF_PATH}/export.sh
|
||||
${{ env.COMP_DIR }}/test/host_test/env.sh $lwip $lwip_uri $lwip_contrib
|
||||
cd $GITHUB_WORKSPACE/${{ env.COMP_DIR }}/test/host_test
|
||||
cat sdkconfig.ci.coverage >> sdkconfig.defaults
|
||||
idf.py build
|
||||
./build/host_modem_test.elf
|
||||
- name: Run gcovr
|
||||
shell: bash
|
||||
run: |
|
||||
python -m pip install gcovr
|
||||
cd $GITHUB_WORKSPACE/${{ env.COMP_DIR }}
|
||||
gcov-8 `find . -name "esp_modem*gcda" -printf '%h\n' | head -n 1`/*
|
||||
gcovr --gcov-ignore-parse-errors -g -k -r . --html index.html -x esp_modem_coverage.xml
|
||||
mkdir modem_coverage_report
|
||||
cp $GITHUB_WORKSPACE/${{ env.COMP_DIR }}/index.html modem_coverage_report
|
||||
cp -rf modem_coverage_report $GITHUB_WORKSPACE
|
||||
- name: Code Coverage Summary Report
|
||||
uses: irongut/CodeCoverageSummary@v1.3.0
|
||||
with:
|
||||
filename: esp-protocols/**/esp_modem_coverage.xml
|
||||
badge: true
|
||||
fail_below_min: false
|
||||
format: markdown
|
||||
hide_branch_rate: false
|
||||
hide_complexity: false
|
||||
indicators: true
|
||||
output: both
|
||||
thresholds: '60 80'
|
||||
- name: Write to Job Summary
|
||||
run: cat code-coverage-results.md >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: modem_coverage_report
|
||||
path: |
|
||||
${{ env.COMP_DIR }}/modem_coverage_report
|
||||
if-no-files-found: error
|
75
.github/workflows/modem__target-test.yml
vendored
Normal file
75
.github/workflows/modem__target-test.yml
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
name: "esp-modem: target-tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
|
||||
jobs:
|
||||
build_esp_modem_tests:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'modem') || github.event_name == 'push'
|
||||
name: Build Target tests
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32c3"]
|
||||
test: [ { app: pppd, path: test/target }, { app: sim800_c3, path: examples/pppos_client }, { app: sim800_cmux, path: examples/simple_cmux_client } ]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TEST_DIR: components/esp_modem/${{ matrix.test.path }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build esp-modem target tests with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
SDKCONFIG: sdkconfig.ci.${{ matrix.test.app }}
|
||||
shell: bash
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
rm -rf sdkconfig build
|
||||
[ -f ${SDKCONFIG} ] && cp ${SDKCONFIG} sdkconfig.defaults
|
||||
idf.py set-target ${{ matrix.idf_target }}
|
||||
idf.py build
|
||||
$GITHUB_WORKSPACE/ci/clean_build_artifacts.sh ${GITHUB_WORKSPACE}/${TEST_DIR}/build
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: modem_target_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/build
|
||||
if-no-files-found: error
|
||||
|
||||
target_tests_esp_modem:
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: |
|
||||
github.repository == 'espressif/esp-protocols' &&
|
||||
( contains(github.event.pull_request.labels.*.name, 'modem') || github.event_name == 'push' )
|
||||
name: Run Target tests
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32c3"]
|
||||
test: [ { app: pppd, path: test/target }, { app: sim800_c3, path: examples/pppos_client }, { app: sim800_cmux, path: examples/simple_cmux_client } ]
|
||||
needs: build_esp_modem_tests
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- modem
|
||||
env:
|
||||
TEST_DIR: components/esp_modem/${{ matrix.test.path }}
|
||||
steps:
|
||||
- name: Clear repository
|
||||
run: sudo rm -fr $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: modem_target_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/build
|
||||
- name: Run Example Test on target
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
python -m pytest --log-cli-level DEBUG --target=${{ matrix.idf_target }}
|
32
.github/workflows/mqtt_cxx__build.yml
vendored
Normal file
32
.github/workflows/mqtt_cxx__build.yml
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
name: "mqtt-cxx: build-tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
|
||||
jobs:
|
||||
build_esp_mqtt_cxx:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'mqtt') || github.event_name == 'push'
|
||||
name: Build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.0"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: example, path: "components/esp_mqtt_cxx/examples" }]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
working-directory: ${{matrix.test.path}}
|
||||
run: |
|
||||
${IDF_PATH}/install.sh --enable-pytest
|
||||
. ${IDF_PATH}/export.sh
|
||||
python $IDF_PATH/tools/ci/ci_build_apps.py . --target ${{ matrix.idf_target }} -vv --preserve-all --pytest-app
|
45
.github/workflows/pre_commit_check.yml
vendored
Normal file
45
.github/workflows/pre_commit_check.yml
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
name: Check pre-commit rules
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, reopened, synchronize]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
pre_commit_check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.base_ref }}
|
||||
fetch-depth: 20
|
||||
- name: Fetch head and base refs
|
||||
# This is necessary for pre-commit to check the changes in the PR branch (and to set origin/HEAD and HEAD refs)
|
||||
run: |
|
||||
git fetch origin ${{ github.event.pull_request.head.sha }}:pr_ref
|
||||
git checkout pr_ref
|
||||
git remote set-head origin --auto
|
||||
git merge-base origin/HEAD HEAD || ( echo "Your PR is far behind origin/HEAD, please rebase" && exit 1 )
|
||||
- name: Set up Python environment
|
||||
uses: actions/setup-python@master
|
||||
with:
|
||||
python-version: v3.7
|
||||
- name: Install python packages
|
||||
run: |
|
||||
pip install pre-commit
|
||||
pre-commit install-hooks
|
||||
- name: Run pre-commit and check for any changes
|
||||
run: |
|
||||
echo "Commits being checked:"
|
||||
git log --oneline --no-decorate origin/HEAD..HEAD
|
||||
echo ""
|
||||
if ! pre-commit run --from-ref origin/HEAD --to-ref HEAD --hook-stage manual --show-diff-on-failure ; then
|
||||
echo ""
|
||||
echo "::notice::It looks like the commits in this PR have been made without having pre-commit hooks installed."
|
||||
echo "::notice::Please see https://github.com/espressif/esp-protocols/CONTRIBUTING.md for instructions."
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
45
.github/workflows/publish-coverage-report.yml
vendored
Normal file
45
.github/workflows/publish-coverage-report.yml
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
name: Publish coverage report to Github Pages
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["websocket: build/host-tests", "esp-modem: build/host-tests"]
|
||||
types:
|
||||
- completed
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
publish_github_pages:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'espressif/esp-protocols'
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Download Websocket Artifact
|
||||
uses: dawidd6/action-download-artifact@v2
|
||||
with:
|
||||
workflow: websocket__build-host-tests.yml
|
||||
workflow_conclusion: success
|
||||
name: websocket_coverage_report
|
||||
path: websocket_coverage_report_artifact
|
||||
- name: Download Modem Artifact
|
||||
uses: dawidd6/action-download-artifact@v2
|
||||
with:
|
||||
workflow: modem__build-host-tests.yml
|
||||
workflow_conclusion: success
|
||||
name: modem_coverage_report
|
||||
path: modem_coverage_report_artifact
|
||||
- name: Merge HTML files
|
||||
run: |
|
||||
echo "<html><body>" > index.html
|
||||
cat modem_coverage_report_artifact/index.html >> index.html
|
||||
cat websocket_coverage_report_artifact/index.html >> index.html
|
||||
echo "</body></html>" >> index.html
|
||||
mkdir coverage_report
|
||||
mv index.html coverage_report
|
||||
|
||||
- name: Deploy generated docs
|
||||
uses: JamesIves/github-pages-deploy-action@4.1.5
|
||||
with:
|
||||
branch: gh-pages
|
||||
folder: coverage_report
|
@ -1,39 +0,0 @@
|
||||
name: Docs and Publish Websockets
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
docs_build:
|
||||
name: Docs-Build-And-Upload
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Generate docs
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install doxygen clang python3-pip git
|
||||
sudo git clone https://github.com/espressif/esp-idf
|
||||
python -m pip install breathe recommonmark
|
||||
python -m pip install -r esp-idf/docs/requirements.txt
|
||||
cd $GITHUB_WORKSPACE/components/esp_websocket_client/docs
|
||||
./generate_docs
|
||||
mkdir -p $GITHUB_WORKSPACE/docs/esp_websocket_client
|
||||
cp -r html/. $GITHUB_WORKSPACE/docs/esp_websocket_client
|
||||
cd $GITHUB_WORKSPACE/docs
|
||||
touch .nojekyll
|
||||
echo '<a href="esp_websocket_client/index.html">esp-websocket-client</a>' >> index.html
|
||||
|
||||
- name: Deploy generated docs.
|
||||
uses: JamesIves/github-pages-deploy-action@4.1.5
|
||||
with:
|
||||
branch: gh-pages
|
||||
folder: docs
|
107
.github/workflows/publish-docs-component.yml
vendored
107
.github/workflows/publish-docs-component.yml
vendored
@ -5,41 +5,90 @@ on:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
docs_build:
|
||||
name: Docs-Build-And-Upload
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCS_DEPLOY_URL_BASE: ${{ secrets.DOCS_DEPLOY_URL_BASE }}
|
||||
DOCS_DEPLOY_SERVER: ${{ secrets.DOCS_DEPLOY_SERVER }}
|
||||
DOCS_DEPLOY_SERVER_USER: ${{ secrets.DOCS_DEPLOY_SERVER_USER }}
|
||||
DOCS_DEPLOY_KEY: ${{ secrets.DOCS_DEPLOY_PRIVATEKEY }}
|
||||
DOCS_DEPLOY_PATH_ORIG : ${{ secrets.DOCS_DEPLOY_PATH }}
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
name: Publish Tag, Release, Docs, Component
|
||||
runs-on: ubuntu-latest
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: github.repository == 'espressif/esp-protocols'
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@master
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Generate docs
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install doxygen clang python3-pip
|
||||
python -m pip install breathe recommonmark
|
||||
cd $GITHUB_WORKSPACE/components/esp_modem/docs
|
||||
./generate_docs
|
||||
mkdir -p $GITHUB_WORKSPACE/docs/esp_modem
|
||||
cp -r html/. $GITHUB_WORKSPACE/docs/esp_modem
|
||||
cd $GITHUB_WORKSPACE/docs
|
||||
touch .nojekyll
|
||||
echo '<a href="esp_modem/index.html">esp-modem</a>' > index.html
|
||||
|
||||
- name: Upload components to component service
|
||||
uses: espressif/github-actions/upload_components@master
|
||||
submodules: recursive
|
||||
token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
- name: Check for version update
|
||||
shell: bash
|
||||
run: ./ci/detect_component_bump
|
||||
- name: Tag merge commit
|
||||
if: env.BUMP_VERSION != ''
|
||||
uses: anothrNick/github-tag-action@1.61.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CUSTOM_TAG: ${{ env.BUMP_TAG }}
|
||||
- name: Create Release
|
||||
if: env.BUMP_VERSION != ''
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
directories: "components/esp_modem"
|
||||
name: "esp_modem"
|
||||
body_path: "release_notes.md"
|
||||
tag_name: ${{ env.BUMP_TAG }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Generate docs
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install doxygen clang python3-pip
|
||||
python -m pip install breathe recommonmark esp-docs==1.4.1
|
||||
for comp in `ls components`; do
|
||||
cd $GITHUB_WORKSPACE/docs/${comp}
|
||||
if [[ "${{ env.BUMP_COMPONENT }}" == "${comp}" ]]; then
|
||||
echo "Building specific version of ${comp} (${{ env.BUMP_VERSION }})"
|
||||
./generate_docs ${{ env.BUMP_VERSION }}
|
||||
else
|
||||
echo "Building latest version of ${comp}"
|
||||
./generate_docs
|
||||
fi
|
||||
done
|
||||
- name: Deploying generated docs
|
||||
shell: bash
|
||||
run: |
|
||||
source $GITHUB_WORKSPACE/docs/utils.sh
|
||||
add_doc_server_ssh_keys $DOCS_DEPLOY_KEY $DOCS_DEPLOY_SERVER $DOCS_DEPLOY_SERVER_USER
|
||||
export GIT_VER=$(git describe --always)
|
||||
export GITHUB_REF_NAME=latest
|
||||
for comp in `ls components`; do
|
||||
echo "Deploying latest of ${comp}"
|
||||
export DOCS_BUILD_DIR=$GITHUB_WORKSPACE/docs/${comp}
|
||||
export DOCS_DEPLOY_PATH=$DOCS_DEPLOY_PATH_ORIG/${comp}
|
||||
cd $GITHUB_WORKSPACE/docs/${comp}
|
||||
deploy-docs
|
||||
done;
|
||||
# Deploy docs with version path
|
||||
if [[ "${{ env.BUMP_VERSION }}" != "" ]]; then
|
||||
echo "Deploying specific version of ${comp} (${{ env.BUMP_VERSION }})"
|
||||
cd $GITHUB_WORKSPACE/docs/${{ env.BUMP_COMPONENT }}
|
||||
export GITHUB_REF_NAME=${{ env.BUMP_VERSION }}
|
||||
deploy-docs
|
||||
fi
|
||||
- name: Upload components to component service
|
||||
uses: espressif/upload-components-ci-action@v1
|
||||
with:
|
||||
directories: >
|
||||
components/asio;
|
||||
components/esp_modem;
|
||||
components/esp_mqtt_cxx;
|
||||
components/esp_websocket_client;
|
||||
components/mdns;
|
||||
components/console_simple_init;
|
||||
namespace: "espressif"
|
||||
api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }}
|
||||
|
||||
- name: Deploy generated docs
|
||||
uses: JamesIves/github-pages-deploy-action@4.1.5
|
||||
with:
|
||||
branch: gh-pages
|
||||
folder: docs
|
||||
|
86
.github/workflows/run-host-tests.yml
vendored
Normal file
86
.github/workflows/run-host-tests.yml
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
name: Run on host
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
idf_version:
|
||||
required: true
|
||||
type: string
|
||||
app_name:
|
||||
type: string
|
||||
required: true
|
||||
app_path:
|
||||
type: string
|
||||
required: true
|
||||
component_path:
|
||||
type: string
|
||||
required: true
|
||||
upload_artifacts:
|
||||
type: boolean
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build App
|
||||
runs-on: ubuntu-20.04
|
||||
permissions:
|
||||
contents: write
|
||||
container: espressif/idf:${{inputs.idf_version}}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: esp-protocols
|
||||
- name: Build ${{ inputs.app_name }} with IDF-${{ inputs.idf_version }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cd $GITHUB_WORKSPACE/${{inputs.app_path}}
|
||||
rm -rf sdkconfig sdkconfig.defaults build
|
||||
cp sdkconfig.ci.linux sdkconfig.defaults
|
||||
idf.py build
|
||||
./build/${{inputs.app_name}}.elf
|
||||
- name: Build with Coverage Enabled
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cd $GITHUB_WORKSPACE/${{inputs.app_path}}
|
||||
rm -rf build sdkconfig sdkconfig.defaults
|
||||
cp sdkconfig.ci.coverage sdkconfig.defaults
|
||||
idf.py fullclean
|
||||
idf.py build
|
||||
./build/${{inputs.app_name}}.elf
|
||||
- name: Run Coverage
|
||||
shell: bash
|
||||
run: |
|
||||
apt-get update && apt-get install -y python3-pip rsync
|
||||
python -m pip install gcovr
|
||||
cd $GITHUB_WORKSPACE/${{inputs.component_path}}
|
||||
gcov `find . -name "*gcda"`
|
||||
gcovr --gcov-ignore-parse-errors -g -k -r . --html index.html -x ${{inputs.app_name}}_coverage.xml
|
||||
mkdir ${{inputs.app_name}}_coverage_report
|
||||
touch ${{inputs.app_name}}_coverage_report/.nojekyll
|
||||
cp index.html ${{inputs.app_name}}_coverage_report
|
||||
cp -rf ${{inputs.app_name}}_coverage_report ${{inputs.app_name}}_coverage.xml $GITHUB_WORKSPACE
|
||||
- name: Code Coverage Summary Report
|
||||
uses: irongut/CodeCoverageSummary@v1.3.0
|
||||
with:
|
||||
filename: esp-protocols/**/${{inputs.app_name}}_coverage.xml
|
||||
badge: true
|
||||
fail_below_min: false
|
||||
format: markdown
|
||||
hide_branch_rate: false
|
||||
hide_complexity: false
|
||||
indicators: true
|
||||
output: both
|
||||
thresholds: '60 80'
|
||||
- name: Write to Job Summary
|
||||
run: cat code-coverage-results.md >> $GITHUB_STEP_SUMMARY
|
||||
- name: Upload files to artifacts for run-target job
|
||||
uses: actions/upload-artifact@v3
|
||||
if: ${{inputs.upload_artifacts}}
|
||||
with:
|
||||
name: ${{inputs.app_name}}_coverage_report
|
||||
path: |
|
||||
${{inputs.component_path}}/${{inputs.app_name}}_coverage_report
|
||||
if-no-files-found: error
|
20
.github/workflows/websocket__build-host-tests.yml
vendored
Normal file
20
.github/workflows/websocket__build-host-tests.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
name: "websocket: build/host-tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
|
||||
|
||||
jobs:
|
||||
host_test_websocket:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'websocket') || github.event_name == 'push'
|
||||
uses: "./.github/workflows/run-host-tests.yml"
|
||||
with:
|
||||
idf_version: "latest"
|
||||
app_name: "websocket"
|
||||
app_path: "esp-protocols/components/esp_websocket_client/examples/linux"
|
||||
component_path: "esp-protocols/components/esp_websocket_client"
|
||||
upload_artifacts: true
|
86
.github/workflows/websocket__build-target-test.yml
vendored
Normal file
86
.github/workflows/websocket__build-target-test.yml
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
name: "websocket: build/target-tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled]
|
||||
|
||||
jobs:
|
||||
build_websocket:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'websocket') || github.event_name == 'push'
|
||||
name: Build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["release-v5.0", "release-v5.1", "latest"]
|
||||
test: [ { app: example, path: "examples/target" }, { app: unit_test, path: "test" } ]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TEST_DIR: components/esp_websocket_client/${{ matrix.test.path }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
python -m pip install idf-build-apps
|
||||
python ./ci/build_apps.py ${TEST_DIR}
|
||||
cd ${TEST_DIR}
|
||||
for dir in `ls -d build_esp32_*`; do
|
||||
$GITHUB_WORKSPACE/ci/clean_build_artifacts.sh `pwd`/$dir
|
||||
zip -qur artifacts.zip $dir
|
||||
done
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: websocket_bin_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/artifacts.zip
|
||||
if-no-files-found: error
|
||||
|
||||
run-target-websocket:
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: |
|
||||
github.repository == 'espressif/esp-protocols' &&
|
||||
( contains(github.event.pull_request.labels.*.name, 'websocket') || github.event_name == 'push' )
|
||||
name: Target test
|
||||
needs: build_websocket
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
idf_ver: ["release-v5.0", "release-v5.1", "latest"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: example, path: "examples/target" }, { app: unit_test, path: "test" } ]
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
env:
|
||||
TEST_DIR: components/esp_websocket_client/${{ matrix.test.path }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: websocket_bin_esp32_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/ci/
|
||||
- name: Install Python packages
|
||||
env:
|
||||
PIP_EXTRA_INDEX_URL: "https://www.piwheels.org/simple"
|
||||
run: |
|
||||
pip install --only-binary cryptography --extra-index-url https://dl.espressif.com/pypi/ -r $GITHUB_WORKSPACE/ci/requirements.txt
|
||||
- name: Run Example Test on target
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
unzip ci/artifacts.zip -d ci
|
||||
for dir in `ls -d ci/build_*`; do
|
||||
rm -rf build sdkconfig.defaults
|
||||
mv $dir build
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${dir#"ci/build_"}.xml --target=${{ matrix.idf_target }}
|
||||
done
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: results_${{ matrix.test.app }}_${{ matrix.idf_target }}_${{ matrix.idf_ver }}.xml
|
||||
path: components/esp_websocket_client/${{ matrix.test.path }}/*.xml
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "components/asio/asio"]
|
||||
path = components/asio/asio
|
||||
url = https://github.com/espressif/asio
|
26
.mypy.ini
Normal file
26
.mypy.ini
Normal file
@ -0,0 +1,26 @@
|
||||
[mypy]
|
||||
|
||||
# Specifies the Python version used to parse and check the target program
|
||||
python_version = 3.9
|
||||
|
||||
# Disallows defining functions without type annotations or with incomplete type annotations
|
||||
# True => enforce type annotation in all function definitions
|
||||
disallow_untyped_defs = True
|
||||
|
||||
# Shows a warning when returning a value with type Any from a function declared with a non- Any return type
|
||||
warn_return_any = True
|
||||
|
||||
# Shows errors for missing return statements on some execution paths
|
||||
warn_no_return = True
|
||||
|
||||
# Suppress error messages about imports that cannot be resolved
|
||||
# True => ignore all import errors
|
||||
ignore_missing_imports = True
|
||||
|
||||
# Disallows defining functions with incomplete type annotations
|
||||
disallow_incomplete_defs = False
|
||||
|
||||
# Directs what to do with imports when the imported module is found as a .py file and not part of the files,
|
||||
# modules and packages provided on the command line.
|
||||
# SKIP -> mypy checks only single file, not included imports
|
||||
follow_imports = skip
|
68
.pre-commit-config.yaml
Normal file
68
.pre-commit-config.yaml
Normal file
@ -0,0 +1,68 @@
|
||||
# See https://pre-commit.com for more information
|
||||
# See https://pre-commit.com/hooks.html for more hooks
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.3.0
|
||||
hooks:
|
||||
- id: check-yaml
|
||||
- id: check-added-large-files
|
||||
- id: fix-byte-order-marker
|
||||
- id: check-case-conflict
|
||||
- id: end-of-file-fixer
|
||||
- id: trailing-whitespace
|
||||
- id: mixed-line-ending
|
||||
- id: debug-statements
|
||||
- repo: https://github.com/pycqa/flake8
|
||||
rev: 5.0.4
|
||||
hooks:
|
||||
- id: flake8
|
||||
args: ['--config=.flake8', '--tee', '--benchmark']
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v0.981
|
||||
hooks:
|
||||
- id: mypy
|
||||
exclude: >
|
||||
(?x)^(
|
||||
.*.py
|
||||
)$
|
||||
- repo: https://github.com/myint/unify
|
||||
rev: v0.5
|
||||
hooks:
|
||||
- id: unify
|
||||
- repo: https://github.com/pre-commit/mirrors-yapf
|
||||
rev: "v0.32.0"
|
||||
hooks:
|
||||
- id: yapf
|
||||
args: ['style={based_on_style: google, column_limit: 160, indent_width: 4}']
|
||||
- repo: https://github.com/pre-commit/mirrors-isort
|
||||
rev: v5.10.1
|
||||
hooks:
|
||||
- id: isort
|
||||
- repo: https://github.com/myint/eradicate/
|
||||
rev: v2.1.0
|
||||
hooks:
|
||||
- id: eradicate
|
||||
- repo: https://github.com/espressif/check-copyright/
|
||||
rev: v1.0.3
|
||||
hooks:
|
||||
- id: check-copyright
|
||||
args: ['--ignore', 'ci/check_copyright_ignore.txt', '--config', 'ci/check_copyright_config.yaml']
|
||||
- repo: https://github.com/igrr/astyle_py.git
|
||||
rev: c0013808882a15a0c0c2c1a9b5c903866c53a653
|
||||
hooks:
|
||||
- id: astyle_py
|
||||
args: ['--style=otbs', '--attach-namespaces', '--attach-classes', '--indent=spaces=4', '--convert-tabs', '--align-pointer=name', '--align-reference=name', '--keep-one-line-statements', '--pad-header', '--pad-oper']
|
||||
- repo: https://github.com/commitizen-tools/commitizen
|
||||
rev: v2.42.1
|
||||
hooks:
|
||||
- id: commitizen
|
||||
- id: commitizen-branch
|
||||
stages: [push, manual]
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: commit message scopes
|
||||
name: "commit message must be scoped with: mdns, modem, websocket, asio, mqtt_cxx, console, common"
|
||||
entry: '\A(?!(feat|fix|ci|bump|test|docs)\((mdns|modem|common|console|websocket|asio|mqtt_cxx|examples)\)\:)'
|
||||
language: pygrep
|
||||
args: [--multiline]
|
||||
stages: [commit-msg]
|
31
CONTRIBUTING.md
Normal file
31
CONTRIBUTING.md
Normal file
@ -0,0 +1,31 @@
|
||||
# Information for Contributors
|
||||
|
||||
Contributions in the form of pull requests, issue reports, and feature requests are welcome!
|
||||
|
||||
## Submitting a PR
|
||||
|
||||
- [ ] Fork the [esp-protocols repository on GitHub](https://github.com/espressif/esp-protocols) to start making your changes.
|
||||
|
||||
- [ ] Install pre-commit hooks: `pip install pre-commit && pre-commit install-hooks && pre-commit install --hook-type commit-msg --hook-type pre-push`
|
||||
|
||||
- [ ] Send a pull request (PR) and work with us until it gets merged and published. Contributions may need some modifications, so a few rounds of review and fixing may be necessary.
|
||||
|
||||
For quick merging, the contribution should be short, and concentrated on a single feature or topic. The larger the contribution is, the longer it would take to review it and merge it.
|
||||
|
||||
Please follow the [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) rule when writing commit messages.
|
||||
|
||||
## Release process
|
||||
|
||||
When releasing a new component version we have to:
|
||||
|
||||
* Update the version number
|
||||
* Update the changelog
|
||||
* Create the version tag in this repository
|
||||
* Deploy the component to component registry
|
||||
* Update the documentation
|
||||
|
||||
This process is not fully automated, the first step needs to be performed manually by project maintainers running the `bump` command. Release procedure is as follows:
|
||||
* Run `ci/bump [component] [version]` (version number is optional, `cz` would automatically increment it if not present)
|
||||
* Check the updated `CHANGELOG.md` and the generated bump commit message
|
||||
* Create a PR
|
||||
Once the PR is merged, the CI job tags the merge commit, creates a new release, builds and deploys documentation and the new component to the component registry
|
29
README.md
29
README.md
@ -1,10 +1,35 @@
|
||||
# Collection of protocol components for ESP-IDF
|
||||
|
||||
[Documentation of esp-protocol](https://espressif.github.io/esp-protocols)
|
||||
## How to use
|
||||
|
||||
The [ESP-Protocols](https://github.com/espressif/esp-protocols) repository contains a collection of protocol components for [ESP-IDF](https://github.com/espressif/esp-idf).
|
||||
Additionally, each component is available in [IDF Component Registry](https://components.espressif.com).
|
||||
Please refer to instructions in [ESP-IDF](https://github.com/espressif/esp-idf)
|
||||
|
||||
## Components
|
||||
|
||||
### esp_modem
|
||||
|
||||
* Brief introduction [README](components/esp_modem/README.md)
|
||||
* Full html [documentation](https://espressif.github.io/esp-protocols/esp_modem/index.html)
|
||||
* Full html [documentation](https://docs.espressif.com/projects/esp-protocols/esp_modem/docs/latest/index.html)
|
||||
|
||||
### mDNS
|
||||
|
||||
* Brief introduction [README](components/mdns/README.md)
|
||||
* Full html [documentation(English)](https://docs.espressif.com/projects/esp-protocols/mdns/docs/latest/en/index.html)
|
||||
* Full html [documentation(Chinese)](https://docs.espressif.com/projects/esp-protocols/mdns/docs/latest/zh_CN/index.html)
|
||||
|
||||
### esp_websocket_client
|
||||
|
||||
* Brief introduction [README](components/esp_websocket_client/README.md)
|
||||
* Full html [documentation](https://docs.espressif.com/projects/esp-protocols/esp_websocket_client/docs/latest/index.html)
|
||||
|
||||
### ASIO port
|
||||
|
||||
* Brief introduction [README](components/asio/README.md)
|
||||
* Full html [documentation](https://docs.espressif.com/projects/esp-protocols/asio/docs/latest/index.html)
|
||||
|
||||
### esp_mqtt_cxx
|
||||
|
||||
* Brief introduction [README](components/esp_mqtt_cxx/README.md)
|
||||
* Full html [documentation](https://docs.espressif.com/projects/esp-protocols/esp_mqtt_cxx/docs/latest/index.html)
|
||||
|
67
ci/build_apps.py
Normal file
67
ci/build_apps.py
Normal file
@ -0,0 +1,67 @@
|
||||
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
"""
|
||||
This file is used in CI for esp-protocols build tests
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
from idf_build_apps import build_apps, find_apps, setup_logging
|
||||
from idf_build_apps.constants import SUPPORTED_TARGETS
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Build all projects',
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
)
|
||||
parser.add_argument('paths', nargs='+', help='Paths to the apps to build.')
|
||||
parser.add_argument(
|
||||
'-t',
|
||||
'--target',
|
||||
default='all',
|
||||
help='Build apps for given target',
|
||||
)
|
||||
parser.add_argument('-r', '--rules', nargs='*', default=['sdkconfig.ci=default', 'sdkconfig.ci.*=', '=default'], help='Rules how to treat configs')
|
||||
parser.add_argument('-m', '--manifests', nargs='*', default=[], help='list of manifest files')
|
||||
parser.add_argument('-d', '--delete', action='store_true', help='Delete build artifacts')
|
||||
parser.add_argument('-c', '--recursive', action='store_true', help='Build recursively')
|
||||
parser.add_argument('-l', '--linux', action='store_true', help='Include linux build (dont check warnings)')
|
||||
args = parser.parse_args()
|
||||
|
||||
IDF_PATH = os.environ['IDF_PATH']
|
||||
|
||||
# Compose the ignore warning strings from the global list and from the environment
|
||||
ignore_warning_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),'ignore_build_warnings.txt')
|
||||
ignore_warning = open(ignore_warning_file).read().rstrip('\n').split('\n')
|
||||
if 'EXPECTED_WARNING' in os.environ:
|
||||
ignore_warning += os.environ['EXPECTED_WARNING'].split('\n')
|
||||
if args.linux:
|
||||
SUPPORTED_TARGETS.append('linux')
|
||||
ignore_warning = 'warning: ' # Ignore all common warnings on linux builds
|
||||
setup_logging(2)
|
||||
apps = find_apps(
|
||||
args.paths,
|
||||
recursive=args.recursive,
|
||||
target=args.target,
|
||||
build_dir='build_@t_@w',
|
||||
config_rules_str=args.rules,
|
||||
build_log_path='build_log.txt',
|
||||
size_json_path='size.json' if not args.linux else None,
|
||||
check_warnings=True,
|
||||
preserve=not args.delete,
|
||||
manifest_files=args.manifests,
|
||||
default_build_targets=SUPPORTED_TARGETS,
|
||||
manifest_rootpath='.',
|
||||
)
|
||||
|
||||
for app in apps:
|
||||
print(app)
|
||||
|
||||
sys.exit(
|
||||
build_apps(apps,
|
||||
dry_run=False,
|
||||
keep_going=False,
|
||||
ignore_warning_strs=ignore_warning)
|
||||
)
|
23
ci/bump
Executable file
23
ci/bump
Executable file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: bump component [version]"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
comp=$1; shift;
|
||||
|
||||
cd components/${comp}
|
||||
if ! cz bump --dry-run; then
|
||||
echo "Commitizen bump commad failed!"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
cz_bump_out=`cz bump --files-only "$@"`
|
||||
commit_title=`echo "${cz_bump_out}" | head -1`
|
||||
commit_body=`cat ../../release_notes.txt`
|
||||
|
||||
git add -u .
|
||||
git commit -m $"${commit_title}
|
||||
|
||||
${commit_body}"
|
105
ci/changelog.py
Normal file
105
ci/changelog.py
Normal file
@ -0,0 +1,105 @@
|
||||
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
|
||||
import sh
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Generates a change log from cz commits')
|
||||
parser.add_argument('component')
|
||||
args = parser.parse_args()
|
||||
|
||||
old_ref = os.environ.get('CZ_PRE_CURRENT_TAG_VERSION')
|
||||
new_tag = os.environ.get('CZ_PRE_NEW_TAG_VERSION')
|
||||
new_ref = os.environ.get('CZ_PRE_NEW_VERSION')
|
||||
component = args.component
|
||||
|
||||
root_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
|
||||
|
||||
git = sh.git.bake(_cwd=root_path)
|
||||
|
||||
keys = ['breaking', 'major', 'feat', 'fix', 'update']
|
||||
items = {key: [] for key in keys}
|
||||
sections = {
|
||||
'feat': 'Features',
|
||||
'fix': 'Bug Fixes',
|
||||
'update': 'Updated',
|
||||
'breaking': 'Breaking changes',
|
||||
'major': 'Major changes'
|
||||
}
|
||||
brief_log = git.log('--oneline', '{}..HEAD'.format(old_ref), '--', 'components/' + component, _tty_out=False)
|
||||
for oneline in brief_log.splitlines():
|
||||
[commit, brief_msg] = oneline.split(' ', 1)
|
||||
if 'Merge' in str(brief_msg) or brief_msg.startswith('bump('): # skip Merge commits and bumps
|
||||
continue
|
||||
find_title = re.findall(r'^(fix|feat|esp_modem|esp-modem|mdns)(\([^\)]+\))?:\s*(.+)$', str(brief_msg))
|
||||
item_type = '' # default prefix
|
||||
item_message = brief_msg # default body
|
||||
if find_title is not None and len(find_title) > 0: # Use scopes & types
|
||||
item_type = find_title[0][0] # prefix (fix/feat/ci)
|
||||
item_message = find_title[0][-1] # title body
|
||||
|
||||
# Add details in parentheses (commit-id and references from the FOOTER section)
|
||||
details = '[{}](https://github.com/espressif/esp-protocols/commit/{})'.format(commit, commit)
|
||||
msg_details = git.show('-s', commit, _tty_out=False)
|
||||
# check references
|
||||
if any(s in str(msg_details) for s in ['esp-protocols/issues', 'BREAKING CHANGE', 'MAJOR CHANGE']):
|
||||
# Closes <issue>
|
||||
closes = re.findall(r'Closes ([^\d]+/(\d+))', str(msg_details), re.MULTILINE)
|
||||
if closes and closes[0] is not None:
|
||||
details += ', [#{}]({})'.format(closes[0][1], closes[0][0])
|
||||
# Breaking changes
|
||||
find_breaking = re.findall(r'BREAKING CHANGE:\s*([^\n]*)', str(msg_details), re.MULTILINE)
|
||||
if find_breaking is not None and len(find_breaking) > 0:
|
||||
if find_breaking[0] != '':
|
||||
items['breaking'].append('{} ([{}](https://github.com/espressif/esp-protocols/commit/{}))'.format(find_breaking[0], item_message, commit))
|
||||
else:
|
||||
items['breaking'].append('{} ({})'.format(item_message, details))
|
||||
details += ', !BREAKING'
|
||||
# Major changes
|
||||
find_major = re.findall(r'MAJOR CHANGE:\s*([^\n]*)',
|
||||
str(msg_details), re.MULTILINE)
|
||||
if find_major is not None and len(
|
||||
find_major) > 0 and find_major[0] != '':
|
||||
items['major'].append('{} ([{}](https://github.com/espressif/esp-protocols/commit/{}))'.format(find_major[0], item_message, commit))
|
||||
if item_type in ['fix', 'feat']:
|
||||
items[item_type].append('{} ({})'.format(item_message, details))
|
||||
else:
|
||||
items['update'].append('{} ({})'.format(item_message, details))
|
||||
# Generate changelog
|
||||
changelog = '## [{}](https://github.com/espressif/esp-protocols/commits/{})\n'.format(
|
||||
new_ref, new_tag)
|
||||
for section, item in items.items():
|
||||
if len(item) > 0:
|
||||
changelog += '\n### {}\n\n'.format(sections[section])
|
||||
for it in item:
|
||||
changelog += '- {}\n'.format(it)
|
||||
changelog += '\n'
|
||||
filename = os.path.join(root_path, 'components', component, 'CHANGELOG.md')
|
||||
# insert the actual changelog to the beginning of the file, just after the title (2nd line)
|
||||
with open(filename, 'r') as orig_changelog:
|
||||
changelog_title = orig_changelog.readline(
|
||||
) # expect # Changelog title on the first line
|
||||
changelog_nl = orig_changelog.readline()
|
||||
orig_items = orig_changelog.read()
|
||||
with open(filename, 'w') as updated_changelog:
|
||||
updated_changelog.write(changelog_title)
|
||||
updated_changelog.write(changelog_nl)
|
||||
updated_changelog.write(changelog)
|
||||
updated_changelog.write(orig_items)
|
||||
git.add(filename)
|
||||
|
||||
# write the current changelog entry to a local text file (removing links, captions and extra newlines)
|
||||
changelog = re.sub(r'\[([^\]]+)\]\([^\)]+\)', r'\1', changelog)
|
||||
changelog = re.sub(r'\#\#[\#\s]*(.+)', r'\1', changelog)
|
||||
changelog = re.sub(r'\n\n', '\n', changelog)
|
||||
with open(os.path.join(root_path, 'release_notes.txt'), 'w') as release_notes:
|
||||
release_notes.write(changelog)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
65
ci/check_copyright_config.yaml
Normal file
65
ci/check_copyright_config.yaml
Normal file
@ -0,0 +1,65 @@
|
||||
# don't modify this section!
|
||||
DEFAULT:
|
||||
perform_check: yes # should the check be performed?
|
||||
# Sections setting this to 'no' don't need to include any other options as they are ignored
|
||||
# When a file is using a section with the option set to 'no', no checks are performed.
|
||||
|
||||
# what licenses (or license expressions) are allowed for files in this section
|
||||
# when setting this option in a section, you need to list all the allowed licenses
|
||||
allowed_licenses:
|
||||
- Apache-2.0
|
||||
license_for_new_files: Apache-2.0 # license to be used when inserting a new copyright notice
|
||||
new_notice_c: | # notice for new C, CPP, H, HPP and LD files
|
||||
/*
|
||||
* SPDX-FileCopyrightText: {years} Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: {license}
|
||||
*/
|
||||
new_notice_python: | # notice for new python files
|
||||
# SPDX-FileCopyrightText: {years} Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: {license}
|
||||
|
||||
# comment lines matching:
|
||||
# SPDX-FileCopyrightText: year[-year] Espressif Systems
|
||||
# or
|
||||
# SPDX-FileContributor: year[-year] Espressif Systems
|
||||
# are replaced with this template prefixed with the correct comment notation (# or // or *) and SPDX- notation
|
||||
espressif_copyright: '{years} Espressif Systems (Shanghai) CO LTD'
|
||||
|
||||
# this section sets the default license for examples and unit tests of components
|
||||
examples_and_unit_tests:
|
||||
include:
|
||||
- 'examples/**'
|
||||
- 'components/**/examples/**'
|
||||
- 'components/**/test/**'
|
||||
- 'components/**/tests/**'
|
||||
- 'common_components/**'
|
||||
allowed_licenses:
|
||||
- Apache-2.0
|
||||
- Unlicense
|
||||
- CC0-1.0
|
||||
license_for_new_files: Unlicense OR CC0-1.0
|
||||
|
||||
asio_component:
|
||||
include:
|
||||
- 'components/asio/port/**'
|
||||
allowed_licenses:
|
||||
- Apache-2.0
|
||||
- BSL-1.0
|
||||
|
||||
slim_modem_examples:
|
||||
include:
|
||||
- 'examples/esp_netif/slip_custom_netif/**'
|
||||
allowed_licenses:
|
||||
- Apache-2.0
|
||||
- Unlicense
|
||||
- CC0-1.0
|
||||
|
||||
ignore:
|
||||
perform_check: no
|
||||
include:
|
||||
- '**/docs/**'
|
||||
- 'components/esp_modem/port/linux/**'
|
||||
- 'components/asio/examples/**'
|
||||
- 'components/mdns/**/esp_system_protocols_linux/**'
|
||||
- 'common_components/protocol_examples_common/**'
|
0
ci/check_copyright_ignore.txt
Normal file
0
ci/check_copyright_ignore.txt
Normal file
7
ci/clean_build_artifacts.sh
Executable file
7
ci/clean_build_artifacts.sh
Executable file
@ -0,0 +1,7 @@
|
||||
# Remove everything, but
|
||||
# - elf/bin files in the build dir
|
||||
# - partition-table and bootloader binaries
|
||||
# - flasher args
|
||||
# - sdkconfigs (header and json)
|
||||
# (Ignoring the command failure as it refuses to delete nonempty dirs)
|
||||
find $1 ! -regex ".*/build[^/]*/[^/]+.\(bin\|elf\)" -a ! -regex ".*\(bootloader\|partition-table\).bin" -a ! -name "flasher_args.json" -a ! -regex ".*/build[^/]*/config/sdkconfig.\(h\|json\)" -delete || true
|
41
ci/detect_component_bump
Executable file
41
ci/detect_component_bump
Executable file
@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
if ! git show -s | grep -q '^Merge'; then
|
||||
echo "Not a merge commit"
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
for comp in `ls components`; do
|
||||
if git log -1 -m --name-only --pretty="" | grep -q components/${comp}/idf_component.yml; then
|
||||
echo "${comp}: Component version file has changed"
|
||||
version=`grep version: components/${comp}/.cz.yaml`
|
||||
version=${version#*version: }
|
||||
|
||||
tag_format=`grep tag_format: components/${comp}/.cz.yaml`
|
||||
tag_format=${tag_format#*tag_format: }
|
||||
|
||||
eval tag=$tag_format
|
||||
# check if the tag is already created
|
||||
if [ $(git tag -l "$tag") ]; then
|
||||
echo "${comp}: version (${tag}) already exits"
|
||||
else
|
||||
echo "${comp}: Component version has been updated to ${version}"
|
||||
# creates release notes from the last entry (between first two "## sections")
|
||||
awk '/^## \[/{a++};{if(a==1){print}}' components/${comp}/CHANGELOG.md > release_notes.md
|
||||
|
||||
echo "BUMP_VERSION=${version}"
|
||||
echo "BUMP_COMPONENT=${comp}"
|
||||
echo "BUMP_TAG=${tag}"
|
||||
|
||||
# export the findings to github env, so it could be used in other jobs
|
||||
echo "BUMP_VERSION=${version}" >> "$GITHUB_ENV"
|
||||
echo "BUMP_COMPONENT=${comp}" >> "$GITHUB_ENV"
|
||||
echo "BUMP_TAG=${tag}" >> "$GITHUB_ENV"
|
||||
|
||||
exit 0;
|
||||
fi
|
||||
fi
|
||||
done
|
||||
echo "No changes in component version file"
|
1
ci/ignore_build_warnings.txt
Normal file
1
ci/ignore_build_warnings.txt
Normal file
@ -0,0 +1 @@
|
||||
DeprecationWarning: pkg_resources is deprecated as an API
|
8
ci/requirements.txt
Normal file
8
ci/requirements.txt
Normal file
@ -0,0 +1,8 @@
|
||||
pytest-embedded-serial-esp
|
||||
pytest-embedded-idf
|
||||
junit_xml
|
||||
SimpleWebSocketServer
|
||||
dpkt
|
||||
pytest
|
||||
idf_build_apps
|
||||
netifaces
|
8
common_components/linux_compat/esp_timer/CMakeLists.txt
Normal file
8
common_components/linux_compat/esp_timer/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
idf_component_register(SRCS esp_timer_linux.c timer_task.cpp
|
||||
INCLUDE_DIRS include)
|
||||
|
||||
set_target_properties(${COMPONENT_LIB} PROPERTIES
|
||||
CXX_STANDARD 17
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
CXX_EXTENSIONS ON
|
||||
)
|
47
common_components/linux_compat/esp_timer/esp_timer_linux.c
Normal file
47
common_components/linux_compat/esp_timer/esp_timer_linux.c
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "esp_err.h"
|
||||
#include "esp_timer.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include <pthread.h>
|
||||
|
||||
void *create_tt(esp_timer_cb_t cb);
|
||||
|
||||
void destroy_tt(void *tt);
|
||||
|
||||
void set_tout(void *tt, uint32_t ms);
|
||||
|
||||
esp_err_t esp_timer_create(const esp_timer_create_args_t *create_args,
|
||||
esp_timer_handle_t *out_handle)
|
||||
{
|
||||
*out_handle = (esp_timer_handle_t)create_tt(create_args->callback);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period)
|
||||
{
|
||||
set_tout(timer, period / 1000);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_timer_stop(esp_timer_handle_t timer)
|
||||
{
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_timer_delete(esp_timer_handle_t timer)
|
||||
{
|
||||
destroy_tt(timer);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int64_t esp_timer_get_time(void)
|
||||
{
|
||||
struct timespec spec;
|
||||
clock_gettime(CLOCK_REALTIME, &spec);
|
||||
return spec.tv_nsec / 1000 + spec.tv_sec * 1000000;
|
||||
}
|
45
common_components/linux_compat/esp_timer/include/esp_timer.h
Normal file
45
common_components/linux_compat/esp_timer/include/esp_timer.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bsd/string.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct esp_timer *esp_timer_handle_t;
|
||||
|
||||
typedef void (*esp_timer_cb_t)(void *arg);
|
||||
|
||||
typedef enum {
|
||||
ESP_TIMER_TASK,
|
||||
} esp_timer_dispatch_t;
|
||||
|
||||
typedef struct {
|
||||
esp_timer_cb_t callback; //!< Function to call when timer expires
|
||||
void *arg; //!< Argument to pass to the callback
|
||||
esp_timer_dispatch_t dispatch_method; //!< Call the callback from task or from ISR
|
||||
const char *name; //!< Timer name, used in esp_timer_dump function
|
||||
bool skip_unhandled_events; //!< Skip unhandled events for periodic timers
|
||||
} esp_timer_create_args_t;
|
||||
|
||||
esp_err_t esp_timer_create(const esp_timer_create_args_t *create_args,
|
||||
esp_timer_handle_t *out_handle);
|
||||
esp_err_t esp_timer_start_periodic(esp_timer_handle_t timer, uint64_t period);
|
||||
|
||||
esp_err_t esp_timer_stop(esp_timer_handle_t timer);
|
||||
|
||||
esp_err_t esp_timer_delete(esp_timer_handle_t timer);
|
||||
|
||||
int64_t esp_timer_get_time(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
30
common_components/linux_compat/esp_timer/timer_task.cpp
Normal file
30
common_components/linux_compat/esp_timer/timer_task.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "timer_task.hpp"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
|
||||
extern "C" void *create_tt(cb_t cb)
|
||||
{
|
||||
auto *tt = new TimerTaskMock(cb);
|
||||
return tt;
|
||||
}
|
||||
|
||||
extern "C" void destroy_tt(void *tt)
|
||||
{
|
||||
auto *timer_task = static_cast<TimerTaskMock *>(tt);
|
||||
delete (timer_task);
|
||||
}
|
||||
|
||||
|
||||
extern "C" void set_tout(void *tt, uint32_t ms)
|
||||
{
|
||||
auto *timer_task = static_cast<TimerTaskMock *>(tt);
|
||||
timer_task->SetTimeout(ms);
|
||||
}
|
57
common_components/linux_compat/esp_timer/timer_task.hpp
Normal file
57
common_components/linux_compat/esp_timer/timer_task.hpp
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
|
||||
typedef void (*cb_t)(void *arg);
|
||||
|
||||
class TimerTaskMock {
|
||||
public:
|
||||
TimerTaskMock(cb_t cb): cb(cb), active(false), ms(INT32_MAX) {}
|
||||
~TimerTaskMock(void)
|
||||
{
|
||||
active = false;
|
||||
t.join();
|
||||
}
|
||||
|
||||
void SetTimeout(uint32_t m)
|
||||
{
|
||||
ms = m;
|
||||
active = true;
|
||||
t = std::thread(run_static, this);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static void run_static(TimerTaskMock *timer)
|
||||
{
|
||||
timer->run();
|
||||
}
|
||||
|
||||
void run(void)
|
||||
{
|
||||
while (!active.load()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
while (active.load()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
|
||||
cb(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
cb_t cb;
|
||||
std::thread t;
|
||||
std::atomic<bool> active;
|
||||
uint32_t ms;
|
||||
|
||||
};
|
13
common_components/linux_compat/freertos/CMakeLists.txt
Normal file
13
common_components/linux_compat/freertos/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
idf_component_register(SRCS freertos_linux.c
|
||||
osal/queue.cpp osal/event_group.cpp osal/mutex.cpp
|
||||
INCLUDE_DIRS include)
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(${COMPONENT_LIB} PRIVATE Threads::Threads)
|
||||
|
||||
set_target_properties(${COMPONENT_LIB} PROPERTIES
|
||||
CXX_STANDARD 17
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
CXX_EXTENSIONS ON
|
||||
)
|
7
common_components/linux_compat/freertos/Kconfig
Normal file
7
common_components/linux_compat/freertos/Kconfig
Normal file
@ -0,0 +1,7 @@
|
||||
menu "FreeRTOS"
|
||||
|
||||
config FREERTOS_NO_AFFINITY
|
||||
hex
|
||||
default 0x7FFFFFFF
|
||||
|
||||
endmenu
|
272
common_components/linux_compat/freertos/freertos_linux.c
Normal file
272
common_components/linux_compat/freertos/freertos_linux.c
Normal file
@ -0,0 +1,272 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "osal/osal_api.h"
|
||||
|
||||
static uint64_t s_semaphore_data = 0;
|
||||
|
||||
typedef enum queue_type_tag {
|
||||
MUTEX_REC,
|
||||
MUTEX,
|
||||
SEMA,
|
||||
QUEUE,
|
||||
} queue_type_t;
|
||||
|
||||
struct generic_queue_handle {
|
||||
queue_type_t type;
|
||||
size_t item_size;
|
||||
void *q;
|
||||
};
|
||||
|
||||
static struct generic_queue_handle *create_generic_queue(queue_type_t type, uint32_t len, uint32_t item_size)
|
||||
{
|
||||
struct generic_queue_handle *h = calloc(1, sizeof(struct generic_queue_handle));
|
||||
h->item_size = len;
|
||||
h->type = type;
|
||||
switch (type) {
|
||||
default:
|
||||
case QUEUE:
|
||||
case SEMA:
|
||||
h->q = osal_queue_create();
|
||||
break;
|
||||
|
||||
case MUTEX:
|
||||
case MUTEX_REC:
|
||||
h->q = osal_mutex_create();
|
||||
break;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
QueueHandle_t xQueueCreate(uint32_t uxQueueLength, uint32_t uxItemSize )
|
||||
{
|
||||
return (QueueHandle_t)create_generic_queue(QUEUE, uxQueueLength, uxItemSize);
|
||||
}
|
||||
|
||||
uint32_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
return osal_queue_send(h->q, (uint8_t *)pvItemToQueue, h->item_size) ? pdTRUE : pdFAIL;
|
||||
}
|
||||
|
||||
uint32_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait )
|
||||
{
|
||||
return xQueueSend(xQueue, pvItemToQueue, xTicksToWait);
|
||||
}
|
||||
|
||||
uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
return osal_queue_recv(h->q, (uint8_t *)pvBuffer, h->item_size, xTicksToWait) ? pdTRUE : pdFAIL;
|
||||
}
|
||||
|
||||
BaseType_t xSemaphoreGive( QueueHandle_t xQueue)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX) {
|
||||
osal_mutex_give(h->q);
|
||||
return pdTRUE;
|
||||
}
|
||||
return xQueueSend(xQueue, &s_semaphore_data, portMAX_DELAY);
|
||||
}
|
||||
|
||||
BaseType_t xSemaphoreGiveRecursive( QueueHandle_t xQueue)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX_REC) {
|
||||
osal_mutex_give(h->q);
|
||||
return pdTRUE;
|
||||
}
|
||||
return pdFALSE;
|
||||
}
|
||||
BaseType_t xSemaphoreTake( QueueHandle_t xQueue, TickType_t pvTask )
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX) {
|
||||
osal_mutex_take(h->q);
|
||||
return pdTRUE;
|
||||
}
|
||||
return xQueueReceive(xQueue, &s_semaphore_data, portMAX_DELAY);
|
||||
}
|
||||
|
||||
|
||||
BaseType_t xSemaphoreTakeRecursive( QueueHandle_t xQueue, TickType_t pvTask )
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX_REC) {
|
||||
osal_mutex_take(h->q);
|
||||
return pdTRUE;
|
||||
}
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vQueueDelete( QueueHandle_t xQueue )
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->q) {
|
||||
if (h->type == MUTEX || h->type == MUTEX_REC) {
|
||||
osal_mutex_delete(h->q);
|
||||
} else {
|
||||
osal_queue_delete(h->q);
|
||||
}
|
||||
}
|
||||
free(xQueue);
|
||||
}
|
||||
|
||||
QueueHandle_t xSemaphoreCreateBinary(void)
|
||||
{
|
||||
QueueHandle_t sempaphore = xQueueCreate(1, 1);
|
||||
return sempaphore;
|
||||
}
|
||||
|
||||
QueueHandle_t xSemaphoreCreateMutex(void)
|
||||
{
|
||||
return (QueueHandle_t)create_generic_queue(MUTEX, 1, 1);
|
||||
}
|
||||
|
||||
QueueHandle_t xSemaphoreCreateRecursiveMutex(void)
|
||||
{
|
||||
return (QueueHandle_t)create_generic_queue(MUTEX_REC, 1, 1);
|
||||
}
|
||||
|
||||
|
||||
void vTaskDelete(TaskHandle_t *task)
|
||||
{
|
||||
if (task == NULL) {
|
||||
pthread_exit(0);
|
||||
}
|
||||
void *thread_rval = NULL;
|
||||
pthread_join((pthread_t)task, &thread_rval);
|
||||
}
|
||||
|
||||
void vTaskSuspend(void *task)
|
||||
{
|
||||
vTaskDelete(task);
|
||||
}
|
||||
|
||||
TickType_t xTaskGetTickCount( void )
|
||||
{
|
||||
struct timespec spec;
|
||||
clock_gettime(CLOCK_REALTIME, &spec);
|
||||
return spec.tv_nsec / 1000000 + spec.tv_sec * 1000;
|
||||
}
|
||||
|
||||
void vTaskDelay( const TickType_t xTicksToDelay )
|
||||
{
|
||||
usleep(xTicksToDelay * 1000);
|
||||
}
|
||||
|
||||
void *pthread_task(void *params)
|
||||
{
|
||||
struct {
|
||||
void *const param;
|
||||
TaskFunction_t task;
|
||||
bool started;
|
||||
} *pthread_params = params;
|
||||
|
||||
void *const param = pthread_params->param;
|
||||
TaskFunction_t task = pthread_params->task;
|
||||
pthread_params->started = true;
|
||||
|
||||
task(param);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pvTaskCode,
|
||||
const char *const pcName,
|
||||
const uint32_t usStackDepth,
|
||||
void *const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t *const pvCreatedTask,
|
||||
const BaseType_t xCoreID)
|
||||
{
|
||||
xTaskCreate(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pvCreatedTask);
|
||||
return pdTRUE;
|
||||
}
|
||||
|
||||
|
||||
BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, const char *const pcName, const uint32_t usStackDepth, void *const pvParameters, UBaseType_t uxPriority, TaskHandle_t *const pvCreatedTask)
|
||||
{
|
||||
pthread_t new_thread = (pthread_t)NULL;
|
||||
pthread_attr_t attr;
|
||||
struct {
|
||||
void *const param;
|
||||
TaskFunction_t task;
|
||||
bool started;
|
||||
} pthread_params = { .param = pvParameters, .task = pvTaskCode};
|
||||
int res = pthread_attr_init(&attr);
|
||||
assert(res == 0);
|
||||
res = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||||
assert(res == 0);
|
||||
res = pthread_create(&new_thread, &attr, pthread_task, &pthread_params);
|
||||
assert(res == 0);
|
||||
|
||||
if (pvCreatedTask) {
|
||||
*pvCreatedTask = (void *)new_thread;
|
||||
}
|
||||
|
||||
// just wait till the task started so we can unwind params from the stack
|
||||
while (pthread_params.started == false) {
|
||||
usleep(1000);
|
||||
}
|
||||
return pdTRUE;
|
||||
}
|
||||
|
||||
void xTaskNotifyGive(TaskHandle_t task)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
TaskHandle_t xTaskGetCurrentTaskHandle(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EventGroupHandle_t xEventGroupCreate( void )
|
||||
{
|
||||
return osal_signal_create();
|
||||
}
|
||||
|
||||
void vEventGroupDelete( EventGroupHandle_t xEventGroup )
|
||||
{
|
||||
osal_signal_delete(xEventGroup);
|
||||
}
|
||||
|
||||
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
|
||||
{
|
||||
return osal_signal_clear(xEventGroup, uxBitsToClear);
|
||||
}
|
||||
|
||||
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup)
|
||||
{
|
||||
return osal_signal_get(xEventGroup);
|
||||
}
|
||||
|
||||
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )
|
||||
{
|
||||
return osal_signal_set(xEventGroup, uxBitsToSet);
|
||||
}
|
||||
|
||||
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait )
|
||||
{
|
||||
return osal_signal_wait(xEventGroup, uxBitsToWaitFor, xWaitForAllBits, xTicksToWait);
|
||||
}
|
13
common_components/linux_compat/freertos/include/esp_task.h
Normal file
13
common_components/linux_compat/freertos/include/esp_task.h
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#define ESP_TASK_PRIO_MAX 25
|
||||
#define ESP_TASKD_EVENT_PRIO 5
|
||||
#define ESP_TASKD_EVENT_STACK 1024
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define portTICK_PERIOD_MS 1
|
||||
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
|
||||
|
||||
typedef void *SemaphoreHandle_t;
|
||||
typedef void *QueueHandle_t;
|
||||
typedef void *TaskHandle_t;
|
||||
typedef void *EventGroupHandle_t;
|
||||
typedef uint32_t TickType_t;
|
||||
typedef TickType_t EventBits_t;
|
||||
|
||||
typedef void (*TaskFunction_t)( void * );
|
||||
typedef unsigned int UBaseType_t;
|
||||
typedef int BaseType_t;
|
||||
|
||||
#define pdFALSE ( ( BaseType_t ) 0 )
|
||||
#define pdTRUE ( ( BaseType_t ) 1 )
|
||||
|
||||
#define pdPASS ( pdTRUE )
|
||||
#define pdFAIL ( pdFALSE )
|
||||
|
||||
#define pdMS_TO_TICKS(tick) (tick)
|
||||
|
||||
uint32_t esp_random(void);
|
||||
void vTaskSuspendAll(void);
|
@ -0,0 +1,6 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
@ -0,0 +1,6 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#pragma once
|
@ -0,0 +1,6 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#pragma once
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TaskHandle_t TaskHandle_t
|
||||
#define vSemaphoreDelete( xSemaphore ) vQueueDelete( ( QueueHandle_t ) ( xSemaphore ) )
|
||||
|
||||
void vTaskDelay( const TickType_t xTicksToDelay );
|
||||
|
||||
void xTaskNotifyGive(TaskHandle_t task);
|
||||
|
||||
TaskHandle_t xTaskGetCurrentTaskHandle(void);
|
||||
|
||||
BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time );
|
||||
|
||||
BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pvTaskCode,
|
||||
const char *const pcName,
|
||||
const uint32_t usStackDepth,
|
||||
void *const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t *const pvCreatedTask,
|
||||
const BaseType_t xCoreID);
|
||||
|
||||
BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, const char *const pcName, const uint32_t usStackDepth, void *const pvParameters, UBaseType_t uxPriority, TaskHandle_t *const pvCreatedTask);
|
||||
|
||||
TickType_t xTaskGetTickCount( void );
|
||||
|
||||
void vQueueDelete( QueueHandle_t xQueue );
|
||||
|
||||
QueueHandle_t xSemaphoreCreateBinary(void);
|
||||
|
||||
QueueHandle_t xSemaphoreCreateMutex(void);
|
||||
QueueHandle_t xSemaphoreCreateRecursiveMutex(void);
|
||||
|
||||
BaseType_t xSemaphoreGive( QueueHandle_t xQueue);
|
||||
|
||||
BaseType_t xSemaphoreTake( QueueHandle_t xQueue, TickType_t pvTask );
|
||||
|
||||
BaseType_t xSemaphoreGiveRecursive( QueueHandle_t xQueue);
|
||||
|
||||
BaseType_t xSemaphoreTakeRecursive( QueueHandle_t xQueue, TickType_t pvTask );
|
||||
|
||||
void vTaskDelete(TaskHandle_t *task);
|
||||
|
||||
QueueHandle_t xQueueCreate( uint32_t uxQueueLength,
|
||||
uint32_t uxItemSize );
|
||||
|
||||
uint32_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait);
|
||||
|
||||
uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait);
|
||||
|
||||
void vTaskSuspend(void *task);
|
||||
|
||||
EventGroupHandle_t xEventGroupCreate( void );
|
||||
void vEventGroupDelete( EventGroupHandle_t xEventGroup );
|
||||
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToClear );
|
||||
|
||||
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToWaitFor,
|
||||
const BaseType_t xClearOnExit,
|
||||
const BaseType_t xWaitForAllBits,
|
||||
TickType_t xTicksToWait );
|
||||
|
||||
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup);
|
||||
|
||||
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToSet );
|
||||
|
||||
uint32_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif //__cplusplus
|
109
common_components/linux_compat/freertos/osal/event_group.cpp
Normal file
109
common_components/linux_compat/freertos/osal/event_group.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include "osal_api.h"
|
||||
|
||||
|
||||
class SignalGroup {
|
||||
|
||||
struct SignalGroupInternal {
|
||||
std::condition_variable notify;
|
||||
std::mutex m;
|
||||
uint32_t flags{ 0 };
|
||||
};
|
||||
|
||||
using SignalT = std::unique_ptr<SignalGroupInternal>;
|
||||
|
||||
public:
|
||||
|
||||
void set(uint32_t bits)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(event_group->m);
|
||||
event_group->flags |= bits;
|
||||
event_group->notify.notify_all();
|
||||
}
|
||||
|
||||
uint32_t get()
|
||||
{
|
||||
return event_group->flags;
|
||||
}
|
||||
|
||||
void clear(uint32_t bits)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(event_group->m);
|
||||
event_group->flags &= ~bits;
|
||||
event_group->notify.notify_all();
|
||||
}
|
||||
|
||||
// waiting for all and clearing if set
|
||||
bool wait(uint32_t flags, uint32_t time_ms)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(event_group->m);
|
||||
return event_group->notify.wait_for(lock, std::chrono::milliseconds(time_ms), [&] {
|
||||
if ((flags & event_group->flags) == flags)
|
||||
{
|
||||
event_group->flags &= ~flags;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// waiting for any bit, not clearing them
|
||||
bool wait_any(uint32_t flags, uint32_t time_ms)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(event_group->m);
|
||||
return event_group->notify.wait_for(lock, std::chrono::milliseconds(time_ms), [&] { return flags & event_group->flags; });
|
||||
}
|
||||
|
||||
private:
|
||||
SignalT event_group{std::make_unique<SignalGroupInternal>()};
|
||||
};
|
||||
|
||||
|
||||
void *osal_signal_create()
|
||||
{
|
||||
auto signal = new SignalGroup;
|
||||
return signal;
|
||||
}
|
||||
|
||||
void osal_signal_delete(void *s)
|
||||
{
|
||||
delete static_cast<SignalGroup *>(s);
|
||||
}
|
||||
|
||||
uint32_t osal_signal_clear(void *s, uint32_t bits)
|
||||
{
|
||||
auto signal = static_cast<SignalGroup *>(s);
|
||||
signal->clear(bits);
|
||||
return signal->get();
|
||||
}
|
||||
|
||||
uint32_t osal_signal_set(void *s, uint32_t bits)
|
||||
{
|
||||
auto signal = static_cast<SignalGroup *>(s);
|
||||
signal->set(bits);
|
||||
return signal->get();
|
||||
}
|
||||
|
||||
uint32_t osal_signal_get(void *s)
|
||||
{
|
||||
auto signal = static_cast<SignalGroup *>(s);
|
||||
return signal->get();
|
||||
}
|
||||
|
||||
uint32_t osal_signal_wait(void *s, uint32_t flags, bool all, uint32_t timeout)
|
||||
{
|
||||
auto signal = static_cast<SignalGroup *>(s);
|
||||
if (all) {
|
||||
signal->wait(flags, timeout);
|
||||
} else {
|
||||
signal->wait_any(flags, timeout);
|
||||
}
|
||||
return signal->get();
|
||||
}
|
31
common_components/linux_compat/freertos/osal/mutex.cpp
Normal file
31
common_components/linux_compat/freertos/osal/mutex.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include "osal_api.h"
|
||||
|
||||
void *osal_mutex_create()
|
||||
{
|
||||
auto mut = new std::recursive_mutex();
|
||||
return mut;
|
||||
}
|
||||
|
||||
void osal_mutex_delete(void *mut)
|
||||
{
|
||||
delete static_cast<std::recursive_mutex *>(mut);
|
||||
}
|
||||
|
||||
void osal_mutex_take(void *m)
|
||||
{
|
||||
auto mut = static_cast<std::recursive_mutex *>(m);
|
||||
mut->lock();
|
||||
}
|
||||
|
||||
void osal_mutex_give(void *m)
|
||||
{
|
||||
auto mut = static_cast<std::recursive_mutex *>(m);
|
||||
mut->unlock();
|
||||
}
|
34
common_components/linux_compat/freertos/osal/osal_api.h
Normal file
34
common_components/linux_compat/freertos/osal/osal_api.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// queue api
|
||||
void *osal_queue_create(void);
|
||||
void osal_queue_delete(void *q);
|
||||
bool osal_queue_send(void *q, uint8_t *data, size_t len);
|
||||
bool osal_queue_recv(void *q, uint8_t *data, size_t len, uint32_t ms);
|
||||
|
||||
// mutex api
|
||||
void *osal_mutex_create(void);
|
||||
void osal_mutex_delete(void *m);
|
||||
void osal_mutex_take(void *m);
|
||||
void osal_mutex_give(void *m);
|
||||
|
||||
// event groups
|
||||
void *osal_signal_create(void);
|
||||
void osal_signal_delete(void *s);
|
||||
uint32_t osal_signal_clear(void *s, uint32_t bits);
|
||||
uint32_t osal_signal_set(void *s, uint32_t bits);
|
||||
uint32_t osal_signal_get(void *s);
|
||||
uint32_t osal_signal_wait(void *s, uint32_t flags, bool all, uint32_t timeout);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
78
common_components/linux_compat/freertos/osal/queue.cpp
Normal file
78
common_components/linux_compat/freertos/osal/queue.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <atomic>
|
||||
#include "osal_api.h"
|
||||
|
||||
template <class T>
|
||||
class Queue {
|
||||
public:
|
||||
void send(std::unique_ptr<T> t)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m);
|
||||
q.push(std::move(t));
|
||||
c.notify_one();
|
||||
}
|
||||
|
||||
std::unique_ptr<T> receive(std::chrono::milliseconds ms)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m);
|
||||
while (q.empty()) {
|
||||
if (c.wait_for(lock, ms) == std::cv_status::timeout) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
std::unique_ptr<T> val = std::move(q.front());
|
||||
q.pop();
|
||||
return val;
|
||||
}
|
||||
|
||||
private:
|
||||
std::queue<std::unique_ptr<T>> q{};
|
||||
mutable std::mutex m{};
|
||||
std::condition_variable c{};
|
||||
};
|
||||
|
||||
using item_t = std::vector<uint8_t>;
|
||||
|
||||
void *osal_queue_create(void)
|
||||
{
|
||||
auto *q = new Queue<item_t>();
|
||||
return q;
|
||||
}
|
||||
|
||||
void osal_queue_delete(void *q)
|
||||
{
|
||||
auto *queue = static_cast<Queue<item_t> *>(q);
|
||||
delete (queue);
|
||||
}
|
||||
|
||||
bool osal_queue_send(void *q, uint8_t *data, size_t len)
|
||||
{
|
||||
auto v = std::make_unique<item_t>(len);
|
||||
v->assign(data, data + len);
|
||||
auto queue = static_cast<Queue<item_t> *>(q);
|
||||
queue->send(std::move(v));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool osal_queue_recv(void *q, uint8_t *data, size_t len, uint32_t ms)
|
||||
{
|
||||
auto queue = static_cast<Queue<item_t> *>(q);
|
||||
auto v = queue->receive(std::chrono::milliseconds(ms));
|
||||
if (v != nullptr) {
|
||||
memcpy(data, (void *)v->data(), len);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
idf_component_register(SRCS "connect.c" "stdin_out.c" "addr_from_stdin.c"
|
||||
INCLUDE_DIRS "include"
|
||||
PRIV_REQUIRES esp_netif driver esp_eth esp_wifi vfs
|
||||
)
|
322
common_components/protocol_examples_common/Kconfig.projbuild
Normal file
322
common_components/protocol_examples_common/Kconfig.projbuild
Normal file
@ -0,0 +1,322 @@
|
||||
menu "Example Connection Configuration"
|
||||
|
||||
orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps"
|
||||
|
||||
config EXAMPLE_CONNECT_WIFI
|
||||
bool "connect using WiFi interface"
|
||||
default y
|
||||
help
|
||||
Protocol examples can use Wi-Fi and/or Ethernet to connect to the network.
|
||||
Choose this option to connect with WiFi
|
||||
|
||||
if EXAMPLE_CONNECT_WIFI
|
||||
config EXAMPLE_WIFI_SSID
|
||||
string "WiFi SSID"
|
||||
default "myssid"
|
||||
help
|
||||
SSID (network name) for the example to connect to.
|
||||
|
||||
config EXAMPLE_WIFI_PASSWORD
|
||||
string "WiFi Password"
|
||||
default "mypassword"
|
||||
help
|
||||
WiFi password (WPA or WPA2) for the example to use.
|
||||
Can be left blank if the network has no security set.
|
||||
|
||||
choice EXAMPLE_WIFI_SCAN_METHOD
|
||||
prompt "WiFi Scan Method"
|
||||
default EXAMPLE_WIFI_SCAN_METHOD_ALL_CHANNEL
|
||||
help
|
||||
WiFi scan method:
|
||||
|
||||
If "Fast" is selected, scan will end after find SSID match AP.
|
||||
|
||||
If "All Channel" is selected, scan will end after scan all the channel.
|
||||
|
||||
config EXAMPLE_WIFI_SCAN_METHOD_FAST
|
||||
bool "Fast"
|
||||
config EXAMPLE_WIFI_SCAN_METHOD_ALL_CHANNEL
|
||||
bool "All Channel"
|
||||
endchoice
|
||||
|
||||
menu "WiFi Scan threshold"
|
||||
config EXAMPLE_WIFI_SCAN_RSSI_THRESHOLD
|
||||
int "WiFi minimum rssi"
|
||||
range -127 0
|
||||
|
||||
default -127
|
||||
help
|
||||
The minimum rssi to accept in the scan mode.
|
||||
|
||||
choice EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD
|
||||
prompt "WiFi Scan auth mode threshold"
|
||||
default EXAMPLE_WIFI_AUTH_OPEN
|
||||
help
|
||||
The weakest authmode to accept in the scan mode.
|
||||
|
||||
config EXAMPLE_WIFI_AUTH_OPEN
|
||||
bool "OPEN"
|
||||
config EXAMPLE_WIFI_AUTH_WEP
|
||||
bool "WEP"
|
||||
config EXAMPLE_WIFI_AUTH_WPA_PSK
|
||||
bool "WPA PSK"
|
||||
config EXAMPLE_WIFI_AUTH_WPA2_PSK
|
||||
bool "WPA2 PSK"
|
||||
config EXAMPLE_WIFI_AUTH_WPA_WPA2_PSK
|
||||
bool "WPA WPA2 PSK"
|
||||
config EXAMPLE_WIFI_AUTH_WPA2_ENTERPRISE
|
||||
bool "WPA2 ENTERPRISE"
|
||||
config EXAMPLE_WIFI_AUTH_WPA3_PSK
|
||||
bool "WPA3 PSK"
|
||||
config EXAMPLE_WIFI_AUTH_WPA2_WPA3_PSK
|
||||
bool "WPA2 WPA3 PSK"
|
||||
config EXAMPLE_WIFI_AUTH_WAPI_PSK
|
||||
bool "WAPI PSK"
|
||||
endchoice
|
||||
endmenu
|
||||
|
||||
choice EXAMPLE_WIFI_CONNECT_AP_SORT_METHOD
|
||||
prompt "WiFi Connect AP Sort Method"
|
||||
default EXAMPLE_WIFI_CONNECT_AP_BY_SIGNAL
|
||||
help
|
||||
WiFi connect AP sort method:
|
||||
|
||||
If "Signal" is selected, Sort matched APs in scan list by RSSI.
|
||||
|
||||
If "Security" is selected, Sort matched APs in scan list by security mode.
|
||||
|
||||
config EXAMPLE_WIFI_CONNECT_AP_BY_SIGNAL
|
||||
bool "Signal"
|
||||
config EXAMPLE_WIFI_CONNECT_AP_BY_SECURITY
|
||||
bool "Security"
|
||||
endchoice
|
||||
endif
|
||||
|
||||
config EXAMPLE_CONNECT_ETHERNET
|
||||
bool "connect using Ethernet interface"
|
||||
default n
|
||||
help
|
||||
Protocol examples can use Wi-Fi and/or Ethernet to connect to the network.
|
||||
Choose this option to connect with Ethernet
|
||||
|
||||
if EXAMPLE_CONNECT_ETHERNET
|
||||
config EXAMPLE_USE_SPI_ETHERNET
|
||||
bool
|
||||
|
||||
choice EXAMPLE_ETHERNET_TYPE
|
||||
prompt "Ethernet Type"
|
||||
default EXAMPLE_USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32
|
||||
default EXAMPLE_USE_W5500
|
||||
help
|
||||
Select which kind of Ethernet will be used in the example.
|
||||
|
||||
config EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
depends on IDF_TARGET_ESP32
|
||||
select ETH_USE_ESP32_EMAC
|
||||
bool "Internal EMAC"
|
||||
help
|
||||
Select internal Ethernet MAC controller.
|
||||
|
||||
config EXAMPLE_USE_DM9051
|
||||
bool "DM9051 Module"
|
||||
select EXAMPLE_USE_SPI_ETHERNET
|
||||
select ETH_USE_SPI_ETHERNET
|
||||
select ETH_SPI_ETHERNET_DM9051
|
||||
help
|
||||
Select external SPI-Ethernet module.
|
||||
|
||||
config EXAMPLE_USE_W5500
|
||||
bool "W5500 Module"
|
||||
select EXAMPLE_USE_SPI_ETHERNET
|
||||
select ETH_USE_SPI_ETHERNET
|
||||
select ETH_SPI_ETHERNET_W5500
|
||||
help
|
||||
Select external SPI-Ethernet module (W5500).
|
||||
|
||||
config EXAMPLE_USE_OPENETH
|
||||
bool "OpenCores Ethernet MAC (EXPERIMENTAL)"
|
||||
select ETH_USE_OPENETH
|
||||
help
|
||||
When this option is enabled, the example is built with support for
|
||||
OpenCores Ethernet MAC, which allows testing the example in QEMU.
|
||||
Note that this option is used for internal testing purposes, and
|
||||
not officially supported. Examples built with this option enabled
|
||||
will not run on a real ESP32 chip.
|
||||
|
||||
endchoice # EXAMPLE_ETHERNET_TYPE
|
||||
|
||||
if EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
choice EXAMPLE_ETH_PHY_MODEL
|
||||
prompt "Ethernet PHY Device"
|
||||
default EXAMPLE_ETH_PHY_IP101
|
||||
help
|
||||
Select the Ethernet PHY device to use in the example.
|
||||
|
||||
config EXAMPLE_ETH_PHY_IP101
|
||||
bool "IP101"
|
||||
help
|
||||
IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver.
|
||||
Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it.
|
||||
|
||||
config EXAMPLE_ETH_PHY_RTL8201
|
||||
bool "RTL8201/SR8201"
|
||||
help
|
||||
RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX.
|
||||
Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it.
|
||||
|
||||
config EXAMPLE_ETH_PHY_LAN87XX
|
||||
bool "LAN87xx"
|
||||
help
|
||||
Below chips are supported:
|
||||
LAN8710A is a small footprint MII/RMII 10/100 Ethernet Transceiver with HP Auto-MDIX and
|
||||
flexPWR® Technology.
|
||||
LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support.
|
||||
LAN8740A/LAN8741A is a small footprint MII/RMII 10/100 Energy Efficient Ethernet Transceiver
|
||||
with HP Auto-MDIX and flexPWR® Technology.
|
||||
LAN8742A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX and
|
||||
flexPWR® Technology.
|
||||
Goto https://www.microchip.com for more information about them.
|
||||
|
||||
config EXAMPLE_ETH_PHY_DP83848
|
||||
bool "DP83848"
|
||||
help
|
||||
DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver.
|
||||
Goto http://www.ti.com/product/DP83848J for more information about it.
|
||||
|
||||
config EXAMPLE_ETH_PHY_KSZ80XX
|
||||
bool "KSZ80xx"
|
||||
help
|
||||
With the KSZ80xx series, Microchip offers single-chip 10BASE-T/100BASE-TX
|
||||
Ethernet Physical Layer Tranceivers (PHY).
|
||||
The following chips are supported: KSZ8001, KSZ8021, KSZ8031, KSZ8041,
|
||||
KSZ8051, KSZ8061, KSZ8081, KSZ8091
|
||||
Goto https://www.microchip.com for more information about them.
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_ETH_MDC_GPIO
|
||||
int "SMI MDC GPIO number"
|
||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||
default 23
|
||||
help
|
||||
Set the GPIO number used by SMI MDC.
|
||||
|
||||
config EXAMPLE_ETH_MDIO_GPIO
|
||||
int "SMI MDIO GPIO number"
|
||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||
default 18
|
||||
help
|
||||
Set the GPIO number used by SMI MDIO.
|
||||
endif
|
||||
|
||||
if EXAMPLE_USE_SPI_ETHERNET
|
||||
config EXAMPLE_ETH_SPI_HOST
|
||||
int "SPI Host Number"
|
||||
range 0 2
|
||||
default 1
|
||||
help
|
||||
Set the SPI host used to communicate with the SPI Ethernet Controller.
|
||||
|
||||
config EXAMPLE_ETH_SPI_SCLK_GPIO
|
||||
int "SPI SCLK GPIO number"
|
||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||
default 14
|
||||
help
|
||||
Set the GPIO number used by SPI SCLK.
|
||||
|
||||
config EXAMPLE_ETH_SPI_MOSI_GPIO
|
||||
int "SPI MOSI GPIO number"
|
||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||
default 13
|
||||
help
|
||||
Set the GPIO number used by SPI MOSI.
|
||||
|
||||
config EXAMPLE_ETH_SPI_MISO_GPIO
|
||||
int "SPI MISO GPIO number"
|
||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX
|
||||
default 12
|
||||
help
|
||||
Set the GPIO number used by SPI MISO.
|
||||
|
||||
config EXAMPLE_ETH_SPI_CS_GPIO
|
||||
int "SPI CS GPIO number"
|
||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||
default 15
|
||||
help
|
||||
Set the GPIO number used by SPI CS.
|
||||
|
||||
config EXAMPLE_ETH_SPI_CLOCK_MHZ
|
||||
int "SPI clock speed (MHz)"
|
||||
range 5 80
|
||||
default 36
|
||||
help
|
||||
Set the clock speed (MHz) of SPI interface.
|
||||
|
||||
config EXAMPLE_ETH_SPI_INT_GPIO
|
||||
int "Interrupt GPIO number"
|
||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX
|
||||
default 4
|
||||
help
|
||||
Set the GPIO number used by the SPI Ethernet module interrupt line.
|
||||
endif # EXAMPLE_USE_SPI_ETHERNET
|
||||
|
||||
config EXAMPLE_ETH_PHY_RST_GPIO
|
||||
int "PHY Reset GPIO number"
|
||||
range -1 ENV_GPIO_OUT_RANGE_MAX
|
||||
default 5
|
||||
help
|
||||
Set the GPIO number used to reset PHY chip.
|
||||
Set to -1 to disable PHY chip hardware reset.
|
||||
|
||||
config EXAMPLE_ETH_PHY_ADDR
|
||||
int "PHY Address"
|
||||
range 0 31 if EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
default 1
|
||||
help
|
||||
Set PHY address according your board schematic.
|
||||
endif # EXAMPLE_CONNECT_ETHERNET
|
||||
|
||||
config EXAMPLE_CONNECT_IPV6
|
||||
bool "Obtain IPv6 address"
|
||||
default y
|
||||
depends on EXAMPLE_CONNECT_WIFI || EXAMPLE_CONNECT_ETHERNET
|
||||
select LWIP_IPV6
|
||||
help
|
||||
By default, examples will wait until IPv4 and IPv6 local link addresses are obtained.
|
||||
Disable this option if the network does not support IPv6.
|
||||
Choose the preferred IPv6 address type if the connection code should wait until other than
|
||||
the local link address gets assigned.
|
||||
Consider enabling IPv6 stateless address autoconfiguration (SLAAC) in the LWIP component.
|
||||
|
||||
if EXAMPLE_CONNECT_IPV6
|
||||
choice EXAMPLE_CONNECT_PREFERRED_IPV6
|
||||
prompt "Preferred IPv6 Type"
|
||||
default EXAMPLE_CONNECT_IPV6_PREF_LOCAL_LINK
|
||||
help
|
||||
Select which kind of IPv6 address the connect logic waits for.
|
||||
|
||||
config EXAMPLE_CONNECT_IPV6_PREF_LOCAL_LINK
|
||||
bool "Local Link Address"
|
||||
help
|
||||
Blocks until Local link address assigned.
|
||||
|
||||
config EXAMPLE_CONNECT_IPV6_PREF_GLOBAL
|
||||
bool "Global Address"
|
||||
help
|
||||
Blocks until Global address assigned.
|
||||
|
||||
config EXAMPLE_CONNECT_IPV6_PREF_SITE_LOCAL
|
||||
bool "Site Local Address"
|
||||
help
|
||||
Blocks until Site link address assigned.
|
||||
|
||||
config EXAMPLE_CONNECT_IPV6_PREF_UNIQUE_LOCAL
|
||||
bool "Unique Local Link Address"
|
||||
help
|
||||
Blocks until Unique local address assigned.
|
||||
|
||||
endchoice
|
||||
|
||||
endif
|
||||
|
||||
|
||||
endmenu
|
68
common_components/protocol_examples_common/addr_from_stdin.c
Normal file
68
common_components/protocol_examples_common/addr_from_stdin.c
Normal file
@ -0,0 +1,68 @@
|
||||
#include <string.h>
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_netif.h"
|
||||
#include "protocol_examples_common.h"
|
||||
|
||||
#include "lwip/sockets.h"
|
||||
#include <lwip/netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define HOST_IP_SIZE 128
|
||||
|
||||
esp_err_t get_addr_from_stdin(int port, int sock_type, int *ip_protocol, int *addr_family, struct sockaddr_storage *dest_addr)
|
||||
{
|
||||
char host_ip[HOST_IP_SIZE];
|
||||
int len;
|
||||
static bool already_init = false;
|
||||
|
||||
// this function could be called multiple times -> make sure UART init runs only once
|
||||
if (!already_init) {
|
||||
example_configure_stdin_stdout();
|
||||
already_init = true;
|
||||
}
|
||||
|
||||
// ignore empty or LF only string (could receive from DUT class)
|
||||
do {
|
||||
fgets(host_ip, HOST_IP_SIZE, stdin);
|
||||
len = strlen(host_ip);
|
||||
} while (len <= 1 && host_ip[0] == '\n');
|
||||
host_ip[len - 1] = '\0';
|
||||
|
||||
struct addrinfo hints, *addr_list, *cur;
|
||||
memset( &hints, 0, sizeof( hints ) );
|
||||
|
||||
// run getaddrinfo() to decide on the IP protocol
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = sock_type;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
if ( getaddrinfo( host_ip, NULL, &hints, &addr_list ) != 0 ) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
for ( cur = addr_list; cur != NULL; cur = cur->ai_next ) {
|
||||
memcpy(dest_addr, cur->ai_addr, sizeof(*dest_addr));
|
||||
if (cur->ai_family == AF_INET) {
|
||||
*ip_protocol = IPPROTO_IP;
|
||||
*addr_family = AF_INET;
|
||||
// add port number and return on first IPv4 match
|
||||
((struct sockaddr_in *)dest_addr)->sin_port = htons(port);
|
||||
freeaddrinfo( addr_list );
|
||||
return ESP_OK;
|
||||
|
||||
}
|
||||
#if CONFIG_LWIP_IPV6
|
||||
else if (cur->ai_family == AF_INET6) {
|
||||
*ip_protocol = IPPROTO_IPV6;
|
||||
*addr_family = AF_INET6;
|
||||
// add port and interface number and return on first IPv6 match
|
||||
((struct sockaddr_in6 *)dest_addr)->sin6_port = htons(port);
|
||||
((struct sockaddr_in6 *)dest_addr)->sin6_scope_id = esp_netif_get_netif_impl_index(EXAMPLE_INTERFACE);
|
||||
freeaddrinfo( addr_list );
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// no match found
|
||||
freeaddrinfo( addr_list );
|
||||
return ESP_FAIL;
|
||||
}
|
527
common_components/protocol_examples_common/connect.c
Normal file
527
common_components/protocol_examples_common/connect.c
Normal file
@ -0,0 +1,527 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Common functions for protocol examples, to establish Wi-Fi or Ethernet connection.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "protocol_examples_common.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_wifi_default.h"
|
||||
#if CONFIG_EXAMPLE_CONNECT_ETHERNET
|
||||
#include "esp_eth.h"
|
||||
#if CONFIG_ETH_USE_SPI_ETHERNET
|
||||
#include "driver/spi_master.h"
|
||||
#endif // CONFIG_ETH_USE_SPI_ETHERNET
|
||||
#endif // CONFIG_EXAMPLE_CONNECT_ETHERNET
|
||||
#include "esp_log.h"
|
||||
#include "esp_netif.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sys.h"
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_CONNECT_IPV6
|
||||
#define MAX_IP6_ADDRS_PER_NETIF (5)
|
||||
#define NR_OF_IP_ADDRESSES_TO_WAIT_FOR (s_active_interfaces*2)
|
||||
|
||||
#if defined(CONFIG_EXAMPLE_CONNECT_IPV6_PREF_LOCAL_LINK)
|
||||
#define EXAMPLE_CONNECT_PREFERRED_IPV6_TYPE ESP_IP6_ADDR_IS_LINK_LOCAL
|
||||
#elif defined(CONFIG_EXAMPLE_CONNECT_IPV6_PREF_GLOBAL)
|
||||
#define EXAMPLE_CONNECT_PREFERRED_IPV6_TYPE ESP_IP6_ADDR_IS_GLOBAL
|
||||
#elif defined(CONFIG_EXAMPLE_CONNECT_IPV6_PREF_SITE_LOCAL)
|
||||
#define EXAMPLE_CONNECT_PREFERRED_IPV6_TYPE ESP_IP6_ADDR_IS_SITE_LOCAL
|
||||
#elif defined(CONFIG_EXAMPLE_CONNECT_IPV6_PREF_UNIQUE_LOCAL)
|
||||
#define EXAMPLE_CONNECT_PREFERRED_IPV6_TYPE ESP_IP6_ADDR_IS_UNIQUE_LOCAL
|
||||
#endif // if-elif CONFIG_EXAMPLE_CONNECT_IPV6_PREF_...
|
||||
|
||||
#else
|
||||
#define NR_OF_IP_ADDRESSES_TO_WAIT_FOR (s_active_interfaces)
|
||||
#endif
|
||||
|
||||
#define EXAMPLE_DO_CONNECT CONFIG_EXAMPLE_CONNECT_WIFI || CONFIG_EXAMPLE_CONNECT_ETHERNET
|
||||
|
||||
#if CONFIG_EXAMPLE_WIFI_SCAN_METHOD_FAST
|
||||
#define EXAMPLE_WIFI_SCAN_METHOD WIFI_FAST_SCAN
|
||||
#elif CONFIG_EXAMPLE_WIFI_SCAN_METHOD_ALL_CHANNEL
|
||||
#define EXAMPLE_WIFI_SCAN_METHOD WIFI_ALL_CHANNEL_SCAN
|
||||
#endif
|
||||
|
||||
#if CONFIG_EXAMPLE_WIFI_CONNECT_AP_BY_SIGNAL
|
||||
#define EXAMPLE_WIFI_CONNECT_AP_SORT_METHOD WIFI_CONNECT_AP_BY_SIGNAL
|
||||
#elif CONFIG_EXAMPLE_WIFI_CONNECT_AP_BY_SECURITY
|
||||
#define EXAMPLE_WIFI_CONNECT_AP_SORT_METHOD WIFI_CONNECT_AP_BY_SECURITY
|
||||
#endif
|
||||
|
||||
#if CONFIG_EXAMPLE_WIFI_AUTH_OPEN
|
||||
#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_OPEN
|
||||
#elif CONFIG_EXAMPLE_WIFI_AUTH_WEP
|
||||
#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WEP
|
||||
#elif CONFIG_EXAMPLE_WIFI_AUTH_WPA_PSK
|
||||
#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_PSK
|
||||
#elif CONFIG_EXAMPLE_WIFI_AUTH_WPA2_PSK
|
||||
#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_PSK
|
||||
#elif CONFIG_EXAMPLE_WIFI_AUTH_WPA_WPA2_PSK
|
||||
#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_WPA2_PSK
|
||||
#elif CONFIG_EXAMPLE_WIFI_AUTH_WPA2_ENTERPRISE
|
||||
#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_ENTERPRISE
|
||||
#elif CONFIG_EXAMPLE_WIFI_AUTH_WPA3_PSK
|
||||
#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA3_PSK
|
||||
#elif CONFIG_EXAMPLE_WIFI_AUTH_WPA2_WPA3_PSK
|
||||
#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_WPA3_PSK
|
||||
#elif CONFIG_EXAMPLE_WIFI_AUTH_WAPI_PSK
|
||||
#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WAPI_PSK
|
||||
#endif
|
||||
|
||||
static int s_active_interfaces = 0;
|
||||
static SemaphoreHandle_t s_semph_get_ip_addrs;
|
||||
static esp_netif_t *s_example_esp_netif = NULL;
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_CONNECT_IPV6
|
||||
static esp_ip6_addr_t s_ipv6_addr;
|
||||
|
||||
/* types of ipv6 addresses to be displayed on ipv6 events */
|
||||
static const char *s_ipv6_addr_types[] = {
|
||||
"ESP_IP6_ADDR_IS_UNKNOWN",
|
||||
"ESP_IP6_ADDR_IS_GLOBAL",
|
||||
"ESP_IP6_ADDR_IS_LINK_LOCAL",
|
||||
"ESP_IP6_ADDR_IS_SITE_LOCAL",
|
||||
"ESP_IP6_ADDR_IS_UNIQUE_LOCAL",
|
||||
"ESP_IP6_ADDR_IS_IPV4_MAPPED_IPV6"
|
||||
};
|
||||
#endif
|
||||
|
||||
static const char *TAG = "example_connect";
|
||||
|
||||
#if CONFIG_EXAMPLE_CONNECT_WIFI
|
||||
static esp_netif_t *wifi_start(void);
|
||||
static void wifi_stop(void);
|
||||
#endif
|
||||
#if CONFIG_EXAMPLE_CONNECT_ETHERNET
|
||||
static esp_netif_t *eth_start(void);
|
||||
static void eth_stop(void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Checks the netif description if it contains specified prefix.
|
||||
* All netifs created withing common connect component are prefixed with the module TAG,
|
||||
* so it returns true if the specified netif is owned by this module
|
||||
*/
|
||||
static bool is_our_netif(const char *prefix, esp_netif_t *netif)
|
||||
{
|
||||
return strncmp(prefix, esp_netif_get_desc(netif), strlen(prefix) - 1) == 0;
|
||||
}
|
||||
|
||||
/* set up connection, Wi-Fi and/or Ethernet */
|
||||
static void start(void)
|
||||
{
|
||||
|
||||
#if CONFIG_EXAMPLE_CONNECT_WIFI
|
||||
s_example_esp_netif = wifi_start();
|
||||
s_active_interfaces++;
|
||||
#endif
|
||||
|
||||
#if CONFIG_EXAMPLE_CONNECT_ETHERNET
|
||||
s_example_esp_netif = eth_start();
|
||||
s_active_interfaces++;
|
||||
#endif
|
||||
|
||||
#if CONFIG_EXAMPLE_CONNECT_WIFI && CONFIG_EXAMPLE_CONNECT_ETHERNET
|
||||
/* if both intefaces at once, clear out to indicate that multiple netifs are active */
|
||||
s_example_esp_netif = NULL;
|
||||
#endif
|
||||
|
||||
#if EXAMPLE_DO_CONNECT
|
||||
/* create semaphore if at least one interface is active */
|
||||
s_semph_get_ip_addrs = xSemaphoreCreateCounting(NR_OF_IP_ADDRESSES_TO_WAIT_FOR, 0);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* tear down connection, release resources */
|
||||
static void stop(void)
|
||||
{
|
||||
#if CONFIG_EXAMPLE_CONNECT_WIFI
|
||||
wifi_stop();
|
||||
s_active_interfaces--;
|
||||
#endif
|
||||
|
||||
#if CONFIG_EXAMPLE_CONNECT_ETHERNET
|
||||
eth_stop();
|
||||
s_active_interfaces--;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if EXAMPLE_DO_CONNECT
|
||||
static esp_ip4_addr_t s_ip_addr;
|
||||
|
||||
static void on_got_ip(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
|
||||
if (!is_our_netif(TAG, event->esp_netif)) {
|
||||
ESP_LOGW(TAG, "Got IPv4 from another interface \"%s\": ignored", esp_netif_get_desc(event->esp_netif));
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "Got IPv4 event: Interface \"%s\" address: " IPSTR, esp_netif_get_desc(event->esp_netif), IP2STR(&event->ip_info.ip));
|
||||
memcpy(&s_ip_addr, &event->ip_info.ip, sizeof(s_ip_addr));
|
||||
xSemaphoreGive(s_semph_get_ip_addrs);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_CONNECT_IPV6
|
||||
|
||||
static void on_got_ipv6(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
ip_event_got_ip6_t *event = (ip_event_got_ip6_t *)event_data;
|
||||
if (!is_our_netif(TAG, event->esp_netif)) {
|
||||
ESP_LOGW(TAG, "Got IPv6 from another netif: ignored");
|
||||
return;
|
||||
}
|
||||
esp_ip6_addr_type_t ipv6_type = esp_netif_ip6_get_addr_type(&event->ip6_info.ip);
|
||||
ESP_LOGI(TAG, "Got IPv6 event: Interface \"%s\" address: " IPV6STR ", type: %s", esp_netif_get_desc(event->esp_netif),
|
||||
IPV62STR(event->ip6_info.ip), s_ipv6_addr_types[ipv6_type]);
|
||||
if (ipv6_type == EXAMPLE_CONNECT_PREFERRED_IPV6_TYPE) {
|
||||
memcpy(&s_ipv6_addr, &event->ip6_info.ip, sizeof(s_ipv6_addr));
|
||||
xSemaphoreGive(s_semph_get_ip_addrs);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CONFIG_EXAMPLE_CONNECT_IPV6
|
||||
|
||||
esp_err_t example_connect(void)
|
||||
{
|
||||
#if EXAMPLE_DO_CONNECT
|
||||
if (s_semph_get_ip_addrs != NULL) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
#endif
|
||||
start();
|
||||
ESP_ERROR_CHECK(esp_register_shutdown_handler(&stop));
|
||||
ESP_LOGI(TAG, "Waiting for IP(s)");
|
||||
for (int i = 0; i < NR_OF_IP_ADDRESSES_TO_WAIT_FOR; ++i) {
|
||||
xSemaphoreTake(s_semph_get_ip_addrs, portMAX_DELAY);
|
||||
}
|
||||
// iterate over active interfaces, and print out IPs of "our" netifs
|
||||
esp_netif_t *netif = NULL;
|
||||
esp_netif_ip_info_t ip;
|
||||
for (int i = 0; i < esp_netif_get_nr_of_ifs(); ++i) {
|
||||
netif = esp_netif_next(netif);
|
||||
if (is_our_netif(TAG, netif)) {
|
||||
ESP_LOGI(TAG, "Connected to %s", esp_netif_get_desc(netif));
|
||||
ESP_ERROR_CHECK(esp_netif_get_ip_info(netif, &ip));
|
||||
|
||||
ESP_LOGI(TAG, "- IPv4 address: " IPSTR, IP2STR(&ip.ip));
|
||||
#ifdef CONFIG_EXAMPLE_CONNECT_IPV6
|
||||
esp_ip6_addr_t ip6[MAX_IP6_ADDRS_PER_NETIF];
|
||||
int ip6_addrs = esp_netif_get_all_ip6(netif, ip6);
|
||||
for (int j = 0; j < ip6_addrs; ++j) {
|
||||
esp_ip6_addr_type_t ipv6_type = esp_netif_ip6_get_addr_type(&(ip6[j]));
|
||||
ESP_LOGI(TAG, "- IPv6 address: " IPV6STR ", type: %s", IPV62STR(ip6[j]), s_ipv6_addr_types[ipv6_type]);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t example_disconnect(void)
|
||||
{
|
||||
if (s_semph_get_ip_addrs == NULL) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
vSemaphoreDelete(s_semph_get_ip_addrs);
|
||||
s_semph_get_ip_addrs = NULL;
|
||||
stop();
|
||||
ESP_ERROR_CHECK(esp_unregister_shutdown_handler(&stop));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_CONNECT_WIFI
|
||||
|
||||
static void on_wifi_disconnect(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
ESP_LOGI(TAG, "Wi-Fi disconnected, trying to reconnect...");
|
||||
esp_err_t err = esp_wifi_connect();
|
||||
if (err == ESP_ERR_WIFI_NOT_STARTED) {
|
||||
return;
|
||||
}
|
||||
ESP_ERROR_CHECK(err);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_CONNECT_IPV6
|
||||
|
||||
static void on_wifi_connect(void *esp_netif, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
esp_netif_create_ip6_linklocal(esp_netif);
|
||||
}
|
||||
|
||||
#endif // CONFIG_EXAMPLE_CONNECT_IPV6
|
||||
|
||||
static esp_netif_t *wifi_start(void)
|
||||
{
|
||||
char *desc;
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||
|
||||
esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_WIFI_STA();
|
||||
// Prefix the interface description with the module TAG
|
||||
// Warning: the interface desc is used in tests to capture actual connection details (IP, gw, mask)
|
||||
asprintf(&desc, "%s: %s", TAG, esp_netif_config.if_desc);
|
||||
esp_netif_config.if_desc = desc;
|
||||
esp_netif_config.route_prio = 128;
|
||||
esp_netif_t *netif = esp_netif_create_wifi(WIFI_IF_STA, &esp_netif_config);
|
||||
free(desc);
|
||||
esp_wifi_set_default_wifi_sta_handlers();
|
||||
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &on_wifi_disconnect, NULL));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &on_got_ip, NULL));
|
||||
#ifdef CONFIG_EXAMPLE_CONNECT_IPV6
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, &on_wifi_connect, netif));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_GOT_IP6, &on_got_ipv6, NULL));
|
||||
#endif
|
||||
|
||||
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
|
||||
wifi_config_t wifi_config = {
|
||||
.sta = {
|
||||
.ssid = CONFIG_EXAMPLE_WIFI_SSID,
|
||||
.password = CONFIG_EXAMPLE_WIFI_PASSWORD,
|
||||
.scan_method = EXAMPLE_WIFI_SCAN_METHOD,
|
||||
.sort_method = EXAMPLE_WIFI_CONNECT_AP_SORT_METHOD,
|
||||
.threshold.rssi = CONFIG_EXAMPLE_WIFI_SCAN_RSSI_THRESHOLD,
|
||||
.threshold.authmode = EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD,
|
||||
},
|
||||
};
|
||||
ESP_LOGI(TAG, "Connecting to %s...", wifi_config.sta.ssid);
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
|
||||
ESP_ERROR_CHECK(esp_wifi_start());
|
||||
esp_wifi_connect();
|
||||
return netif;
|
||||
}
|
||||
|
||||
static void wifi_stop(void)
|
||||
{
|
||||
esp_netif_t *wifi_netif = get_example_netif_from_desc("sta");
|
||||
ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &on_wifi_disconnect));
|
||||
ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &on_got_ip));
|
||||
#ifdef CONFIG_EXAMPLE_CONNECT_IPV6
|
||||
ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_GOT_IP6, &on_got_ipv6));
|
||||
ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_CONNECTED, &on_wifi_connect));
|
||||
#endif
|
||||
esp_err_t err = esp_wifi_stop();
|
||||
if (err == ESP_ERR_WIFI_NOT_INIT) {
|
||||
return;
|
||||
}
|
||||
ESP_ERROR_CHECK(err);
|
||||
ESP_ERROR_CHECK(esp_wifi_deinit());
|
||||
ESP_ERROR_CHECK(esp_wifi_clear_default_wifi_driver_and_handlers(wifi_netif));
|
||||
esp_netif_destroy(wifi_netif);
|
||||
s_example_esp_netif = NULL;
|
||||
}
|
||||
#endif // CONFIG_EXAMPLE_CONNECT_WIFI
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_CONNECT_ETHERNET
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_CONNECT_IPV6
|
||||
|
||||
/** Event handler for Ethernet events */
|
||||
static void on_eth_event(void *esp_netif, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
switch (event_id) {
|
||||
case ETHERNET_EVENT_CONNECTED:
|
||||
ESP_LOGI(TAG, "Ethernet Link Up");
|
||||
ESP_ERROR_CHECK(esp_netif_create_ip6_linklocal(esp_netif));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CONFIG_EXAMPLE_CONNECT_IPV6
|
||||
|
||||
static esp_eth_handle_t s_eth_handle = NULL;
|
||||
static esp_eth_mac_t *s_mac = NULL;
|
||||
static esp_eth_phy_t *s_phy = NULL;
|
||||
static esp_eth_netif_glue_handle_t s_eth_glue = NULL;
|
||||
|
||||
static esp_netif_t *eth_start(void)
|
||||
{
|
||||
char *desc;
|
||||
esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_ETH();
|
||||
// Prefix the interface description with the module TAG
|
||||
// Warning: the interface desc is used in tests to capture actual connection details (IP, gw, mask)
|
||||
asprintf(&desc, "%s: %s", TAG, esp_netif_config.if_desc);
|
||||
esp_netif_config.if_desc = desc;
|
||||
esp_netif_config.route_prio = 64;
|
||||
esp_netif_config_t netif_config = {
|
||||
.base = &esp_netif_config,
|
||||
.stack = ESP_NETIF_NETSTACK_DEFAULT_ETH
|
||||
};
|
||||
esp_netif_t *netif = esp_netif_new(&netif_config);
|
||||
assert(netif);
|
||||
free(desc);
|
||||
|
||||
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
|
||||
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
|
||||
phy_config.phy_addr = CONFIG_EXAMPLE_ETH_PHY_ADDR;
|
||||
phy_config.reset_gpio_num = CONFIG_EXAMPLE_ETH_PHY_RST_GPIO;
|
||||
#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
|
||||
esp32_emac_config.smi_mdc_gpio_num = CONFIG_EXAMPLE_ETH_MDC_GPIO;
|
||||
esp32_emac_config.smi_mdio_gpio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO;
|
||||
s_mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
|
||||
#if CONFIG_EXAMPLE_ETH_PHY_IP101
|
||||
s_phy = esp_eth_phy_new_ip101(&phy_config);
|
||||
#elif CONFIG_EXAMPLE_ETH_PHY_RTL8201
|
||||
s_phy = esp_eth_phy_new_rtl8201(&phy_config);
|
||||
#elif CONFIG_EXAMPLE_ETH_PHY_LAN87XX
|
||||
s_phy = esp_eth_phy_new_lan87xx(&phy_config);
|
||||
#elif CONFIG_EXAMPLE_ETH_PHY_DP83848
|
||||
s_phy = esp_eth_phy_new_dp83848(&phy_config);
|
||||
#elif CONFIG_EXAMPLE_ETH_PHY_KSZ80XX
|
||||
s_phy = esp_eth_phy_new_ksz80xx(&phy_config);
|
||||
#endif
|
||||
#elif CONFIG_EXAMPLE_USE_SPI_ETHERNET
|
||||
gpio_install_isr_service(0);
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
spi_device_handle_t spi_handle = NULL;
|
||||
#endif
|
||||
spi_bus_config_t buscfg = {
|
||||
.miso_io_num = CONFIG_EXAMPLE_ETH_SPI_MISO_GPIO,
|
||||
.mosi_io_num = CONFIG_EXAMPLE_ETH_SPI_MOSI_GPIO,
|
||||
.sclk_io_num = CONFIG_EXAMPLE_ETH_SPI_SCLK_GPIO,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, 1));
|
||||
#if CONFIG_EXAMPLE_USE_DM9051
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.command_bits = 1,
|
||||
.address_bits = 7,
|
||||
.mode = 0,
|
||||
.clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
|
||||
.spics_io_num = CONFIG_EXAMPLE_ETH_SPI_CS_GPIO,
|
||||
.queue_size = 20
|
||||
};
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
|
||||
/* dm9051 ethernet driver is based on spi driver */
|
||||
eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle);
|
||||
#else
|
||||
eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg);
|
||||
#endif // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
|
||||
dm9051_config.int_gpio_num = CONFIG_EXAMPLE_ETH_SPI_INT_GPIO;
|
||||
s_mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config);
|
||||
s_phy = esp_eth_phy_new_dm9051(&phy_config);
|
||||
#elif CONFIG_EXAMPLE_USE_W5500
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.command_bits = 16, // Actually it's the address phase in W5500 SPI frame
|
||||
.address_bits = 8, // Actually it's the control phase in W5500 SPI frame
|
||||
.mode = 0,
|
||||
.clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
|
||||
.spics_io_num = CONFIG_EXAMPLE_ETH_SPI_CS_GPIO,
|
||||
.queue_size = 20
|
||||
};
|
||||
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
|
||||
/* w5500 ethernet driver is based on spi driver */
|
||||
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_handle);
|
||||
#else
|
||||
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg);
|
||||
#endif // ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
w5500_config.int_gpio_num = CONFIG_EXAMPLE_ETH_SPI_INT_GPIO;
|
||||
s_mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
|
||||
s_phy = esp_eth_phy_new_w5500(&phy_config);
|
||||
#endif
|
||||
#elif CONFIG_EXAMPLE_USE_OPENETH
|
||||
phy_config.autonego_timeout_ms = 100;
|
||||
s_mac = esp_eth_mac_new_openeth(&mac_config);
|
||||
s_phy = esp_eth_phy_new_dp83848(&phy_config);
|
||||
#endif
|
||||
|
||||
// Install Ethernet driver
|
||||
esp_eth_config_t config = ETH_DEFAULT_CONFIG(s_mac, s_phy);
|
||||
ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle));
|
||||
#if !CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
/* The SPI Ethernet module might doesn't have a burned factory MAC address, we cat to set it manually.
|
||||
02:00:00 is a Locally Administered OUI range so should not be used except when testing on a LAN under your control.
|
||||
*/
|
||||
ESP_ERROR_CHECK(esp_eth_ioctl(s_eth_handle, ETH_CMD_S_MAC_ADDR, (uint8_t[]) {
|
||||
0x02, 0x00, 0x00, 0x12, 0x34, 0x56
|
||||
}));
|
||||
#endif
|
||||
// combine driver with netif
|
||||
s_eth_glue = esp_eth_new_netif_glue(s_eth_handle);
|
||||
esp_netif_attach(netif, s_eth_glue);
|
||||
|
||||
// Register user defined event handers
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &on_got_ip, NULL));
|
||||
#ifdef CONFIG_EXAMPLE_CONNECT_IPV6
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ETHERNET_EVENT_CONNECTED, &on_eth_event, netif));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_GOT_IP6, &on_got_ipv6, NULL));
|
||||
#endif
|
||||
|
||||
esp_eth_start(s_eth_handle);
|
||||
return netif;
|
||||
}
|
||||
|
||||
static void eth_stop(void)
|
||||
{
|
||||
esp_netif_t *eth_netif = get_example_netif_from_desc("eth");
|
||||
ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_ETH_GOT_IP, &on_got_ip));
|
||||
#ifdef CONFIG_EXAMPLE_CONNECT_IPV6
|
||||
ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_GOT_IP6, &on_got_ipv6));
|
||||
ESP_ERROR_CHECK(esp_event_handler_unregister(ETH_EVENT, ETHERNET_EVENT_CONNECTED, &on_eth_event));
|
||||
#endif
|
||||
ESP_ERROR_CHECK(esp_eth_stop(s_eth_handle));
|
||||
ESP_ERROR_CHECK(esp_eth_del_netif_glue(s_eth_glue));
|
||||
ESP_ERROR_CHECK(esp_eth_driver_uninstall(s_eth_handle));
|
||||
s_eth_handle = NULL;
|
||||
ESP_ERROR_CHECK(s_phy->del(s_phy));
|
||||
ESP_ERROR_CHECK(s_mac->del(s_mac));
|
||||
|
||||
esp_netif_destroy(eth_netif);
|
||||
s_example_esp_netif = NULL;
|
||||
}
|
||||
|
||||
esp_eth_handle_t get_example_eth_handle(void)
|
||||
{
|
||||
return s_eth_handle;
|
||||
}
|
||||
|
||||
#endif // CONFIG_EXAMPLE_CONNECT_ETHERNET
|
||||
|
||||
esp_netif_t *get_example_netif(void)
|
||||
{
|
||||
return s_example_esp_netif;
|
||||
}
|
||||
|
||||
esp_netif_t *get_example_netif_from_desc(const char *desc)
|
||||
{
|
||||
esp_netif_t *netif = NULL;
|
||||
char *expected_desc;
|
||||
asprintf(&expected_desc, "%s: %s", TAG, desc);
|
||||
while ((netif = esp_netif_next(netif)) != NULL) {
|
||||
if (strcmp(esp_netif_get_desc(netif), expected_desc) == 0) {
|
||||
free(expected_desc);
|
||||
return netif;
|
||||
}
|
||||
}
|
||||
free(expected_desc);
|
||||
return netif;
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
/* Common utilities for socket address input interface:
|
||||
The API get_addr_from_stdin() is mainly used by socket client examples which read IP address from stdin (if configured).
|
||||
This option is typically used in the CI, but could be enabled in the project configuration.
|
||||
In that case this component is used to receive a string that is evaluated and processed to output
|
||||
socket structures to open a connectio
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "lwip/sys.h"
|
||||
#include <lwip/netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
/**
|
||||
* @brief Read and evaluate IP address from stdin
|
||||
*
|
||||
* This API reads stdin and parses the input address using getaddrinfo()
|
||||
* to fill in struct sockaddr_storage (for both IPv4 and IPv6) used to open
|
||||
* a socket. IP protocol is guessed from the IP address string.
|
||||
*
|
||||
* @param[in] port port number of expected connection
|
||||
* @param[in] sock_type expected protocol: SOCK_STREAM or SOCK_DGRAM
|
||||
* @param[out] ip_protocol resultant IP protocol: IPPROTO_IP or IPPROTO_IP6
|
||||
* @param[out] addr_family resultant address family: AF_INET or AF_INET6
|
||||
* @param[out] dest_addr sockaddr_storage structure (for both IPv4 and IPv6)
|
||||
* @return ESP_OK on success, ESP_FAIL otherwise
|
||||
*/
|
||||
esp_err_t get_addr_from_stdin(int port, int sock_type,
|
||||
int *ip_protocol,
|
||||
int *addr_family,
|
||||
struct sockaddr_storage *dest_addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Common functions for protocol examples, to establish Wi-Fi or Ethernet connection.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_eth.h"
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_CONNECT_ETHERNET
|
||||
#define EXAMPLE_INTERFACE get_example_netif()
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_CONNECT_WIFI
|
||||
#define EXAMPLE_INTERFACE get_example_netif()
|
||||
#endif
|
||||
|
||||
#if !defined (CONFIG_EXAMPLE_CONNECT_ETHERNET) && !defined (CONFIG_EXAMPLE_CONNECT_WIFI)
|
||||
// This is useful for some tests which do not need a network connection
|
||||
#define EXAMPLE_INTERFACE NULL
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Configure Wi-Fi or Ethernet, connect, wait for IP
|
||||
*
|
||||
* This all-in-one helper function is used in protocols examples to
|
||||
* reduce the amount of boilerplate in the example.
|
||||
*
|
||||
* It is not intended to be used in real world applications.
|
||||
* See examples under examples/wifi/getting_started/ and examples/ethernet/
|
||||
* for more complete Wi-Fi or Ethernet initialization code.
|
||||
*
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*
|
||||
* @return ESP_OK on successful connection
|
||||
*/
|
||||
esp_err_t example_connect(void);
|
||||
|
||||
/**
|
||||
* Counterpart to example_connect, de-initializes Wi-Fi or Ethernet
|
||||
*/
|
||||
esp_err_t example_disconnect(void);
|
||||
|
||||
/**
|
||||
* @brief Configure stdin and stdout to use blocking I/O
|
||||
*
|
||||
* This helper function is used in ASIO examples. It wraps installing the
|
||||
* UART driver and configuring VFS layer to use UART driver for console I/O.
|
||||
*/
|
||||
esp_err_t example_configure_stdin_stdout(void);
|
||||
|
||||
/**
|
||||
* @brief Returns esp-netif pointer created by example_connect()
|
||||
*
|
||||
* @note If multiple interfaces active at once, this API return NULL
|
||||
* In that case the get_example_netif_from_desc() should be used
|
||||
* to get esp-netif pointer based on interface description
|
||||
*/
|
||||
esp_netif_t *get_example_netif(void);
|
||||
|
||||
/**
|
||||
* @brief Returns esp-netif pointer created by example_connect() described by
|
||||
* the supplied desc field
|
||||
*
|
||||
* @param desc Textual interface of created network interface, for example "sta"
|
||||
* indicate default WiFi station, "eth" default Ethernet interface.
|
||||
*
|
||||
*/
|
||||
esp_netif_t *get_example_netif_from_desc(const char *desc);
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_CONNECT_ETHERNET
|
||||
/**
|
||||
* @brief Get the example Ethernet driver handle
|
||||
*
|
||||
* @return esp_eth_handle_t
|
||||
*/
|
||||
esp_eth_handle_t get_example_eth_handle(void);
|
||||
#endif // CONFIG_EXAMPLE_CONNECT_ETHERNET
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
30
common_components/protocol_examples_common/stdin_out.c
Normal file
30
common_components/protocol_examples_common/stdin_out.c
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Common functions for protocol examples, to configure stdin and stdout.
|
||||
*/
|
||||
|
||||
#include "protocol_examples_common.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_vfs_dev.h"
|
||||
#include "driver/uart.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
esp_err_t example_configure_stdin_stdout(void)
|
||||
{
|
||||
// Initialize VFS & UART so we can use std::cout/cin
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
/* Install UART driver for interrupt-driven reads and writes */
|
||||
ESP_ERROR_CHECK( uart_driver_install( (uart_port_t)CONFIG_ESP_CONSOLE_UART_NUM,
|
||||
256, 0, 0, NULL, 0) );
|
||||
/* Tell VFS to use UART driver */
|
||||
esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);
|
||||
esp_vfs_dev_uart_port_set_rx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CR);
|
||||
/* Move the caret to the beginning of the next line on '\n' */
|
||||
esp_vfs_dev_uart_port_set_tx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CRLF);
|
||||
return ESP_OK;
|
||||
}
|
43
components/asio/CHANGELOG.md
Normal file
43
components/asio/CHANGELOG.md
Normal file
@ -0,0 +1,43 @@
|
||||
# Changelog
|
||||
|
||||
## [1.14.1~3](https://github.com/espressif/esp-protocols/commits/f148c98)
|
||||
|
||||
### Updated
|
||||
|
||||
- ASIO: Updated package version to "1.14.1~3" ([f148c98](https://github.com/espressif/esp-protocols/commit/f148c98))
|
||||
- ASIO: Example tests integration ([5193ebc](https://github.com/espressif/esp-protocols/commit/5193ebc))
|
||||
|
||||
|
||||
## [1.0.2](https://github.com/espressif/esp-protocols/commits/57afa38)
|
||||
|
||||
### Updated
|
||||
|
||||
- Bump asio/mdns/esp_websocket_client versions ([57afa38](https://github.com/espressif/esp-protocols/commit/57afa38))
|
||||
- ignore format warnings ([d66f9dc](https://github.com/espressif/esp-protocols/commit/d66f9dc))
|
||||
- asio: Fix exampels build ([3662c14](https://github.com/espressif/esp-protocols/commit/3662c14))
|
||||
|
||||
|
||||
## [1.0.1](https://github.com/espressif/esp-protocols/commits/055f051)
|
||||
|
||||
### Updated
|
||||
|
||||
- ASIO: Initial version based on IDF 5.0 with history ([055f051](https://github.com/espressif/esp-protocols/commit/055f051))
|
||||
- asio: Disable concepts support Fix example for compatibility with C++20 ([ac7bf46](https://github.com/espressif/esp-protocols/commit/ac7bf46), [IDF@9dba047](https://github.com/espressif/esp-idf/commit/9dba0476a01cd80d76e21706ad350009606b877e))
|
||||
- lwip: Update socket API to include port-version of sockets/netdb ([057a5d2](https://github.com/espressif/esp-protocols/commit/057a5d2), [IDF@53c009e](https://github.com/espressif/esp-idf/commit/53c009e62631bae569fa849c6b6c9e70a10b3afe))
|
||||
- esp_netif/lwip: Implement basic support for vanilla-lwip (2.1.3-REL) ([63bff63](https://github.com/espressif/esp-protocols/commit/63bff63), [IDF@5b471a1](https://github.com/espressif/esp-idf/commit/5b471a18489b056f65fe8dcbb2c992d27909ebc9))
|
||||
- mbedtls: Remove certs.c and certs.h from port directory ([e3c4391](https://github.com/espressif/esp-protocols/commit/e3c4391), [IDF@f31d8dd](https://github.com/espressif/esp-idf/commit/f31d8dd2955be0fe949340dcf3b043ec6daf4378))
|
||||
- mbedtls-3 update: 1) Fix build issue in mbedtls 2) skip the public headers check in IDF 3)Update Kconfig Macros 4)Remove deprecated config options 5) Update the sha API according to new nomenclature 6) Update mbedtls_rsa_init usage 7) Include mbedtls/build_info.h instead of mbedtls/config.h 8) Dont include check_config.h 9) Add additional error message in esp_blufi_api.h ([9813818](https://github.com/espressif/esp-protocols/commit/9813818), [IDF@4512253](https://github.com/espressif/esp-idf/commit/45122533e0bca5d538585e22308f14b74c33e474))
|
||||
- asio: Use internal ssl context and engine impl ([f605fdd](https://github.com/espressif/esp-protocols/commit/f605fdd), [IDF@d823106](https://github.com/espressif/esp-idf/commit/d823106aa6b24b8bdcc30373513c8688c61438c4))
|
||||
- Build & config: Remove leftover files from the unsupported "make" build system ([abbc8d9](https://github.com/espressif/esp-protocols/commit/abbc8d9), [IDF@766aa57](https://github.com/espressif/esp-idf/commit/766aa5708443099f3f033b739cda0e1de101cca6))
|
||||
- openssl: Add deprecation warning to ssl.h ([a029774](https://github.com/espressif/esp-protocols/commit/a029774), [IDF@cfc0018](https://github.com/espressif/esp-idf/commit/cfc001870c5e0afed7b42b6bf8c326eae053fe96))
|
||||
- asio coap: If LWIP IPV6 is disabled, automatically don't build asio & coap ([cc0f2b3](https://github.com/espressif/esp-protocols/commit/cc0f2b3), [IDF@e305f29](https://github.com/espressif/esp-idf/commit/e305f2938278c2a39e75c21a3ed59d8f4d4e62fa))
|
||||
- asio: update copyright notice ([47d57a5](https://github.com/espressif/esp-protocols/commit/47d57a5), [IDF@2d0895e](https://github.com/espressif/esp-idf/commit/2d0895e9a98bc7846d0ac7321f2b86b47346bf21))
|
||||
- Whitespace: Automated whitespace fixes (large commit) ([622a360](https://github.com/espressif/esp-protocols/commit/622a360), [IDF@66fb5a2](https://github.com/espressif/esp-idf/commit/66fb5a29bbdc2482d67c52e6f66b303378c9b789))
|
||||
- cmake: Apply cmakelint fixes ([4358c3c](https://github.com/espressif/esp-protocols/commit/4358c3c), [IDF@e82eac4](https://github.com/espressif/esp-idf/commit/e82eac4354b8b4111697656f3acce7450eeff366))
|
||||
- asio: option to use wolfSSL as TLS stack for ASIO ([c05558b](https://github.com/espressif/esp-protocols/commit/c05558b), [IDF@1c8171c](https://github.com/espressif/esp-idf/commit/1c8171c3e8d5a67e47dc8d6abac27ad2989470c3))
|
||||
- asio: Basic SSL/TLS support in asio port for ESP platform ([dab1230](https://github.com/espressif/esp-protocols/commit/dab1230), [IDF@9459c0d](https://github.com/espressif/esp-idf/commit/9459c0dd432fdd0fccb49ea65bb5c72d1849e1ba))
|
||||
- asio: updated ASIO port to use latest asio and esp-idf features ([9190917](https://github.com/espressif/esp-protocols/commit/9190917), [IDF@13d603e](https://github.com/espressif/esp-idf/commit/13d603e486624380d49f2e89614b10425c208d14))
|
||||
- components: use new component registration api ([9e83b1e](https://github.com/espressif/esp-protocols/commit/9e83b1e), [IDF@9eccd7c](https://github.com/espressif/esp-idf/commit/9eccd7c0826d6cc2e9de59304d1e5f76c0063ccf))
|
||||
- Rename Kconfig options (root) ([3b49d1f](https://github.com/espressif/esp-protocols/commit/3b49d1f), [IDF@c5000c8](https://github.com/espressif/esp-idf/commit/c5000c83d250896fffbddd7a3991384ea0fc286d))
|
||||
- cmake: make main a component again ([57672d5](https://github.com/espressif/esp-protocols/commit/57672d5), [IDF@d9939ce](https://github.com/espressif/esp-idf/commit/d9939cedd9b44d63dc148354c3a0a139b9c7113d))
|
||||
- asio: initial idf port of asio library without ssl ([5472d5c](https://github.com/espressif/esp-protocols/commit/5472d5c), [IDF@1ef13c5](https://github.com/espressif/esp-idf/commit/1ef13c524c484e9fb62e6c0b11482c30c5383728))
|
46
components/asio/CMakeLists.txt
Normal file
46
components/asio/CMakeLists.txt
Normal file
@ -0,0 +1,46 @@
|
||||
if(NOT CONFIG_LWIP_IPV6 AND NOT CMAKE_BUILD_EARLY_EXPANSION)
|
||||
# note: the component is still included in the build so it can become visible again in config
|
||||
# without needing to re-run CMake. However no source or header files are built.
|
||||
message(STATUS "IPV6 support is disabled so the asio component will not be built")
|
||||
idf_component_register()
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(asio_sources "asio/asio/src/asio.cpp")
|
||||
set(asio_requires lwip)
|
||||
|
||||
if(CONFIG_ASIO_SSL_SUPPORT)
|
||||
list(APPEND asio_sources
|
||||
"port/src/asio_ssl_impl.cpp"
|
||||
"port/mbedtls/src/mbedtls_context.cpp"
|
||||
"port/mbedtls/src/mbedtls_engine.cpp")
|
||||
set(asio_priv_includes "port/mbedtls/include")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${asio_sources}
|
||||
INCLUDE_DIRS "asio/asio/include" "port/include"
|
||||
PRIV_INCLUDE_DIRS ${asio_priv_includes}
|
||||
PRIV_REQUIRES ${asio_requires})
|
||||
|
||||
target_compile_definitions(${COMPONENT_LIB} PUBLIC SA_RESTART=0x01
|
||||
SA_NOCLDSTOP=0x2
|
||||
SA_NOCLDWAIT=0x4
|
||||
ASIO_DISABLE_SERIAL_PORT
|
||||
ASIO_SEPARATE_COMPILATION
|
||||
ASIO_STANDALONE
|
||||
ASIO_HAS_PTHREADS
|
||||
OPENSSL_NO_ENGINE
|
||||
)
|
||||
|
||||
if(NOT CONFIG_COMPILER_CXX_EXCEPTIONS)
|
||||
target_compile_definitions(${COMPONENT_LIB} PUBLIC ASIO_NO_EXCEPTIONS)
|
||||
endif()
|
||||
|
||||
if(NOT CONFIG_COMPILER_RTTI)
|
||||
target_compile_definitions(${COMPONENT_LIB} PUBLIC ASIO_NO_TYPEID)
|
||||
endif()
|
||||
|
||||
if(CONFIG_ASIO_SSL_SUPPORT)
|
||||
idf_component_get_property(mbedtls mbedtls COMPONENT_LIB)
|
||||
target_link_libraries(${COMPONENT_LIB} PUBLIC ${mbedtls})
|
||||
endif()
|
19
components/asio/Kconfig
Normal file
19
components/asio/Kconfig
Normal file
@ -0,0 +1,19 @@
|
||||
menu "ESP-ASIO"
|
||||
visible if LWIP_IPV6
|
||||
|
||||
config ASIO_SSL_SUPPORT
|
||||
bool "Enable SSL/TLS support of ASIO"
|
||||
default n
|
||||
help
|
||||
Enable support for basic SSL/TLS features, available for mbedTLS/OpenSSL
|
||||
|
||||
config ASIO_SSL_BIO_SIZE
|
||||
int "Size of BIO object"
|
||||
default 1024
|
||||
depends on ASIO_SSL_SUPPORT
|
||||
help
|
||||
Size in bytes of SSL-BIO implementation.
|
||||
Reducing the BIO size saves more RAM, but may slow down input output operations due to
|
||||
fragmentation.
|
||||
|
||||
endmenu
|
23
components/asio/LICENSE
Normal file
23
components/asio/LICENSE
Normal file
@ -0,0 +1,23 @@
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
13
components/asio/README.md
Normal file
13
components/asio/README.md
Normal file
@ -0,0 +1,13 @@
|
||||
# ASIO port
|
||||
|
||||
[](https://components.espressif.com/components/espressif/asio)
|
||||
|
||||
Asio is a cross-platform C++ library, see https://think-async.com/Asio/. It provides a consistent asynchronous model using a modern C++ approach.
|
||||
|
||||
## Examples
|
||||
|
||||
Get started with examples [examples](https://github.com/espressif/esp-protocols/tree/master/components/asio/examples)
|
||||
|
||||
## Documentation
|
||||
|
||||
* View the full [html documentation](https://docs.espressif.com/projects/esp-protocols/asio/docs/latest/index.html)
|
1
components/asio/asio
Submodule
1
components/asio/asio
Submodule
Submodule components/asio/asio added at 9cf116aa63
10
components/asio/examples/asio_chat/CMakeLists.txt
Normal file
10
components/asio/examples/asio_chat/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS ../.. ../../../../common_components/protocol_examples_common)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(asio_chat)
|
65
components/asio/examples/asio_chat/README.md
Normal file
65
components/asio/examples/asio_chat/README.md
Normal file
@ -0,0 +1,65 @@
|
||||
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 | ESP32-C3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- |
|
||||
|
||||
|
||||
# Asio chat client and server examples
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
The application aims to demonstrate a simple use of Asio library in different modes.
|
||||
In project settings it could be configured to run either a Asio chat server, a Asio chat client, or both.
|
||||
|
||||
## How to use example
|
||||
|
||||
The example is configured by default as an Asio chat client.
|
||||
|
||||
Note that the example uses string representation of IP addresses and ports.
|
||||
|
||||
You can find the upstream asio chat implementation [here] https://github.com/chriskohlhoff/asio/tree/master/asio/src/examples/cpp11/chat
|
||||
|
||||
### Asio Client
|
||||
|
||||
In the client mode, the example connects to the configured address, sends the message, which was inserted as an input in the terminal, and receives a response.
|
||||
|
||||
### Asio Server
|
||||
|
||||
In the server mode, Asio chat server with a specified port number is created and being polled till a connection request from the client arrives.
|
||||
Chat server echoes a message (received from any client) to all connected clients.
|
||||
|
||||
## Configure the project
|
||||
|
||||
```
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
Set following parameters under Example Configuration Options:
|
||||
|
||||
* Set `EXAMPLE_CHAT_SERVER` to use the example as an ASIO chat server
|
||||
* Configure `EXAMPLE_CHAT_SERVER_BIND_PORT` to the port number.
|
||||
|
||||
* Set `EXAMPLE_CHAT_CLIENT` to use the example as an ASIO chat client
|
||||
* Configure `EXAMPLE_CHAT_CLIENT_CONNECT_ADDRESS` to a string representation of the address to connect the client to.
|
||||
* Configure `EXAMPLE_CHAT_CLIENT_CONNECT_PORT` to the port number.
|
||||
|
||||
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more d etails.
|
||||
|
||||
## Running the example in server mode
|
||||
|
||||
- Configure the example according "Configure the project" section.
|
||||
- Run `idf.py -p PORT flash monitor` to build and upload the example to your board and connect to it's serial terminal.
|
||||
- Wait for the board to connect to WiFi or Ethernet (note the IP address).
|
||||
- Connect to the server using multiple clients, for example using any option below.
|
||||
- build and run asio chat client on your host machine
|
||||
- run chat_client asio example on ESP platform
|
||||
- since chat messages consists of ASCII size and message, it is possible to
|
||||
netcat `nc IP PORT` and type for example ` 4ABC<CR>` to transmit 'ABC\n'
|
||||
|
||||
## Running the example in client mode
|
||||
|
||||
- Configure the example according "Configure the project" section.
|
||||
- Start chat server either on host machine or as another ESP device running chat_server example.
|
||||
- Run `idf.py -p PORT flash monitor` to build and upload the example to your board and connect to it's serial terminal.
|
||||
- Wait for the board to connect to WiFi or Ethernet.
|
||||
- Receive and send messages to/from other clients on stdin/stdout via serial terminal.
|
||||
|
||||
See the README.md file in the upper level 'examples' directory for more information about examples.
|
2
components/asio/examples/asio_chat/main/CMakeLists.txt
Normal file
2
components/asio/examples/asio_chat/main/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "asio_chat.cpp"
|
||||
INCLUDE_DIRS ".")
|
39
components/asio/examples/asio_chat/main/Kconfig.projbuild
Normal file
39
components/asio/examples/asio_chat/main/Kconfig.projbuild
Normal file
@ -0,0 +1,39 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_CHAT_SERVER
|
||||
bool "Asio example chat server"
|
||||
default n
|
||||
help
|
||||
This example will setup a chat server, binds it to the specified address
|
||||
and starts listening.
|
||||
|
||||
if EXAMPLE_CHAT_SERVER
|
||||
config EXAMPLE_CHAT_SERVER_BIND_PORT
|
||||
string "Asio example server bind port"
|
||||
default "3344"
|
||||
help
|
||||
Server listener's socket would be bound to this port.
|
||||
endif
|
||||
|
||||
config EXAMPLE_CHAT_CLIENT
|
||||
bool "Asio example chat client"
|
||||
default y
|
||||
help
|
||||
This example will setup an asio chat client.
|
||||
and sends the data.
|
||||
|
||||
if EXAMPLE_CHAT_CLIENT
|
||||
config EXAMPLE_CHAT_CLIENT_CONNECT_ADDRESS
|
||||
string "Client connection address"
|
||||
default "192.168.0.1"
|
||||
help
|
||||
Client's socket would connect to this address/host.
|
||||
|
||||
config EXAMPLE_CHAT_CLIENT_CONNECT_PORT
|
||||
string "Client connection port"
|
||||
default "3344"
|
||||
help
|
||||
Client's connection port.
|
||||
endif
|
||||
|
||||
endmenu
|
120
components/asio/examples/asio_chat/main/asio_chat.cpp
Normal file
120
components/asio/examples/asio_chat/main/asio_chat.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
/* ASIO chat server client example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include "protocol_examples_common.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_event.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "server.hpp"
|
||||
#include "client.hpp"
|
||||
#include <thread>
|
||||
#include <pthread.h>
|
||||
|
||||
using asio::ip::tcp;
|
||||
|
||||
static const char *TAG = "asio-chat";
|
||||
|
||||
// This variable is necessary for `python test` execution, it provides synchronisation between server/client(as server should be started before client)
|
||||
std::mutex server_ready;
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_CHAT_CLIENT
|
||||
static void get_string(char *line, size_t size)
|
||||
{
|
||||
int count = 0;
|
||||
while (count < size) {
|
||||
int c = fgetc(stdin);
|
||||
if (c == '\n') {
|
||||
line[count] = '\0';
|
||||
break;
|
||||
} else if (c > 0 && c < 127) {
|
||||
line[count] = c;
|
||||
++count;
|
||||
}
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
void start_client(void)
|
||||
{
|
||||
const std::string port(CONFIG_EXAMPLE_CHAT_CLIENT_CONNECT_PORT);
|
||||
const std::string name(CONFIG_EXAMPLE_CHAT_CLIENT_CONNECT_ADDRESS);
|
||||
asio::io_context io_context;
|
||||
char line[128];
|
||||
|
||||
tcp::resolver resolver(io_context);
|
||||
auto endpoints = resolver.resolve(name, port);
|
||||
chat_client c(io_context, endpoints);
|
||||
#ifdef CONFIG_EXAMPLE_CHAT_SERVER
|
||||
std::lock_guard<std::mutex> guard(server_ready);
|
||||
#endif
|
||||
std::thread t([&io_context]() {
|
||||
try {
|
||||
io_context.run();
|
||||
} catch (const std::exception &e) {
|
||||
ESP_LOGE(TAG, "Exception occured during client thread execution %s", e.what());
|
||||
} catch (...) {
|
||||
ESP_LOGE(TAG, "Unknown exception");
|
||||
}
|
||||
});
|
||||
do {
|
||||
ESP_LOGI(TAG, "CLIENT: Waiting for input");
|
||||
get_string(line, sizeof(line));
|
||||
|
||||
chat_message msg;
|
||||
msg.body_length(std::strlen(line));
|
||||
std::memcpy(msg.body(), line, msg.body_length());
|
||||
msg.encode_header();
|
||||
c.write(msg);
|
||||
sleep(1);
|
||||
} while (strcmp(line, "exit") != 0);
|
||||
|
||||
c.close();
|
||||
t.join();
|
||||
}
|
||||
#endif // CONFIG_EXAMPLE_CHAT_CLIENT
|
||||
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
esp_netif_init();
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
try {
|
||||
#ifdef CONFIG_EXAMPLE_CHAT_SERVER
|
||||
asio::io_context io_context;
|
||||
chat_server server(io_context, tcp::endpoint(tcp::v4(), std::atoi(CONFIG_EXAMPLE_CHAT_SERVER_BIND_PORT)));
|
||||
std::thread t = std::thread([&io_context]() { // Chat server starting here
|
||||
try {
|
||||
io_context.run();
|
||||
} catch (const std::exception &e) {
|
||||
ESP_LOGE(TAG, "Exception occured during server thread execution %s", e.what());
|
||||
} catch (...) {
|
||||
ESP_LOGE(TAG, "Unknown exception");
|
||||
}
|
||||
});;
|
||||
#endif
|
||||
#ifdef CONFIG_EXAMPLE_CHAT_CLIENT
|
||||
start_client();
|
||||
#endif
|
||||
#ifdef CONFIG_EXAMPLE_CHAT_SERVER
|
||||
t.join();
|
||||
#endif
|
||||
} catch (const std::exception &e) {
|
||||
ESP_LOGE(TAG, "Exception occured during run %s", e.what());
|
||||
} catch (...) {
|
||||
ESP_LOGE(TAG, "Unknown exception");
|
||||
}
|
||||
ESP_ERROR_CHECK(example_disconnect());
|
||||
}
|
90
components/asio/examples/asio_chat/main/chat_message.hpp
Normal file
90
components/asio/examples/asio_chat/main/chat_message.hpp
Normal file
@ -0,0 +1,90 @@
|
||||
//
|
||||
// chat_message.hpp
|
||||
// ~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef CHAT_MESSAGE_HPP
|
||||
#define CHAT_MESSAGE_HPP
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
class chat_message {
|
||||
public:
|
||||
static constexpr std::size_t header_length = 4;
|
||||
static constexpr std::size_t max_body_length = 512;
|
||||
|
||||
chat_message()
|
||||
: body_length_(0)
|
||||
{
|
||||
}
|
||||
|
||||
const char *data() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
char *data()
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
std::size_t length() const
|
||||
{
|
||||
return header_length + body_length_;
|
||||
}
|
||||
|
||||
const char *body() const
|
||||
{
|
||||
return data_ + header_length;
|
||||
}
|
||||
|
||||
char *body()
|
||||
{
|
||||
return data_ + header_length;
|
||||
}
|
||||
|
||||
std::size_t body_length() const
|
||||
{
|
||||
return body_length_;
|
||||
}
|
||||
|
||||
void body_length(std::size_t new_length)
|
||||
{
|
||||
body_length_ = new_length;
|
||||
if (body_length_ > max_body_length) {
|
||||
body_length_ = max_body_length;
|
||||
}
|
||||
}
|
||||
|
||||
bool decode_header()
|
||||
{
|
||||
char header[header_length + 1] = "";
|
||||
std::strncat(header, data_, header_length);
|
||||
body_length_ = std::atoi(header);
|
||||
if (body_length_ > max_body_length) {
|
||||
body_length_ = 0;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void encode_header()
|
||||
{
|
||||
char header[header_length + 1] = "";
|
||||
std::sprintf(header, "%4d", static_cast<int>(body_length_));
|
||||
std::memcpy(data_, header, header_length);
|
||||
}
|
||||
|
||||
private:
|
||||
char data_[header_length + max_body_length];
|
||||
std::size_t body_length_;
|
||||
};
|
||||
|
||||
#endif // CHAT_MESSAGE_HPP
|
110
components/asio/examples/asio_chat/main/client.hpp
Normal file
110
components/asio/examples/asio_chat/main/client.hpp
Normal file
@ -0,0 +1,110 @@
|
||||
//
|
||||
// client.hpp
|
||||
// ~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef CHAT_CLIENT_HPP
|
||||
#define CHAT_CLIENT_HPP
|
||||
|
||||
#include <deque>
|
||||
#include "asio.hpp"
|
||||
#include "chat_message.hpp"
|
||||
|
||||
typedef std::deque<chat_message> chat_message_queue;
|
||||
|
||||
class chat_client {
|
||||
public:
|
||||
chat_client(asio::io_context &io_context,
|
||||
const asio::ip::tcp::resolver::results_type &endpoints)
|
||||
: io_context_(io_context),
|
||||
socket_(io_context)
|
||||
{
|
||||
do_connect(endpoints);
|
||||
}
|
||||
|
||||
void write(const chat_message &msg)
|
||||
{
|
||||
asio::post(io_context_,
|
||||
[this, msg]() {
|
||||
bool write_in_progress = !write_msgs_.empty();
|
||||
write_msgs_.push_back(msg);
|
||||
if (!write_in_progress) {
|
||||
do_write();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
asio::post(io_context_, [this]() {
|
||||
socket_.close();
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
void do_connect(const asio::ip::tcp::resolver::results_type &endpoints)
|
||||
{
|
||||
asio::async_connect(socket_, endpoints,
|
||||
[this](std::error_code ec, asio::ip::tcp::endpoint) {
|
||||
if (!ec) {
|
||||
do_read_header();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void do_read_header()
|
||||
{
|
||||
asio::async_read(socket_,
|
||||
asio::buffer(read_msg_.data(), chat_message::header_length),
|
||||
[this](std::error_code ec, std::size_t /*length*/) {
|
||||
if (!ec && read_msg_.decode_header()) {
|
||||
do_read_body();
|
||||
} else {
|
||||
socket_.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void do_read_body()
|
||||
{
|
||||
asio::async_read(socket_,
|
||||
asio::buffer(read_msg_.body(), read_msg_.body_length()),
|
||||
[this](std::error_code ec, std::size_t /*length*/) {
|
||||
if (!ec) {
|
||||
do_read_header();
|
||||
} else {
|
||||
socket_.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void do_write()
|
||||
{
|
||||
asio::async_write(socket_,
|
||||
asio::buffer(write_msgs_.front().data(),
|
||||
write_msgs_.front().length()),
|
||||
[this](std::error_code ec, std::size_t /*length*/) {
|
||||
if (!ec) {
|
||||
write_msgs_.pop_front();
|
||||
if (!write_msgs_.empty()) {
|
||||
do_write();
|
||||
}
|
||||
} else {
|
||||
socket_.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
asio::io_context &io_context_;
|
||||
asio::ip::tcp::socket socket_;
|
||||
chat_message read_msg_;
|
||||
chat_message_queue write_msgs_;
|
||||
};
|
||||
|
||||
#endif // CHAT_CLIENT_HPP
|
@ -0,0 +1,6 @@
|
||||
dependencies:
|
||||
## Required IDF version
|
||||
idf: ">=5.0"
|
||||
espressif/asio:
|
||||
version: "^1.14.1"
|
||||
override_path: '../../../'
|
185
components/asio/examples/asio_chat/main/server.hpp
Normal file
185
components/asio/examples/asio_chat/main/server.hpp
Normal file
@ -0,0 +1,185 @@
|
||||
//
|
||||
// server.hpp
|
||||
// ~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef CHAT_SERVER_HPP
|
||||
#define CHAT_SERVER_HPP
|
||||
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <deque>
|
||||
#include <utility>
|
||||
#include "asio.hpp"
|
||||
#include "chat_message.hpp"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
typedef std::deque<chat_message> chat_message_queue;
|
||||
|
||||
extern std::mutex server_ready;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
|
||||
class chat_participant {
|
||||
public:
|
||||
virtual ~chat_participant() {}
|
||||
virtual void deliver(const chat_message &msg) = 0;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<chat_participant> chat_participant_ptr;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
class chat_room {
|
||||
public:
|
||||
void join(chat_participant_ptr participant)
|
||||
{
|
||||
participants_.insert(participant);
|
||||
for (auto msg : recent_msgs_) {
|
||||
participant->deliver(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void leave(chat_participant_ptr participant)
|
||||
{
|
||||
participants_.erase(participant);
|
||||
}
|
||||
|
||||
void deliver(const chat_message &msg)
|
||||
{
|
||||
recent_msgs_.push_back(msg);
|
||||
while (recent_msgs_.size() > max_recent_msgs) {
|
||||
recent_msgs_.pop_front();
|
||||
}
|
||||
|
||||
for (auto participant : participants_) {
|
||||
participant->deliver(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::set<chat_participant_ptr> participants_;
|
||||
enum { max_recent_msgs = 100 };
|
||||
chat_message_queue recent_msgs_;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
|
||||
class chat_session
|
||||
: public chat_participant,
|
||||
public std::enable_shared_from_this<chat_session> {
|
||||
public:
|
||||
chat_session(asio::ip::tcp::socket socket, chat_room &room)
|
||||
: socket_(std::move(socket)),
|
||||
room_(room)
|
||||
{
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
room_.join(shared_from_this());
|
||||
do_read_header();
|
||||
}
|
||||
|
||||
void deliver(const chat_message &msg)
|
||||
{
|
||||
bool write_in_progress = !write_msgs_.empty();
|
||||
write_msgs_.push_back(msg);
|
||||
if (!write_in_progress) {
|
||||
do_write();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void do_read_header()
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
asio::async_read(socket_,
|
||||
asio::buffer(read_msg_.data(), chat_message::header_length),
|
||||
[this, self](std::error_code ec, std::size_t /*length*/) {
|
||||
if (!ec && read_msg_.decode_header()) {
|
||||
do_read_body();
|
||||
} else {
|
||||
room_.leave(shared_from_this());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void do_read_body()
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
asio::async_read(socket_,
|
||||
asio::buffer(read_msg_.body(), read_msg_.body_length()),
|
||||
[this, self](std::error_code ec, std::size_t /*length*/) {
|
||||
if (!ec) {
|
||||
ESP_LOGD("asio-chat:", "%s", read_msg_.body());
|
||||
room_.deliver(read_msg_);
|
||||
do_read_header();
|
||||
} else {
|
||||
room_.leave(shared_from_this());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void do_write()
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
asio::async_write(socket_,
|
||||
asio::buffer(write_msgs_.front().data(),
|
||||
write_msgs_.front().length()),
|
||||
[this, self](std::error_code ec, std::size_t /*length*/) {
|
||||
if (!ec) {
|
||||
write_msgs_.pop_front();
|
||||
if (!write_msgs_.empty()) {
|
||||
do_write();
|
||||
}
|
||||
} else {
|
||||
room_.leave(shared_from_this());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
asio::ip::tcp::socket socket_;
|
||||
chat_room &room_;
|
||||
chat_message read_msg_;
|
||||
chat_message_queue write_msgs_;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
class chat_server {
|
||||
public:
|
||||
chat_server(asio::io_context &io_context,
|
||||
const asio::ip::tcp::endpoint &endpoint)
|
||||
: acceptor_(io_context, endpoint)
|
||||
{
|
||||
do_accept();
|
||||
}
|
||||
|
||||
private:
|
||||
void do_accept()
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(server_ready);
|
||||
acceptor_.async_accept(
|
||||
[this](std::error_code ec, asio::ip::tcp::socket socket) {
|
||||
if (!ec) {
|
||||
std::make_shared<chat_session>(std::move(socket), room_)->start();
|
||||
}
|
||||
|
||||
do_accept();
|
||||
});
|
||||
}
|
||||
|
||||
asio::ip::tcp::acceptor acceptor_;
|
||||
chat_room room_;
|
||||
};
|
||||
|
||||
#endif // CHAT_SERVER_HPP
|
16
components/asio/examples/asio_chat/pytest_asio_chat_test.py
Normal file
16
components/asio/examples/asio_chat/pytest_asio_chat_test.py
Normal file
@ -0,0 +1,16 @@
|
||||
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import re
|
||||
|
||||
|
||||
def test_examples_asio_chat(dut):
|
||||
msg = 'asio-chat: received hi'
|
||||
# start the test and expect the client to receive back it's original data
|
||||
dut.expect(re.compile(b'Waiting for input'), timeout=30)
|
||||
dut.write(msg)
|
||||
dut.write('exit')
|
||||
msg = bytes(msg, encoding='utf8')
|
||||
dut.expect(re.compile(msg), timeout=30)
|
6
components/asio/examples/asio_chat/sdkconfig.ci
Normal file
6
components/asio/examples/asio_chat/sdkconfig.ci
Normal file
@ -0,0 +1,6 @@
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=n
|
||||
CONFIG_EXAMPLE_CHAT_CLIENT=y
|
||||
CONFIG_EXAMPLE_CHAT_SERVER=y
|
||||
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
|
||||
CONFIG_EXAMPLE_CHAT_CLIENT_CONNECT_ADDRESS="localhost"
|
8
components/asio/examples/asio_chat/sdkconfig.defaults
Normal file
8
components/asio/examples/asio_chat/sdkconfig.defaults
Normal file
@ -0,0 +1,8 @@
|
||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
|
||||
#
|
||||
# Partition Table
|
||||
#
|
||||
# Leave some room for larger apps without needing to reduce other features
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
10
components/asio/examples/async_request/CMakeLists.txt
Normal file
10
components/asio/examples/async_request/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS ../../ ../../../../common_components/protocol_examples_common)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(async_http_request)
|
52
components/asio/examples/async_request/README.md
Normal file
52
components/asio/examples/async_request/README.md
Normal file
@ -0,0 +1,52 @@
|
||||
| Supported Targets | ESP32 |
|
||||
| ----------------- | ----- |
|
||||
|
||||
# Async request using ASIO
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
The application aims to show how to compose async operations using ASIO to build network protocols and operations.
|
||||
|
||||
# Configure and Building example
|
||||
|
||||
This example doesn't require any configuration, just build it with
|
||||
|
||||
```
|
||||
idf.py build
|
||||
```
|
||||
|
||||
# Async operations composition and automatic lifetime control
|
||||
|
||||
On this example we compose the operation by starting the next step in the chain inside the completion handler of the
|
||||
previous operation. Also we pass the `Connection` class itself as the parameter of its final handler to be owned by
|
||||
the following operation. This is possible due to the control of lifetime by the usage of `std::shared_ptr`.
|
||||
|
||||
The control of lifetime of the class, done by `std::shared_ptr` usage, guarantee that the data will be available for
|
||||
async operations until it's not needed any more. This makes necessary that all of the async operation class must start
|
||||
its lifetime as a `std::shared_ptr` due to the usage of `std::enable_shared_from_this`.
|
||||
|
||||
|
||||
User creates a shared_ptr──┐
|
||||
of AddressResolution and │
|
||||
ask for resolve. │
|
||||
The handler for the ┌▼─────────────────────┐
|
||||
complete operation is sent│ AddressResolution │ In the completion of resolve a connection is created.
|
||||
└─────────────────┬────┘ AddressResolution is automaticly destroyed since it's
|
||||
│ no longer needed
|
||||
┌─▼────────────────────────────────────┐
|
||||
│ Connection │
|
||||
└──────┬───────────────────────────────┘
|
||||
Http::Session is created once we have a Connection. │
|
||||
Connection is passed to Http::Session that holds it │
|
||||
avoiding it's destruction. │
|
||||
┌─▼───────────────────────────────┐
|
||||
│ Http::Session │
|
||||
└────────┬────────────────────────┘
|
||||
After the HTTP request is │
|
||||
sent the completion handler │
|
||||
is called. │
|
||||
└────►Completion Handler()
|
||||
|
||||
|
||||
The previous diagram shows the process and the life span of each of the tasks in this examples. At each stage the
|
||||
object responsible for the last action inject itself to the completion handler of the next stage for reuse.
|
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "async_http_request.cpp"
|
||||
INCLUDE_DIRS ".")
|
@ -0,0 +1,369 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*
|
||||
* ASIO HTTP request example
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <asio.hpp>
|
||||
#include <memory>
|
||||
#include <system_error>
|
||||
#include <utility>
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_event.h"
|
||||
#include "protocol_examples_common.h"
|
||||
|
||||
constexpr auto TAG = "async_request";
|
||||
using asio::ip::tcp;
|
||||
|
||||
namespace {
|
||||
|
||||
void esp_init()
|
||||
{
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
esp_log_level_set("async_request", ESP_LOG_DEBUG);
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Simple class to add the resolver to a chain of actions
|
||||
*
|
||||
*/
|
||||
class AddressResolution : public std::enable_shared_from_this<AddressResolution> {
|
||||
public:
|
||||
explicit AddressResolution(asio::io_context &context) : ctx(context), resolver(ctx) {}
|
||||
|
||||
/**
|
||||
* @brief Initiator function for the address resolution
|
||||
*
|
||||
* @tparam CompletionToken callable responsible to use the results.
|
||||
*
|
||||
* @param host Host address
|
||||
* @param port Port for the target, must be number due to a limitation on lwip.
|
||||
*/
|
||||
template<class CompletionToken>
|
||||
void resolve(const std::string &host, const std::string &port, CompletionToken &&completion_handler)
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
resolver.async_resolve(host, port, [self, completion_handler](const asio::error_code & error, tcp::resolver::results_type results) {
|
||||
if (error) {
|
||||
ESP_LOGE(TAG, "Failed to resolve: %s", error.message().c_str());
|
||||
return;
|
||||
}
|
||||
completion_handler(self, results);
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
asio::io_context &ctx;
|
||||
tcp::resolver resolver;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Connection class
|
||||
*
|
||||
* The lowest level dependency on our asynchronous task, Connection provide an interface to TCP sockets.
|
||||
* A similar class could be provided for a TLS connection.
|
||||
*
|
||||
* @note: All read and write operations are written on an explicit strand, even though an implicit strand
|
||||
* occurs in this example since we run the io context in a single task.
|
||||
*
|
||||
*/
|
||||
class Connection : public std::enable_shared_from_this<Connection> {
|
||||
public:
|
||||
explicit Connection(asio::io_context &context) : ctx(context), strand(context), socket(ctx) {}
|
||||
|
||||
/**
|
||||
* @brief Start the connection
|
||||
*
|
||||
* Async operation to start a connection. As the final act of the process the Connection class pass a
|
||||
* std::shared_ptr of itself to the completion_handler.
|
||||
* Since it uses std::shared_ptr as an automatic control of its lifetime this class must be created
|
||||
* through a std::make_shared call.
|
||||
*
|
||||
* @tparam completion_handler A callable to act as the final handler for the process.
|
||||
* @param host host address
|
||||
* @param port port number - due to a limitation on lwip implementation this should be the number not the
|
||||
* service name typically seen in ASIO examples.
|
||||
*
|
||||
* @note The class could be modified to store the completion handler, as a member variable, instead of
|
||||
* pass it along asynchronous calls to allow the process to run again completely.
|
||||
*
|
||||
*/
|
||||
template<class CompletionToken>
|
||||
void start(tcp::resolver::results_type results, CompletionToken &&completion_handler)
|
||||
{
|
||||
connect(results, completion_handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start an async write on the socket
|
||||
*
|
||||
* @tparam data
|
||||
* @tparam completion_handler A callable to act as the final handler for the process.
|
||||
*
|
||||
*/
|
||||
template<class DataType, class CompletionToken>
|
||||
void write_async(const DataType &data, CompletionToken &&completion_handler)
|
||||
{
|
||||
asio::async_write(socket, data, asio::bind_executor(strand, completion_handler));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start an async read on the socket
|
||||
*
|
||||
* @tparam data
|
||||
* @tparam completion_handler A callable to act as the final handler for the process.
|
||||
*
|
||||
*/
|
||||
template<class DataBuffer, class CompletionToken>
|
||||
void read_async(DataBuffer &&in_data, CompletionToken &&completion_handler)
|
||||
{
|
||||
asio::async_read(socket, in_data, asio::bind_executor(strand, completion_handler));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template<class CompletionToken>
|
||||
void connect(tcp::resolver::results_type results, CompletionToken &&completion_handler)
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
asio::async_connect(socket, results, [self, completion_handler](const asio::error_code & error, [[maybe_unused]] const tcp::endpoint & endpoint) {
|
||||
if (error) {
|
||||
ESP_LOGE(TAG, "Failed to connect: %s", error.message().c_str());
|
||||
return;
|
||||
}
|
||||
completion_handler(self);
|
||||
});
|
||||
}
|
||||
asio::io_context &ctx;
|
||||
asio::io_context::strand strand;
|
||||
tcp::socket socket;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
namespace Http {
|
||||
enum class Method { GET };
|
||||
|
||||
/**
|
||||
* @brief Simple HTTP request class
|
||||
*
|
||||
* The user needs to write the request information direct to header and body fields.
|
||||
*
|
||||
* Only GET verb is provided.
|
||||
*
|
||||
*/
|
||||
class Request {
|
||||
public:
|
||||
Request(Method method, std::string host, std::string port, const std::string &target) : host_data(std::move(host)), port_data(std::move(port))
|
||||
{
|
||||
header_data.append("GET ");
|
||||
header_data.append(target);
|
||||
header_data.append(" HTTP/1.1");
|
||||
header_data.append("\r\n");
|
||||
header_data.append("Host: ");
|
||||
header_data.append(host_data);
|
||||
header_data.append("\r\n");
|
||||
header_data.append("\r\n");
|
||||
};
|
||||
|
||||
void set_header_field(std::string const &field)
|
||||
{
|
||||
header_data.append(field);
|
||||
}
|
||||
|
||||
void append_to_body(std::string const &data)
|
||||
{
|
||||
body_data.append(data);
|
||||
};
|
||||
|
||||
const std::string &host() const
|
||||
{
|
||||
return host_data;
|
||||
}
|
||||
|
||||
const std::string &service_port() const
|
||||
{
|
||||
return port_data;
|
||||
}
|
||||
|
||||
const std::string &header() const
|
||||
{
|
||||
return header_data;
|
||||
}
|
||||
|
||||
const std::string &body() const
|
||||
{
|
||||
return body_data;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string host_data;
|
||||
std::string port_data;
|
||||
std::string header_data;
|
||||
std::string body_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Simple HTTP response class
|
||||
*
|
||||
* The response is built from received data and only parsed to split header and body.
|
||||
*
|
||||
* A copy of the received data is kept.
|
||||
*
|
||||
*/
|
||||
struct Response {
|
||||
/**
|
||||
* @brief Construct a response from a contiguous buffer.
|
||||
*
|
||||
* Simple http parsing.
|
||||
*
|
||||
*/
|
||||
template<class DataIt>
|
||||
explicit Response(DataIt data, size_t size)
|
||||
{
|
||||
raw_response = std::string(data, size);
|
||||
|
||||
auto header_last = raw_response.find("\r\n\r\n");
|
||||
if (header_last != std::string::npos) {
|
||||
header = raw_response.substr(0, header_last);
|
||||
}
|
||||
body = raw_response.substr(header_last + 3);
|
||||
}
|
||||
/**
|
||||
* @brief Print response content.
|
||||
*/
|
||||
void print()
|
||||
{
|
||||
ESP_LOGI(TAG, "Header :\n %s", header.c_str());
|
||||
ESP_LOGI(TAG, "Body : \n %s", body.c_str());
|
||||
}
|
||||
|
||||
std::string raw_response;
|
||||
std::string header;
|
||||
std::string body;
|
||||
};
|
||||
|
||||
/** @brief HTTP Session
|
||||
*
|
||||
* Session class to handle HTTP protocol implementation.
|
||||
*
|
||||
*/
|
||||
class Session : public std::enable_shared_from_this<Session> {
|
||||
public:
|
||||
explicit Session(std::shared_ptr<Connection> connection_in) : connection(std::move(connection_in))
|
||||
{
|
||||
}
|
||||
|
||||
template<class CompletionToken>
|
||||
void send_request(const Request &request, CompletionToken &&completion_handler)
|
||||
{
|
||||
auto self = shared_from_this();
|
||||
send_data = { asio::buffer(request.header()), asio::buffer(request.body()) };
|
||||
connection->write_async(send_data, [self, &completion_handler](std::error_code error, std::size_t bytes_transfered) {
|
||||
if (error) {
|
||||
ESP_LOGE(TAG, "Request write error: %s", error.message().c_str());
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "Bytes Transfered: %d", bytes_transfered);
|
||||
self->get_response(completion_handler);
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
template<class CompletionToken>
|
||||
void get_response(CompletionToken &&completion_handler)
|
||||
{
|
||||
auto self = shared_from_this();
|
||||
connection->read_async(asio::buffer(receive_buffer), [self, &completion_handler](std::error_code error, std::size_t bytes_received) {
|
||||
if (error and error.value() != asio::error::eof) {
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "Bytes Received: %d", bytes_received);
|
||||
if (bytes_received == 0) {
|
||||
return;
|
||||
}
|
||||
Response response(std::begin(self->receive_buffer), bytes_received);
|
||||
|
||||
completion_handler(self, response);
|
||||
});
|
||||
}
|
||||
/*
|
||||
* For this example we assumed 2048 to be enough for the receive_buffer
|
||||
*/
|
||||
std::array<char, 2048> receive_buffer;
|
||||
/*
|
||||
* The hardcoded 2 below is related to the type we receive the data to send. We gather the parts from Request, header
|
||||
* and body, to send avoiding the copy.
|
||||
*/
|
||||
std::array<asio::const_buffer, 2> send_data;
|
||||
std::shared_ptr<Connection> connection;
|
||||
};
|
||||
|
||||
/** @brief Execute a fully async HTTP request
|
||||
*
|
||||
* @tparam completion_handler
|
||||
* @param ctx io context
|
||||
* @param request
|
||||
*
|
||||
* @note : We build this function as a simpler interface to compose the operations of connecting to
|
||||
* the address and running the HTTP session. The Http::Session class is injected to the completion handler
|
||||
* for further use.
|
||||
*/
|
||||
template<class CompletionToken>
|
||||
void request_async(asio::io_context &context, const Request &request, CompletionToken &&completion_handler)
|
||||
{
|
||||
/*
|
||||
* The first step is to resolve the address we want to connect to.
|
||||
* The AddressResolution itself is injected to the completion handler.
|
||||
*
|
||||
* This shared_ptr is destroyed by the end of the scope. Pay attention that this is a non blocking function
|
||||
* the lifetime of the object is extended by the resolve call
|
||||
*/
|
||||
std::make_shared<AddressResolution>(context)->resolve(request.host(), request.service_port(),
|
||||
[&context, &request, completion_handler](std::shared_ptr<AddressResolution> resolver, tcp::resolver::results_type results) {
|
||||
/* After resolution we create a Connection.
|
||||
* The completion handler gets a shared_ptr<Connection> to receive the connection, once the
|
||||
* connection process is complete.
|
||||
*/
|
||||
std::make_shared<Connection>(context)->start(results,
|
||||
[&request, completion_handler](std::shared_ptr<Connection> connection) {
|
||||
// Now we create a HTTP::Session and inject the necessary connection.
|
||||
std::make_shared<Session>(connection)->send_request(request, completion_handler);
|
||||
});
|
||||
});
|
||||
}
|
||||
}// namespace Http
|
||||
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
// Basic initialization of ESP system
|
||||
esp_init();
|
||||
|
||||
asio::io_context io_context;
|
||||
Http::Request request(Http::Method::GET, "www.httpbin.org", "80", "/get");
|
||||
Http::request_async(io_context, request, [](std::shared_ptr<Http::Session> session, Http::Response response) {
|
||||
/*
|
||||
* We only print the response here but could reuse session for other requests.
|
||||
*/
|
||||
response.print();
|
||||
});
|
||||
|
||||
// io_context.run will block until all the tasks on the context are done.
|
||||
io_context.run();
|
||||
ESP_LOGI(TAG, "Context run done");
|
||||
|
||||
ESP_ERROR_CHECK(example_disconnect());
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
dependencies:
|
||||
## Required IDF version
|
||||
idf: ">=5.0"
|
||||
espressif/asio:
|
||||
version: "^1.14.1"
|
||||
override_path: '../../../'
|
@ -0,0 +1,8 @@
|
||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
|
||||
#
|
||||
# Partition Table
|
||||
#
|
||||
# Leave some room for larger apps without needing to reduce other features
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
10
components/asio/examples/socks4/CMakeLists.txt
Normal file
10
components/asio/examples/socks4/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS ../.. ../../../../common_components/protocol_examples_common)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(asio_sock4)
|
72
components/asio/examples/socks4/README.md
Normal file
72
components/asio/examples/socks4/README.md
Normal file
@ -0,0 +1,72 @@
|
||||
| Supported Targets | ESP32 | ESP32-S2 |
|
||||
| ----------------- | ----- | ----- |
|
||||
|
||||
# Async request using ASIO
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
The application aims to show how to connect to a Socks4 proxy using async operations with ASIO. The SOCKS protocol is
|
||||
briefly described by the diagram below.
|
||||
|
||||
┌──────┐ ┌─────┐ ┌──────┐
|
||||
│Client│ │Proxy│ │Target│
|
||||
└──┬───┘ └──┬──┘ └──┬───┘
|
||||
│ │ │
|
||||
│ ╔═╧══════════════╗ │
|
||||
══════════════════════╪════════════════════════╣ Initialization ╠═══╪════════════════════════════════════════════
|
||||
│ ╚═╤══════════════╝ │
|
||||
│ │ │
|
||||
╔══════════════════╗│ │ │
|
||||
║We establish a ░║│ Socket Connection │ │
|
||||
║TCP connection ║│ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ > │
|
||||
║and get a socket ║│ │ │
|
||||
╚══════════════════╝│ │ │
|
||||
│ │ │
|
||||
│ ╔═╧══════════════╗ │
|
||||
══════════════════════╪════════════════════════╣ Socks Protocol ╠═══╪════════════════════════════════════════════
|
||||
│ ╚═╤══════════════╝ │
|
||||
│ │ │
|
||||
│ Client Connection Request│ │
|
||||
│ ─────────────────────────> │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ ╔════════════╪═══════╤══════════╪════════════════════════════════╗
|
||||
│ ║ TARGET CONNECTION │ │ ║
|
||||
│ ╟────────────────────┘ │ ╔═══════════════════╗ ║
|
||||
│ ║ │ Socket Connection│ ║Proxy establishes ░║ ║
|
||||
│ ║ │ <─ ─ ─ ─ ─ ─ ─ ─ > ║ TCPconnection ║ ║
|
||||
│ ║ │ │ ║ with target host ║ ║
|
||||
│ ╚════════════╪══════════════════╪══╚═══════════════════╝═════════╝
|
||||
│ │ │
|
||||
│ Response packet │ │
|
||||
│ <───────────────────────── │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ │ ╔═══════╗ │
|
||||
══════════════════════╪══════════════════════════╪══╣ Usage ╠═══════╪════════════════════════════════════════════
|
||||
│ │ ╚═══════╝ │
|
||||
│ │ │
|
||||
╔═════════════════╗│ │ │
|
||||
║Client uses the ░║│ │ │
|
||||
║ socket opened ║│ │ │
|
||||
║ with proxy ║│ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─>
|
||||
║to communicate ║│ │ │
|
||||
║ ║│ │ │
|
||||
╚═════════════════╝┴───┐ ┌──┴──┐ ┌──┴───┐
|
||||
│Client│ │Proxy│ │Target│
|
||||
└──────┘ └─────┘ └──────┘
|
||||
|
||||
|
||||
# Configure and Building example
|
||||
|
||||
This example requires the proxy address to be configured. You can do this using the menuconfig option.
|
||||
Proxy address and port must be configured in order for this example to work.
|
||||
|
||||
If using Linux ssh can be used as a proxy for testing.
|
||||
|
||||
```
|
||||
ssh -N -v -D 0.0.0.0:1080 localhost
|
||||
```
|
||||
# Async operations composition and automatic lifetime control
|
||||
|
||||
For documentation about the structure of this example look into [async\_request README](../async_request/README.md).
|
2
components/asio/examples/socks4/main/CMakeLists.txt
Normal file
2
components/asio/examples/socks4/main/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "socks4.cpp"
|
||||
INCLUDE_DIRS ".")
|
16
components/asio/examples/socks4/main/Kconfig.projbuild
Normal file
16
components/asio/examples/socks4/main/Kconfig.projbuild
Normal file
@ -0,0 +1,16 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_PROXY_ADDRESS
|
||||
string "Proxy address"
|
||||
default "myproxy"
|
||||
help
|
||||
Address of the proxy to be used.
|
||||
|
||||
config EXAMPLE_PROXY_SERVICE
|
||||
string "Proxy Service Type"
|
||||
default "myport"
|
||||
help
|
||||
Service type. Due to a limitation of lwip, must
|
||||
be the port number e.g. "1080".
|
||||
|
||||
endmenu
|
6
components/asio/examples/socks4/main/idf_component.yml
Normal file
6
components/asio/examples/socks4/main/idf_component.yml
Normal file
@ -0,0 +1,6 @@
|
||||
dependencies:
|
||||
## Required IDF version
|
||||
idf: ">=5.0"
|
||||
espressif/asio:
|
||||
version: "^1.14.1"
|
||||
override_path: '../../../'
|
393
components/asio/examples/socks4/main/socks4.cpp
Normal file
393
components/asio/examples/socks4/main/socks4.cpp
Normal file
@ -0,0 +1,393 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*
|
||||
*
|
||||
* ASIO Socks4 example
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <asio.hpp>
|
||||
#include <memory>
|
||||
#include <system_error>
|
||||
#include <utility>
|
||||
#include "esp_log.h"
|
||||
#include "socks4.hpp"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_event.h"
|
||||
#include "protocol_examples_common.h"
|
||||
|
||||
constexpr auto TAG = "asio_socks4";
|
||||
using asio::ip::tcp;
|
||||
|
||||
namespace {
|
||||
|
||||
void esp_init()
|
||||
{
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
esp_log_level_set("async_request", ESP_LOG_DEBUG);
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Simple class to add the resolver to a chain of actions
|
||||
*
|
||||
*/
|
||||
class AddressResolution : public std::enable_shared_from_this<AddressResolution> {
|
||||
public:
|
||||
explicit AddressResolution(asio::io_context &context) : ctx(context), resolver(ctx) {}
|
||||
|
||||
/**
|
||||
* @brief Initiator function for the address resolution
|
||||
*
|
||||
* @tparam CompletionToken callable responsible to use the results.
|
||||
*
|
||||
* @param host Host address
|
||||
* @param port Port for the target, must be number due to a limitation on lwip.
|
||||
*/
|
||||
template<class CompletionToken>
|
||||
void resolve(const std::string &host, const std::string &port, CompletionToken &&completion_handler)
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
resolver.async_resolve(host, port, [self, completion_handler](const asio::error_code & error, tcp::resolver::results_type results) {
|
||||
if (error) {
|
||||
ESP_LOGE(TAG, "Failed to resolve: %s", error.message().c_str());
|
||||
return;
|
||||
}
|
||||
completion_handler(self, results);
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
asio::io_context &ctx;
|
||||
tcp::resolver resolver;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Connection class
|
||||
*
|
||||
* The lowest level dependency on our asynchronous task, Connection provide an interface to TCP sockets.
|
||||
* A similar class could be provided for a TLS connection.
|
||||
*
|
||||
* @note: All read and write operations are written on an explicit strand, even though an implicit strand
|
||||
* occurs in this example since we run the io context in a single task.
|
||||
*
|
||||
*/
|
||||
class Connection : public std::enable_shared_from_this<Connection> {
|
||||
public:
|
||||
explicit Connection(asio::io_context &context) : ctx(context), strand(context), socket(ctx) {}
|
||||
|
||||
/**
|
||||
* @brief Start the connection
|
||||
*
|
||||
* Async operation to start a connection. As the final act of the process the Connection class pass a
|
||||
* std::shared_ptr of itself to the completion_handler.
|
||||
* Since it uses std::shared_ptr as an automatic control of its lifetime this class must be created
|
||||
* through a std::make_shared call.
|
||||
*
|
||||
* @tparam completion_handler A callable to act as the final handler for the process.
|
||||
* @param host host address
|
||||
* @param port port number - due to a limitation on lwip implementation this should be the number not the
|
||||
* service name typically seen in ASIO examples.
|
||||
*
|
||||
* @note The class could be modified to store the completion handler, as a member variable, instead of
|
||||
* pass it along asynchronous calls to allow the process to run again completely.
|
||||
*
|
||||
*/
|
||||
template<class CompletionToken>
|
||||
void start(tcp::resolver::results_type results, CompletionToken &&completion_handler)
|
||||
{
|
||||
connect(results, completion_handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start an async write on the socket
|
||||
*
|
||||
* @tparam data
|
||||
* @tparam completion_handler A callable to act as the final handler for the process.
|
||||
*
|
||||
*/
|
||||
template<class DataType, class CompletionToken>
|
||||
void write_async(const DataType &data, CompletionToken &&completion_handler)
|
||||
{
|
||||
asio::async_write(socket, data, asio::bind_executor(strand, completion_handler));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start an async read on the socket
|
||||
*
|
||||
* @tparam data
|
||||
* @tparam completion_handler A callable to act as the final handler for the process.
|
||||
*
|
||||
*/
|
||||
template<class DataBuffer, class CompletionToken>
|
||||
void read_async(DataBuffer &&in_data, CompletionToken &&completion_handler)
|
||||
{
|
||||
asio::async_read(socket, in_data, asio::bind_executor(strand, completion_handler));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template<class CompletionToken>
|
||||
void connect(tcp::resolver::results_type results, CompletionToken &&completion_handler)
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
asio::async_connect(socket, results, [self, completion_handler](const asio::error_code & error, [[maybe_unused]] const tcp::endpoint & endpoint) {
|
||||
if (error) {
|
||||
ESP_LOGE(TAG, "Failed to connect: %s", error.message().c_str());
|
||||
return;
|
||||
}
|
||||
completion_handler(self);
|
||||
});
|
||||
}
|
||||
asio::io_context &ctx;
|
||||
asio::io_context::strand strand;
|
||||
tcp::socket socket;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace Socks {
|
||||
|
||||
struct ConnectionData {
|
||||
ConnectionData(socks4::request::command_type cmd, const asio::ip::tcp::endpoint &endpoint,
|
||||
const std::string &user_id) : request(cmd, endpoint, user_id) {};
|
||||
socks4::request request;
|
||||
socks4::reply reply;
|
||||
};
|
||||
|
||||
template<class CompletionToken>
|
||||
void async_connect(asio::io_context &context, std::string proxy, std::string proxy_port, std::string host, std::string port, CompletionToken &&completion_handler)
|
||||
{
|
||||
/*
|
||||
* The first step is to resolve the address of the proxy we want to connect to.
|
||||
* The AddressResolution itself is injected to the completion handler.
|
||||
*/
|
||||
// Resolve proxy
|
||||
std::make_shared<AddressResolution>(context)->resolve(proxy, proxy_port,
|
||||
[&context, host, port, completion_handler](std::shared_ptr<AddressResolution> resolver, tcp::resolver::results_type proxy_resolution) {
|
||||
// We also need to resolve the target host address
|
||||
resolver->resolve(host, port, [&context, proxy_resolution, completion_handler](std::shared_ptr<AddressResolution> resolver, tcp::resolver::results_type host_resolution) {
|
||||
// Make connection with the proxy
|
||||
ESP_LOGI(TAG, "Startig Proxy Connection");
|
||||
std::make_shared<Connection>(context)->start(proxy_resolution,
|
||||
[resolver, host_resolution, completion_handler](std::shared_ptr<Connection> connection) {
|
||||
auto connect_data = std::make_shared<ConnectionData>(socks4::request::connect, *host_resolution, "");
|
||||
ESP_LOGI(TAG, "Sending Request to proxy for host connection.");
|
||||
connection->write_async(connect_data->request.buffers(), [connection, connect_data, completion_handler](std::error_code error, std::size_t bytes_received) {
|
||||
if (error) {
|
||||
ESP_LOGE(TAG, "Proxy request write error: %s", error.message().c_str());
|
||||
return;
|
||||
}
|
||||
connection->read_async(connect_data->reply.buffers(), [connection, connect_data, completion_handler](std::error_code error, std::size_t bytes_received) {
|
||||
if (error) {
|
||||
|
||||
ESP_LOGE(TAG, "Proxy response read error: %s", error.message().c_str());
|
||||
return;
|
||||
}
|
||||
if (!connect_data->reply.success()) {
|
||||
ESP_LOGE(TAG, "Proxy error: %#x", connect_data->reply.status());
|
||||
}
|
||||
completion_handler(connection);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
} // namespace Socks
|
||||
|
||||
namespace Http {
|
||||
enum class Method { GET };
|
||||
|
||||
/**
|
||||
* @brief Simple HTTP request class
|
||||
*
|
||||
* The user needs to write the request information direct to header and body fields.
|
||||
*
|
||||
* Only GET verb is provided.
|
||||
*
|
||||
*/
|
||||
class Request {
|
||||
public:
|
||||
Request(Method method, std::string host, std::string port, const std::string &target) : host_data(std::move(host)), port_data(std::move(port))
|
||||
{
|
||||
header_data.append("GET ");
|
||||
header_data.append(target);
|
||||
header_data.append(" HTTP/1.1");
|
||||
header_data.append("\r\n");
|
||||
header_data.append("Host: ");
|
||||
header_data.append(host_data);
|
||||
header_data.append("\r\n");
|
||||
header_data.append("\r\n");
|
||||
};
|
||||
|
||||
void set_header_field(std::string const &field)
|
||||
{
|
||||
header_data.append(field);
|
||||
}
|
||||
|
||||
void append_to_body(std::string const &data)
|
||||
{
|
||||
body_data.append(data);
|
||||
};
|
||||
|
||||
const std::string &host() const
|
||||
{
|
||||
return host_data;
|
||||
}
|
||||
|
||||
const std::string &service_port() const
|
||||
{
|
||||
return port_data;
|
||||
}
|
||||
|
||||
const std::string &header() const
|
||||
{
|
||||
return header_data;
|
||||
}
|
||||
|
||||
const std::string &body() const
|
||||
{
|
||||
return body_data;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string host_data;
|
||||
std::string port_data;
|
||||
std::string header_data;
|
||||
std::string body_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Simple HTTP response class
|
||||
*
|
||||
* The response is built from received data and only parsed to split header and body.
|
||||
*
|
||||
* A copy of the received data is kept.
|
||||
*
|
||||
*/
|
||||
struct Response {
|
||||
/**
|
||||
* @brief Construct a response from a contiguous buffer.
|
||||
*
|
||||
* Simple http parsing.
|
||||
*
|
||||
*/
|
||||
template<class DataIt>
|
||||
explicit Response(DataIt data, size_t size)
|
||||
{
|
||||
raw_response = std::string(data, size);
|
||||
|
||||
auto header_last = raw_response.find("\r\n\r\n");
|
||||
if (header_last != std::string::npos) {
|
||||
header = raw_response.substr(0, header_last);
|
||||
}
|
||||
body = raw_response.substr(header_last + 3);
|
||||
}
|
||||
/**
|
||||
* @brief Print response content.
|
||||
*/
|
||||
void print()
|
||||
{
|
||||
ESP_LOGI(TAG, "Header :\n %s", header.c_str());
|
||||
ESP_LOGI(TAG, "Body : \n %s", body.c_str());
|
||||
}
|
||||
|
||||
std::string raw_response;
|
||||
std::string header;
|
||||
std::string body;
|
||||
};
|
||||
|
||||
/** @brief HTTP Session
|
||||
*
|
||||
* Session class to handle HTTP protocol implementation.
|
||||
*
|
||||
*/
|
||||
class Session : public std::enable_shared_from_this<Session> {
|
||||
public:
|
||||
explicit Session(std::shared_ptr<Connection> connection_in) : connection(std::move(connection_in))
|
||||
{
|
||||
}
|
||||
|
||||
template<class CompletionToken>
|
||||
void send_request(const Request &request, CompletionToken &&completion_handler)
|
||||
{
|
||||
auto self = shared_from_this();
|
||||
send_data = { asio::buffer(request.header()), asio::buffer(request.body()) };
|
||||
connection->write_async(send_data, [self, &completion_handler](std::error_code error, std::size_t bytes_transfered) {
|
||||
if (error) {
|
||||
ESP_LOGE(TAG, "Request write error: %s", error.message().c_str());
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "Bytes Transfered: %d", bytes_transfered);
|
||||
self->get_response(completion_handler);
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
template<class CompletionToken>
|
||||
void get_response(CompletionToken &&completion_handler)
|
||||
{
|
||||
auto self = shared_from_this();
|
||||
connection->read_async(asio::buffer(receive_buffer), [self, &completion_handler](std::error_code error, std::size_t bytes_received) {
|
||||
if (error and error.value() != asio::error::eof) {
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "Bytes Received: %d", bytes_received);
|
||||
if (bytes_received == 0) {
|
||||
return;
|
||||
}
|
||||
Response response(std::begin(self->receive_buffer), bytes_received);
|
||||
|
||||
completion_handler(self, response);
|
||||
});
|
||||
}
|
||||
/*
|
||||
* For this example we assumed 2048 to be enough for the receive_buffer
|
||||
*/
|
||||
std::array<char, 2048> receive_buffer;
|
||||
/*
|
||||
* The hardcoded 2 below is related to the type we receive the data to send. We gather the parts from Request, header
|
||||
* and body, to send avoiding the copy.
|
||||
*/
|
||||
std::array<asio::const_buffer, 2> send_data;
|
||||
std::shared_ptr<Connection> connection;
|
||||
};
|
||||
}// namespace Http
|
||||
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
// Basic initialization of ESP system
|
||||
esp_init();
|
||||
|
||||
asio::io_context io_context;
|
||||
Http::Request request(Http::Method::GET, "www.httpbin.org", "80", "/get");
|
||||
Socks::async_connect(io_context, CONFIG_EXAMPLE_PROXY_ADDRESS, CONFIG_EXAMPLE_PROXY_SERVICE, request.host(), request.service_port(),
|
||||
[&request](std::shared_ptr<Connection> connection) {
|
||||
// Now we create a HTTP::Session and inject the necessary connection.
|
||||
std::make_shared<Http::Session>(connection)->send_request(request, [](std::shared_ptr<Http::Session> session, Http::Response response) {
|
||||
response.print();
|
||||
});
|
||||
});
|
||||
// io_context.run will block until all the tasks on the context are done.
|
||||
io_context.run();
|
||||
ESP_LOGI(TAG, "Context run done");
|
||||
|
||||
ESP_ERROR_CHECK(example_disconnect());
|
||||
}
|
136
components/asio/examples/socks4/main/socks4.hpp
Normal file
136
components/asio/examples/socks4/main/socks4.hpp
Normal file
@ -0,0 +1,136 @@
|
||||
//
|
||||
// socks4.hpp
|
||||
// ~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef SOCKS4_HPP
|
||||
#define SOCKS4_HPP
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <asio/buffer.hpp>
|
||||
#include <asio/ip/tcp.hpp>
|
||||
|
||||
namespace socks4 {
|
||||
|
||||
const unsigned char version = 0x04;
|
||||
|
||||
class request {
|
||||
public:
|
||||
enum command_type {
|
||||
connect = 0x01,
|
||||
bind = 0x02
|
||||
};
|
||||
|
||||
request(command_type cmd, const asio::ip::tcp::endpoint &endpoint,
|
||||
const std::string &user_id)
|
||||
: version_(version),
|
||||
command_(cmd),
|
||||
user_id_(user_id),
|
||||
null_byte_(0)
|
||||
{
|
||||
// Only IPv4 is supported by the SOCKS 4 protocol.
|
||||
if (endpoint.protocol() != asio::ip::tcp::v4()) {
|
||||
throw asio::system_error(
|
||||
asio::error::address_family_not_supported);
|
||||
}
|
||||
|
||||
// Convert port number to network byte order.
|
||||
unsigned short port = endpoint.port();
|
||||
port_high_byte_ = (port >> 8) & 0xff;
|
||||
port_low_byte_ = port & 0xff;
|
||||
|
||||
// Save IP address in network byte order.
|
||||
address_ = endpoint.address().to_v4().to_bytes();
|
||||
}
|
||||
|
||||
std::array<asio::const_buffer, 7> buffers() const
|
||||
{
|
||||
return {
|
||||
{
|
||||
asio::buffer(&version_, 1),
|
||||
asio::buffer(&command_, 1),
|
||||
asio::buffer(&port_high_byte_, 1),
|
||||
asio::buffer(&port_low_byte_, 1),
|
||||
asio::buffer(address_),
|
||||
asio::buffer(user_id_),
|
||||
asio::buffer(&null_byte_, 1)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned char version_;
|
||||
unsigned char command_;
|
||||
unsigned char port_high_byte_;
|
||||
unsigned char port_low_byte_;
|
||||
asio::ip::address_v4::bytes_type address_;
|
||||
std::string user_id_;
|
||||
unsigned char null_byte_;
|
||||
};
|
||||
|
||||
class reply {
|
||||
public:
|
||||
enum status_type {
|
||||
request_granted = 0x5a,
|
||||
request_failed = 0x5b,
|
||||
request_failed_no_identd = 0x5c,
|
||||
request_failed_bad_user_id = 0x5d
|
||||
};
|
||||
|
||||
reply()
|
||||
: null_byte_(0),
|
||||
status_()
|
||||
{
|
||||
}
|
||||
|
||||
std::array<asio::mutable_buffer, 5> buffers()
|
||||
{
|
||||
return {
|
||||
{
|
||||
asio::buffer(&null_byte_, 1),
|
||||
asio::buffer(&status_, 1),
|
||||
asio::buffer(&port_high_byte_, 1),
|
||||
asio::buffer(&port_low_byte_, 1),
|
||||
asio::buffer(address_)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bool success() const
|
||||
{
|
||||
return null_byte_ == 0 && status_ == request_granted;
|
||||
}
|
||||
|
||||
unsigned char status() const
|
||||
{
|
||||
return status_;
|
||||
}
|
||||
|
||||
asio::ip::tcp::endpoint endpoint() const
|
||||
{
|
||||
unsigned short port = port_high_byte_;
|
||||
port = (port << 8) & 0xff00;
|
||||
port = port | port_low_byte_;
|
||||
|
||||
asio::ip::address_v4 address(address_);
|
||||
|
||||
return asio::ip::tcp::endpoint(address, port);
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned char null_byte_;
|
||||
unsigned char status_;
|
||||
unsigned char port_high_byte_;
|
||||
unsigned char port_low_byte_;
|
||||
asio::ip::address_v4::bytes_type address_;
|
||||
};
|
||||
|
||||
} // namespace socks4
|
||||
|
||||
#endif // SOCKS4_HPP
|
3
components/asio/examples/socks4/sdkconfig.defaults
Normal file
3
components/asio/examples/socks4/sdkconfig.defaults
Normal file
@ -0,0 +1,3 @@
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
CONFIG_COMPILER_CXX_RTTI=y
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=0
|
11
components/asio/examples/ssl_client_server/CMakeLists.txt
Normal file
11
components/asio/examples/ssl_client_server/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS ../.. ../../../../common_components/protocol_examples_common)
|
||||
set(EXCLUDE_COMPONENTS openssl)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(asio_ssl_client_server)
|
88
components/asio/examples/ssl_client_server/README.md
Normal file
88
components/asio/examples/ssl_client_server/README.md
Normal file
@ -0,0 +1,88 @@
|
||||
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 | ESP32-C3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- |
|
||||
|
||||
# Asio SSL client/server example
|
||||
|
||||
Simple Asio client and server with SSL/TLS transport
|
||||
|
||||
## How to Use Example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example can be executed on any ESP platform board. No external connection is required, it is recommended though
|
||||
to connect to internet or a local network via WiFi or Ethernet to easily exercise features of this example.
|
||||
|
||||
### Configure the project
|
||||
|
||||
* Open the project configuration menu (`idf.py menuconfig`)
|
||||
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
|
||||
* Enable the ASIO client and set server's host name to examine client's functionality.
|
||||
The ASIO client connects to the configured server and sends default payload string "GET / HTTP/1.1"
|
||||
* Enable the ASIO server to examine server's functionality. The ASIO server listens to connection and echos back what was received.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
### Client connecting to public server
|
||||
|
||||
The below output illustrates the client connecting to a public https server.
|
||||
|
||||
```
|
||||
I (1267) example_connect: Waiting for IP(s)
|
||||
I (2587) wifi:new:<11,0>, old:<1,0>, ap:<255,255>, sta:<11,0>, prof:1
|
||||
I (3367) wifi:state: init -> auth (b0)
|
||||
I (3377) wifi:state: auth -> assoc (0)
|
||||
I (3387) wifi:state: assoc -> run (10)
|
||||
I (3397) wifi:security type: 3, phy: bgn, rssi: -49
|
||||
I (3397) wifi:pm start, type: 1
|
||||
I (3457) wifi:AP's beacon interval = 102400 us, DTIM period = 1
|
||||
I (4747) example_connect: Got IPv6 event: Interface "example_connect: sta" address: fe80:0000:0000:0000:260a:xxxx:xxxx:xxxx, type: ESP_IP6_ADDR_IS_LINK_LOCAL
|
||||
I (5247) esp_netif_handlers: example_connect: sta ip: 192.168.32.69, mask: 255.255.252.0, gw: 192.168.32.3
|
||||
I (5247) example_connect: Got IPv4 event: Interface "example_connect: sta" address: 192.168.32.69
|
||||
I (5257) example_connect: Connected to example_connect: sta
|
||||
I (5257) example_connect: - IPv4 address: 192.168.32.69
|
||||
I (5267) example_connect: - IPv6 address: fe80:0000:0000:0000:260a:xxxx:xxxx:xxxx, type: ESP_IP6_ADDR_IS_LINK_LOCAL
|
||||
W (5277) esp32_asio_pthread: pthread_condattr_setclock: not yet supported!
|
||||
W (5297) esp32_asio_pthread: pthread_condattr_setclock: not yet supported!
|
||||
Reply: HTTP/1.1 200 OK
|
||||
D
|
||||
```
|
||||
### Both server and client enabled
|
||||
|
||||
The below output demonstrates the client connecting to the ASIO server via loopback interface, so no WiFi, nor Ethernet connection
|
||||
was established.
|
||||
```
|
||||
I (0) cpu_start: App cpu up.
|
||||
I (495) heap_init: Initializing. RAM available for dynamic allocation:
|
||||
I (502) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
|
||||
I (508) heap_init: At 3FFB5400 len 0002AC00 (171 KiB): DRAM
|
||||
I (515) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
|
||||
I (521) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
|
||||
I (527) heap_init: At 4008BB80 len 00014480 (81 KiB): IRAM
|
||||
I (534) cpu_start: Pro cpu start user code
|
||||
I (556) spi_flash: detected chip: gd
|
||||
I (556) spi_flash: flash io: dio
|
||||
W (556) spi_flash: Detected size(4096k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
|
||||
I (566) cpu_start: Starting scheduler on PRO CPU.
|
||||
I (0) cpu_start: Starting scheduler on APP CPU.
|
||||
I (600) example_connect: Waiting for IP(s)
|
||||
W (600) esp32_asio_pthread: pthread_condattr_setclock: not yet supported!
|
||||
W (1610) esp32_asio_pthread: pthread_condattr_setclock: not yet supported!
|
||||
W (1610) esp32_asio_pthread: pthread_condattr_setclock: not yet supported!
|
||||
Server received: GET / HTTP/1.1
|
||||
|
||||
|
||||
Reply: GET / HTTP/1.1
|
||||
```
|
||||
See the README.md file in the upper level 'examples' directory for more information about examples.
|
@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "asio_ssl_main.cpp"
|
||||
INCLUDE_DIRS "."
|
||||
EMBED_TXTFILES ca.crt server.key srv.crt)
|
@ -0,0 +1,36 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_CLIENT
|
||||
bool "Enable TLS client"
|
||||
default y
|
||||
help
|
||||
Choose this option to use ASIO TLS/SSL client functionality
|
||||
|
||||
config EXAMPLE_PORT
|
||||
string "ASIO port number"
|
||||
default "443"
|
||||
help
|
||||
Port number used by ASIO example.
|
||||
|
||||
config EXAMPLE_SERVER
|
||||
bool "Enable TLS server"
|
||||
default n
|
||||
help
|
||||
Choose this option to use ASIO TLS/SSL server functionality
|
||||
|
||||
config EXAMPLE_SERVER_NAME
|
||||
string "ASIO server name or IP"
|
||||
default "www.google.com"
|
||||
depends on EXAMPLE_CLIENT
|
||||
help
|
||||
Asio example server ip for the ASIO client to connect to.
|
||||
|
||||
config EXAMPLE_CLIENT_VERIFY_PEER
|
||||
bool "Client to verify peer"
|
||||
default n
|
||||
depends on EXAMPLE_CLIENT
|
||||
help
|
||||
This option sets client's mode to verify peer, default is
|
||||
verify-none
|
||||
|
||||
endmenu
|
@ -0,0 +1,272 @@
|
||||
//
|
||||
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include <string>
|
||||
#include "protocol_examples_common.h"
|
||||
#include "esp_event.h"
|
||||
#include "nvs_flash.h"
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include "asio.hpp"
|
||||
#include "asio/ssl.hpp"
|
||||
#include "asio/buffer.hpp"
|
||||
#include "esp_pthread.h"
|
||||
|
||||
extern const unsigned char server_pem_start[] asm("_binary_srv_crt_start");
|
||||
extern const unsigned char server_pem_end[] asm("_binary_srv_crt_end");
|
||||
|
||||
extern const unsigned char cacert_pem_start[] asm("_binary_ca_crt_start");
|
||||
extern const unsigned char cacert_pem_end[] asm("_binary_ca_crt_end");
|
||||
|
||||
extern const unsigned char prvtkey_pem_start[] asm("_binary_server_key_start");
|
||||
extern const unsigned char prvtkey_pem_end[] asm("_binary_server_key_end");
|
||||
|
||||
static const asio::const_buffer cert_chain(cacert_pem_start, cacert_pem_end - cacert_pem_start);
|
||||
static const asio::const_buffer privkey(prvtkey_pem_start, prvtkey_pem_end - prvtkey_pem_start);
|
||||
static const asio::const_buffer server_cert(server_pem_start, server_pem_end - server_pem_start);
|
||||
|
||||
using asio::ip::tcp;
|
||||
|
||||
static const std::size_t max_length = 1024;
|
||||
|
||||
class Client {
|
||||
public:
|
||||
Client(asio::io_context &io_context,
|
||||
asio::ssl::context &context,
|
||||
const tcp::resolver::results_type &endpoints)
|
||||
: socket_(io_context, context)
|
||||
{
|
||||
|
||||
#if CONFIG_EXAMPLE_CLIENT_VERIFY_PEER
|
||||
socket_.set_verify_mode(asio::ssl::verify_peer);
|
||||
#else
|
||||
socket_.set_verify_mode(asio::ssl::verify_none);
|
||||
#endif // CONFIG_EXAMPLE_CLIENT_VERIFY_PEER
|
||||
|
||||
connect(endpoints);
|
||||
}
|
||||
|
||||
private:
|
||||
void connect(const tcp::resolver::results_type &endpoints)
|
||||
{
|
||||
asio::async_connect(socket_.lowest_layer(), endpoints,
|
||||
[this](const std::error_code & error,
|
||||
const tcp::endpoint & /*endpoint*/) {
|
||||
if (!error) {
|
||||
handshake();
|
||||
} else {
|
||||
std::cout << "Connect failed: " << error.message() << "\n";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void handshake()
|
||||
{
|
||||
socket_.async_handshake(asio::ssl::stream_base::client,
|
||||
[this](const std::error_code & error) {
|
||||
if (!error) {
|
||||
send_request();
|
||||
} else {
|
||||
std::cout << "Handshake failed: " << error.message() << "\n";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void send_request()
|
||||
{
|
||||
size_t request_length = std::strlen(request_);
|
||||
|
||||
asio::async_write(socket_,
|
||||
asio::buffer(request_, request_length),
|
||||
[this](const std::error_code & error, std::size_t length) {
|
||||
if (!error) {
|
||||
receive_response(length);
|
||||
} else {
|
||||
std::cout << "Write failed: " << error.message() << "\n";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void receive_response(std::size_t length)
|
||||
{
|
||||
asio::async_read(socket_,
|
||||
asio::buffer(reply_, length),
|
||||
[this](const std::error_code & error, std::size_t length) {
|
||||
if (!error) {
|
||||
std::cout << "Reply: ";
|
||||
std::cout.write(reply_, length);
|
||||
std::cout << "\n";
|
||||
} else {
|
||||
std::cout << "Read failed: " << error.message() << "\n";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
asio::ssl::stream<tcp::socket> socket_;
|
||||
char request_[max_length] = "GET / HTTP/1.1\r\n\r\n";
|
||||
char reply_[max_length];
|
||||
};
|
||||
|
||||
class Session : public std::enable_shared_from_this<Session> {
|
||||
public:
|
||||
Session(tcp::socket socket, asio::ssl::context &context)
|
||||
: socket_(std::move(socket), context)
|
||||
{
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
do_handshake();
|
||||
}
|
||||
|
||||
private:
|
||||
void do_handshake()
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
socket_.async_handshake(asio::ssl::stream_base::server,
|
||||
[this, self](const std::error_code & error) {
|
||||
if (!error) {
|
||||
do_read();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void do_read()
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
socket_.async_read_some(asio::buffer(data_),
|
||||
[this, self](const std::error_code & ec, std::size_t length) {
|
||||
if (!ec) {
|
||||
std::cout << "Server received: ";
|
||||
std::cout.write(data_, length);
|
||||
std::cout << std::endl;
|
||||
do_write(length);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void do_write(std::size_t length)
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
asio::async_write(socket_, asio::buffer(data_, length),
|
||||
[this, self](const std::error_code & ec,
|
||||
std::size_t /*length*/) {
|
||||
if (!ec) {
|
||||
do_read();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
asio::ssl::stream<tcp::socket> socket_;
|
||||
char data_[max_length];
|
||||
};
|
||||
|
||||
class Server {
|
||||
public:
|
||||
Server(asio::io_context &io_context, unsigned short port)
|
||||
: acceptor_(io_context, tcp::endpoint(tcp::v4(), port)),
|
||||
context_(asio::ssl::context::tls_server)
|
||||
{
|
||||
context_.set_options(
|
||||
asio::ssl::context::default_workarounds
|
||||
| asio::ssl::context::no_sslv2);
|
||||
context_.use_certificate_chain(server_cert);
|
||||
context_.use_private_key(privkey, asio::ssl::context::pem);
|
||||
|
||||
do_accept();
|
||||
}
|
||||
|
||||
private:
|
||||
void do_accept()
|
||||
{
|
||||
acceptor_.async_accept(
|
||||
[this](const std::error_code & error, tcp::socket socket) {
|
||||
if (!error) {
|
||||
std::make_shared<Session>(std::move(socket), context_)->start();
|
||||
}
|
||||
|
||||
do_accept();
|
||||
});
|
||||
}
|
||||
|
||||
tcp::acceptor acceptor_;
|
||||
asio::ssl::context context_;
|
||||
};
|
||||
|
||||
void set_thread_config(const char *name, int stack, int prio)
|
||||
{
|
||||
auto cfg = esp_pthread_get_default_config();
|
||||
cfg.thread_name = name;
|
||||
cfg.stack_size = stack;
|
||||
cfg.prio = prio;
|
||||
esp_pthread_set_cfg(&cfg);
|
||||
}
|
||||
|
||||
void ssl_server_thread()
|
||||
{
|
||||
asio::io_context io_context;
|
||||
|
||||
Server s(io_context, 443);
|
||||
|
||||
io_context.run();
|
||||
}
|
||||
|
||||
void ssl_client_thread()
|
||||
{
|
||||
asio::io_context io_context;
|
||||
|
||||
tcp::resolver resolver(io_context);
|
||||
std::string server_ip = CONFIG_EXAMPLE_SERVER_NAME;
|
||||
std::string server_port = CONFIG_EXAMPLE_PORT;
|
||||
auto endpoints = resolver.resolve(server_ip, server_port);
|
||||
|
||||
asio::ssl::context ctx(asio::ssl::context::tls_client);
|
||||
#if CONFIG_EXAMPLE_CLIENT_VERIFY_PEER
|
||||
ctx.add_certificate_authority(cert_chain);
|
||||
#endif // CONFIG_EXAMPLE_CLIENT_VERIFY_PEER
|
||||
|
||||
Client c(io_context, ctx, endpoints);
|
||||
|
||||
io_context.run();
|
||||
|
||||
}
|
||||
|
||||
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
esp_netif_init();
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
/* This helper function configures blocking UART I/O */
|
||||
ESP_ERROR_CHECK(example_configure_stdin_stdout());
|
||||
std::vector<std::thread> work_threads;
|
||||
|
||||
#if CONFIG_EXAMPLE_SERVER
|
||||
set_thread_config("Server", 16 * 1024, 5);
|
||||
work_threads.emplace_back(std::thread(ssl_server_thread));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
#endif // CONFIG_EXAMPLE_SERVER
|
||||
|
||||
#if CONFIG_EXAMPLE_CLIENT
|
||||
set_thread_config("Client", 16 * 1024, 5);
|
||||
work_threads.emplace_back(ssl_client_thread);
|
||||
#endif // CONFIG_EXAMPLE_CLIENT
|
||||
|
||||
for (auto &t : work_threads) {
|
||||
t.join();
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user