mirror of
https://github.com/0xFEEDC0DE64/arduino-esp32.git
synced 2025-06-25 18:01:33 +02:00
Compare commits
629 Commits
Author | SHA1 | Date | |
---|---|---|---|
cf60cf4c3b | |||
b5b45cd518 | |||
9a9fb2c3aa | |||
41e392f661 | |||
6be6abf35b | |||
baaff8480e | |||
54140dc5ca | |||
9f8b433196 | |||
b7c3607b5b | |||
2b0dbdc12a | |||
b06735a33a | |||
537b1a6d3a | |||
440437c905 | |||
9bb8224159 | |||
0db0af5932 | |||
8d9d7bbca9 | |||
291c519642 | |||
bbcc624c97 | |||
2656452d04 | |||
273a8d79b4 | |||
42b4a9927d | |||
383b999ddd | |||
52c284af75 | |||
5f057c7cac | |||
880fc0bdfb | |||
9eaa5873bf | |||
7678be447d | |||
c6f6522032 | |||
d2519843ad | |||
2cebf72876 | |||
4fa3cbab64 | |||
280bf4d014 | |||
dc0208ed1e | |||
f58cba0b4f | |||
38057d66ad | |||
4d98cea085 | |||
33f4745635 | |||
9f1ccb9c85 | |||
ea04207c8f | |||
e06f9b7fa6 | |||
2e19d27e3e | |||
b8fcea9a8d | |||
46bde99c06 | |||
7f61d2044a | |||
f13f84ddeb | |||
096af056d1 | |||
acadabb146 | |||
7d50114881 | |||
be074eec80 | |||
bd96f7f159 | |||
ca7ed86bbd | |||
a1bd429747 | |||
11cad8747e | |||
2d7ec30a1b | |||
ef961442d7 | |||
d5bd8e325c | |||
0a4b6599d2 | |||
8cb2a4ba3e | |||
d12af93ee2 | |||
7e9d75a974 | |||
61c98b8370 | |||
b92c58d74b | |||
35d9759fa6 | |||
04267e12da | |||
86494d5cb9 | |||
12a8779fd6 | |||
6ecd249a4a | |||
b15f5bac79 | |||
3d7f9d9282 | |||
dc3394d6ac | |||
351a651295 | |||
d009787a6f | |||
57b7e4c678 | |||
345055050b | |||
09bff5027d | |||
79f77afc98 | |||
594ee6d249 | |||
934841e236 | |||
cda6facdc7 | |||
eccbfdb48a | |||
27e61dcaf5 | |||
7553683bd2 | |||
40c325bd0a | |||
4f7e8065c0 | |||
05db08e20a | |||
ad067eab2d | |||
31d5120e04 | |||
d1110013af | |||
caca107719 | |||
279f7e33be | |||
f3835ea89f | |||
0d61996917 | |||
88f1b235e6 | |||
400aca52ce | |||
3fb164224d | |||
cebaf93dd8 | |||
176e5b0e79 | |||
9a16cd4600 | |||
b769dd0de3 | |||
7f1b7ade7b | |||
806e388d23 | |||
07f1bceef4 | |||
aa61b75aa4 | |||
48dfc89ccb | |||
c6bae38ce9 | |||
87d5f9d121 | |||
ed2115e361 | |||
644f7a8a2f | |||
81cdcc9e27 | |||
04988bdb21 | |||
2103a789b6 | |||
669cbec58e | |||
4f4bf07726 | |||
1840ba5c53 | |||
20028a2027 | |||
2977df4648 | |||
5320123e04 | |||
0a0ee87ba5 | |||
1bb1160dea | |||
a744383cbd | |||
7ea54ab6aa | |||
fd70e0d071 | |||
0e3994c966 | |||
5d7032d4f2 | |||
46abedcc1a | |||
a6a68a9546 | |||
062d4b123f | |||
ad68da6e41 | |||
f69b40dfff | |||
3a554c55f4 | |||
03d3d6112b | |||
05df11e0d9 | |||
c2be29eb97 | |||
49c47884a7 | |||
0ea23fe38a | |||
7f560284ff | |||
8569b2c893 | |||
49b76649f1 | |||
5d9bb5cf50 | |||
c8215315ae | |||
4d118b36a2 | |||
2c9b648502 | |||
5508689ea3 | |||
93d77859d9 | |||
0f772270fb | |||
13e02063d6 | |||
9b75c65fc7 | |||
109ba7a3b4 | |||
b2c678877c | |||
856e596c79 | |||
354e485c4b | |||
1c4966566c | |||
4bb60f68da | |||
ed220bd042 | |||
80f9f9aeec | |||
251d5ef92b | |||
8c723be135 | |||
b50a1755c8 | |||
bb0a194bb7 | |||
ed59ae6482 | |||
b4a9684a74 | |||
1977370e6f | |||
307b1368dd | |||
32d5654aa6 | |||
7637a739cc | |||
cd85239252 | |||
ac9d04a400 | |||
2195109ecc | |||
8d938c849d | |||
cb005fc8b5 | |||
89351e3ade | |||
86de90fe24 | |||
5960cd3e2a | |||
82e208c8c9 | |||
e7c9813625 | |||
dd78794311 | |||
0607d36734 | |||
6e77f7f3e5 | |||
915d45de7d | |||
c2b37d95e0 | |||
2f13a960ac | |||
579e04be25 | |||
5443d7ca93 | |||
7b3c1dfd50 | |||
85ef51ffbc | |||
36075257c2 | |||
7de1717640 | |||
8869d39d79 | |||
cfe8526ec8 | |||
c09ec5bd3d | |||
d8b2098461 | |||
3fc974f3aa | |||
9ad860758c | |||
cec3fca4ad | |||
dac493fb92 | |||
bc3d11364f | |||
f41beb92bf | |||
8c4ca5a235 | |||
b3085d4a8b | |||
547c2d3346 | |||
7d2632c024 | |||
e59355df71 | |||
ec63d09e54 | |||
188560e7f3 | |||
91e095f5a7 | |||
c8d8dc2265 | |||
b847f41e24 | |||
611ba8ea8a | |||
0cab2483e6 | |||
79e4339582 | |||
a35035f827 | |||
9ef3e2d2a6 | |||
0cdfb0b193 | |||
e50613622e | |||
24b277ad92 | |||
c2b3f2d6af | |||
8fb8e7d060 | |||
048b26547a | |||
b10ed77aaf | |||
4638628873 | |||
6f70e27011 | |||
d0b064a1ee | |||
85c77a9c3f | |||
c8e3f0c732 | |||
5ad468f9dc | |||
38c4c06108 | |||
b334b2c2f9 | |||
8a46697168 | |||
270a2759d9 | |||
01d9345d28 | |||
71e3d515f3 | |||
64cfb33deb | |||
5f1dff7dad | |||
40ebee1cb1 | |||
ed96d2a1b7 | |||
caa391ab34 | |||
3b71e136e1 | |||
1c77790a5b | |||
5bff89f0be | |||
9bbd720d4c | |||
589bb7032d | |||
f8c06894c5 | |||
a5c873b786 | |||
895a150840 | |||
ca88fdc273 | |||
f32083a6d0 | |||
b30e55efff | |||
0ac2de7aab | |||
0eec630314 | |||
731fd19bdf | |||
298c6104a2 | |||
8ea12f89f3 | |||
b3ba80d570 | |||
a5935ce1cc | |||
96d6975bd5 | |||
9eaeeb660c | |||
e22d8b6787 | |||
56fe2dbaff | |||
06a399b84a | |||
4ce2cc3c1d | |||
07390157df | |||
bab3a70f54 | |||
cd4f9038ee | |||
7fe2812f7f | |||
9710fedaf0 | |||
f5cacfee1a | |||
f71a4bd406 | |||
5f77b0108b | |||
717ca79ecb | |||
07613b3158 | |||
80ea521940 | |||
5c04de6f39 | |||
0d163a1ce2 | |||
2a7e509978 | |||
1b8c7e34f9 | |||
7a574399b1 | |||
fd089d8fd3 | |||
f356ccd54a | |||
6daf773464 | |||
70a896481d | |||
390da0d090 | |||
d5e2bb12ca | |||
f4acac4c2b | |||
5137fc5c80 | |||
03066e42ef | |||
cd5257ad78 | |||
ee6336a312 | |||
61f71930e9 | |||
ec40c4c96f | |||
2bda4a9617 | |||
91b9fae111 | |||
2a1fde7736 | |||
a12d609b22 | |||
73576674b8 | |||
007a93ec7e | |||
a5f3fc6fad | |||
65e256c40a | |||
fa55a2c91d | |||
a070884441 | |||
a9c8b46b1a | |||
6954150176 | |||
548f712df2 | |||
56ce580b0e | |||
509d31ba51 | |||
9e32cec9a2 | |||
3376ea1bd5 | |||
1c7e329140 | |||
c17b212cd0 | |||
7dbda4988b | |||
d1134fd45e | |||
d5fdd715ef | |||
ca7106e97e | |||
87e5787cf7 | |||
c13d11e7d1 | |||
b0d8d4dd44 | |||
05de017bd5 | |||
e1548e9b7e | |||
c29ec9da3d | |||
b3783fba95 | |||
a22ec4a978 | |||
20498cf8b1 | |||
02e51728c4 | |||
d2816b2f32 | |||
2e32022611 | |||
74ffdac74a | |||
4ee17ec3ee | |||
476660f763 | |||
f558e69181 | |||
5bf3aab527 | |||
1aced120ba | |||
7d7824701f | |||
89feacb813 | |||
aae6f24a37 | |||
43b781a158 | |||
e055b28d1a | |||
714ba948e6 | |||
e57de64a3c | |||
fd5a2f08f9 | |||
e9389e3122 | |||
0acf19af8f | |||
aff2e42ac6 | |||
2743e7b739 | |||
c453a0037b | |||
2f249edb8e | |||
bd57ff4ab4 | |||
43bf393dbf | |||
bea7bd1852 | |||
7dd537f8d3 | |||
50d142950d | |||
d13de284b8 | |||
697d4ff7c4 | |||
ab309e40d5 | |||
932666a03f | |||
a0ad987029 | |||
271e5cd206 | |||
619568db5b | |||
0202ba7c21 | |||
119ece2b0f | |||
606446a830 | |||
a28cf00295 | |||
672e4faa92 | |||
f8eebb5c39 | |||
6bf104874a | |||
9a9ff62216 | |||
3d6e4e1b94 | |||
01d7ea7b80 | |||
af23d0bb10 | |||
582e6433e9 | |||
ef07a84ade | |||
ea043cdb14 | |||
c60092951f | |||
fa74767b2e | |||
d922557e01 | |||
33d4186b35 | |||
6dab3f6777 | |||
1efcd21ba9 | |||
7b5cd47d07 | |||
14126060a1 | |||
25c0b52212 | |||
e0beac88c9 | |||
a87b2ec690 | |||
6744565257 | |||
da8b7c1b80 | |||
91508030d8 | |||
a0c975dfbc | |||
0906bf580f | |||
53a4bf33b6 | |||
92220b7643 | |||
dd649808d1 | |||
67ee7c32e7 | |||
8091c2cac7 | |||
4930853edb | |||
8e8c5035ea | |||
1db72a27c4 | |||
e28dce7eb7 | |||
d5f71ce545 | |||
7df50a97d1 | |||
566f659e90 | |||
cb0a939a6f | |||
cebd8704c8 | |||
ff85f3e90e | |||
dffda0bd6e | |||
2ceab7c279 | |||
84e458a9e1 | |||
f3c1a91f8e | |||
5af0336177 | |||
628b8f0c29 | |||
2bb32bd4b0 | |||
89d6b895d1 | |||
010a7c60f7 | |||
c0345eafbf | |||
71ec3c3e31 | |||
8ec76405b9 | |||
8806acfbf9 | |||
2e9cb5945d | |||
c001996eef | |||
c1344ae094 | |||
f6b9e9c2ab | |||
fc737e08c6 | |||
e302a6848a | |||
aa2393b573 | |||
755cd938f7 | |||
86fdb5b23d | |||
ffd15e4637 | |||
29d59876b4 | |||
8cbc60edbc | |||
00a546ee06 | |||
2ba1e66060 | |||
489feb8727 | |||
3350476d1d | |||
fa6f75952d | |||
6718da0350 | |||
45fa0f8294 | |||
6cf307dbd1 | |||
81844f5360 | |||
f7cf583b87 | |||
e8a2c16c8f | |||
9a7946e685 | |||
566b69eda3 | |||
e544e67838 | |||
b0582e1ec8 | |||
a539257a38 | |||
70656aa129 | |||
fa61b3bffe | |||
452c27a74a | |||
2fd39b1aff | |||
ff18a211e4 | |||
a6e3b29004 | |||
812d131663 | |||
00e69a28bc | |||
229d9b7366 | |||
6dd8be3262 | |||
28ea39cf05 | |||
f49c854ff3 | |||
879388e170 | |||
1085e9a8f0 | |||
bed9c96f41 | |||
5af139bb74 | |||
4f9a90fa0e | |||
310e78e6fd | |||
c827bb4177 | |||
1628f533a1 | |||
3e66aeff84 | |||
66d33f792c | |||
0de0d3f79a | |||
512d0d088f | |||
77810471ce | |||
be081ac026 | |||
4d3f6caa0d | |||
2db811f7f3 | |||
39836f12df | |||
25fd2d0f3b | |||
278fa0d87a | |||
b37f4069e4 | |||
e602145c2b | |||
6f6ee98188 | |||
1289f4be4b | |||
70f000da71 | |||
884e417a49 | |||
bb7dea1566 | |||
bff9f0b6b1 | |||
72803703fd | |||
0596a2ac86 | |||
fe1fdd2790 | |||
af7e489f01 | |||
5cfff190e9 | |||
7a332864ab | |||
8aa6e2e143 | |||
b5f317010c | |||
f644d9d157 | |||
a15b7e9088 | |||
ce340faf94 | |||
b69b04cb2b | |||
0cbba8a71d | |||
9e1f8cc457 | |||
cfe7e01158 | |||
fcd734a13c | |||
aa030e044c | |||
95d417cd93 | |||
df4eeb3005 | |||
a360064768 | |||
bfde8daf75 | |||
e583a0e879 | |||
7e9afe8c5e | |||
dcb007a485 | |||
bec6f87235 | |||
4ae64c541e | |||
46257c03b3 | |||
0640964879 | |||
e609c78f20 | |||
04963009ee | |||
c3ec91f968 | |||
a30005949a | |||
acefd4bf2e | |||
c700e5694f | |||
0d564d7b1d | |||
44ca2ee976 | |||
af79e18ecb | |||
273196d7e6 | |||
5d2460c74a | |||
259ff80d60 | |||
3902aa4019 | |||
f9d1b24c01 | |||
c7fa251d78 | |||
7b811f9b3a | |||
1fdc660641 | |||
a53c9de09d | |||
b58a3509b8 | |||
01d22c8807 | |||
b70737d276 | |||
233d31bed2 | |||
65c861ad4c | |||
f6a71da378 | |||
b8c9819e7f | |||
1bc1e8c602 | |||
2132d9f809 | |||
14ff311479 | |||
a3ed511884 | |||
9e2888392e | |||
a43682596f | |||
825b6ea79e | |||
deaf339bde | |||
f12df4c719 | |||
85032b226c | |||
e5ea089a7f | |||
96822d783f | |||
4e96bffe0e | |||
ea61563c69 | |||
5be3078b76 | |||
7206b2f397 | |||
3028ec42c7 | |||
145904fb9c | |||
cb8d72fdc7 | |||
1e4bf14a3e | |||
f9f995b283 | |||
c8fe873965 | |||
18d260ec6e | |||
3a8ac27a86 | |||
a6a9a518a7 | |||
02ee799f35 | |||
ce61074802 | |||
339618f8ef | |||
6e4e4c96ee | |||
a0f0bd930c | |||
80c110ece7 | |||
65511b23d3 | |||
14d6f6e7e6 | |||
9db207afbe | |||
a989853d4a | |||
172802b18e | |||
fff1783046 | |||
cb53ec4891 | |||
7d3a67ada0 | |||
d057e544e0 | |||
b05430cfd9 | |||
e346f20aa9 | |||
bdc45e39ef | |||
a7ddf39521 | |||
abb8ea99d5 | |||
30b3eebabc | |||
3222e6490a | |||
2fba81223e | |||
e51f7a5b87 | |||
7d2560cbbf | |||
17065dfd3a | |||
2f5b3c0c56 | |||
1fe3ee87b6 | |||
328523f5e3 | |||
7761ebd9f2 | |||
f9a382ab9f | |||
d854dc1bf6 | |||
f1f8d7e306 | |||
da798c7db0 | |||
8d7fb58672 | |||
2fda054bea | |||
e157ec06a7 | |||
05d72f963d | |||
b14f82b65f | |||
c830511f01 | |||
cbd4dc53a6 | |||
44f5a4dbc8 | |||
e63aa40650 | |||
28a410dd50 | |||
ddfeae90d0 | |||
ff90778173 | |||
4e9d1ee237 | |||
c1a94b5326 | |||
3e160587f3 | |||
79010b6498 | |||
9925772db0 | |||
c77aed4ac4 | |||
901a341949 | |||
9f6d0d2958 | |||
9efecc1be0 | |||
b0c6991bcf | |||
8afdd71b3a | |||
871dd183d8 | |||
05111bbde7 | |||
bad53905e8 | |||
95b87545e7 | |||
9f8f05735b | |||
a835bb26c4 | |||
5e46c9bae6 | |||
659c8ad528 | |||
2fe965259a | |||
0161e28614 | |||
4e5cbdaa7f | |||
12ca9e8b52 | |||
8b01b9e187 |
54
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
54
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Please fill in the bug report carefully
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
Make your question, not a Statement, inclusive. Include all pertinent information:
|
||||
|
||||
What you are trying to do?
|
||||
Describe your system( Hardware, computer, O/S, core version, environment).
|
||||
Describe what is failing.
|
||||
Show the shortest possible code that will duplicate the error.
|
||||
Show the EXACT error message(it doesn't work is not enough).
|
||||
All of this work on your part shows us that you have worked to solve YOUR problem. The more complete your issue posting is, the more likely someone will volunteer their time to help you.
|
||||
|
||||
If you have a Guru Meditation Error or Backtrace, ***please decode it***:
|
||||
https://github.com/me-no-dev/EspExceptionDecoder
|
||||
|
||||
----------------------------- Remove above -----------------------------
|
||||
|
||||
|
||||
### Hardware:
|
||||
Board: ?ESP32 Dev Module? ?node32? ?ttgo_lora?
|
||||
Core Installation version: ?1.0.0? ?1.0.1-rc4? ?1.0.1? ?1.0.1-git? ?1.0.2? ?1.0.3?
|
||||
IDE name: ?Arduino IDE? ?Platform.io? ?IDF component?
|
||||
Flash Frequency: ?40Mhz?
|
||||
PSRAM enabled: ?no? ?yes?
|
||||
Upload Speed: ?115200?
|
||||
Computer OS: ?Windows 10? ?Mac OSX? ?Ubuntu?
|
||||
|
||||
### Description:
|
||||
Describe your problem here
|
||||
|
||||
|
||||
### Sketch: (leave the backquotes for [code formatting](https://help.github.com/articles/creating-and-highlighting-code-blocks/))
|
||||
```cpp
|
||||
|
||||
//Change the code below by your sketch
|
||||
#include <Arduino.h>
|
||||
|
||||
void setup() {
|
||||
}
|
||||
|
||||
void loop() {
|
||||
}
|
||||
```
|
||||
|
||||
### Debug Messages:
|
||||
```
|
||||
Enable Core debug level: Debug on tools menu of Arduino IDE, then put the serial output here
|
||||
```
|
27
.github/scripts/check-cmakelists.sh
vendored
Executable file
27
.github/scripts/check-cmakelists.sh
vendored
Executable file
@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# This script is for Travis. It checks all non-examples source files in libraries/ and cores/ are listed in
|
||||
# CMakeLists.txt for the cmake-based IDF component
|
||||
#
|
||||
# If you see an error running this script, edit CMakeLists.txt and add any new source files into your PR
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
# pull all submodules
|
||||
git submodule update --init --recursive
|
||||
|
||||
# find all source files in repo
|
||||
REPO_SRCS=`find cores/esp32/ libraries/ -name 'examples' -prune -o -name '*.c' -print -o -name '*.cpp' -print | sort`
|
||||
|
||||
# find all source files named in CMakeLists.txt COMPONENT_SRCS
|
||||
CMAKE_SRCS=`cmake --trace-expand -C CMakeLists.txt 2>&1 | grep set\(srcs | cut -d'(' -f3 | sed 's/ )//' | sed 's/srcs //' | tr ' ;' '\n' | sort`
|
||||
|
||||
if ! diff -u0 --label "Repo Files" --label "srcs" <(echo "$REPO_SRCS") <(echo "$CMAKE_SRCS"); then
|
||||
echo "Source files in repo (-) and source files in CMakeLists.txt (+) don't match"
|
||||
echo "Edit CMakeLists.txt as appropriate to add/remove source files from COMPONENT_SRCS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "CMakeLists.txt and repo source files match"
|
||||
exit 0
|
36
.github/scripts/install-arduino-core-esp32.sh
vendored
Executable file
36
.github/scripts/install-arduino-core-esp32.sh
vendored
Executable file
@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
|
||||
export ARDUINO_ESP32_PATH="$ARDUINO_USR_PATH/hardware/espressif/esp32"
|
||||
if [ ! -d "$ARDUINO_ESP32_PATH" ]; then
|
||||
echo "Installing ESP32 Arduino Core ..."
|
||||
script_init_path="$PWD"
|
||||
mkdir -p "$ARDUINO_USR_PATH/hardware/espressif"
|
||||
cd "$ARDUINO_USR_PATH/hardware/espressif"
|
||||
|
||||
echo "Installing Python Serial ..."
|
||||
pip install pyserial > /dev/null
|
||||
|
||||
if [ "$OS_IS_WINDOWS" == "1" ]; then
|
||||
echo "Installing Python Requests ..."
|
||||
pip install requests > /dev/null
|
||||
fi
|
||||
|
||||
if [ "$GITHUB_REPOSITORY" == "espressif/arduino-esp32" ]; then
|
||||
echo "Linking Core..."
|
||||
ln -s $GITHUB_WORKSPACE esp32
|
||||
else
|
||||
echo "Cloning Core Repository..."
|
||||
git clone https://github.com/espressif/arduino-esp32.git esp32 > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
#echo "Updating Submodules ..."
|
||||
cd esp32
|
||||
#git submodule update --init --recursive > /dev/null 2>&1
|
||||
|
||||
echo "Installing Platform Tools ..."
|
||||
cd tools && python get.py
|
||||
cd $script_init_path
|
||||
|
||||
echo "ESP32 Arduino has been installed in '$ARDUINO_ESP32_PATH'"
|
||||
echo ""
|
||||
fi
|
228
.github/scripts/install-arduino-ide.sh
vendored
Executable file
228
.github/scripts/install-arduino-ide.sh
vendored
Executable file
@ -0,0 +1,228 @@
|
||||
#!/bin/bash
|
||||
|
||||
#OSTYPE: 'linux-gnu', ARCH: 'x86_64' => linux64
|
||||
#OSTYPE: 'msys', ARCH: 'x86_64' => win32
|
||||
#OSTYPE: 'darwin18', ARCH: 'i386' => macos
|
||||
|
||||
OSBITS=`arch`
|
||||
if [[ "$OSTYPE" == "linux"* ]]; then
|
||||
export OS_IS_LINUX="1"
|
||||
ARCHIVE_FORMAT="tar.xz"
|
||||
if [[ "$OSBITS" == "i686" ]]; then
|
||||
OS_NAME="linux32"
|
||||
elif [[ "$OSBITS" == "x86_64" ]]; then
|
||||
OS_NAME="linux64"
|
||||
elif [[ "$OSBITS" == "armv7l" || "$OSBITS" == "aarch64" ]]; then
|
||||
OS_NAME="linuxarm"
|
||||
else
|
||||
OS_NAME="$OSTYPE-$OSBITS"
|
||||
echo "Unknown OS '$OS_NAME'"
|
||||
exit 1
|
||||
fi
|
||||
elif [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
export OS_IS_MACOS="1"
|
||||
ARCHIVE_FORMAT="zip"
|
||||
OS_NAME="macosx"
|
||||
elif [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then
|
||||
export OS_IS_WINDOWS="1"
|
||||
ARCHIVE_FORMAT="zip"
|
||||
OS_NAME="windows"
|
||||
else
|
||||
OS_NAME="$OSTYPE-$OSBITS"
|
||||
echo "Unknown OS '$OS_NAME'"
|
||||
exit 1
|
||||
fi
|
||||
export OS_NAME
|
||||
|
||||
ARDUINO_BUILD_DIR="$HOME/.arduino/build.tmp"
|
||||
ARDUINO_CACHE_DIR="$HOME/.arduino/cache.tmp"
|
||||
|
||||
if [ "$OS_IS_MACOS" == "1" ]; then
|
||||
export ARDUINO_IDE_PATH="/Applications/Arduino.app/Contents/Java"
|
||||
export ARDUINO_USR_PATH="$HOME/Documents/Arduino"
|
||||
elif [ "$OS_IS_WINDOWS" == "1" ]; then
|
||||
export ARDUINO_IDE_PATH="$HOME/arduino_ide"
|
||||
export ARDUINO_USR_PATH="$HOME/Documents/Arduino"
|
||||
else
|
||||
export ARDUINO_IDE_PATH="$HOME/arduino_ide"
|
||||
export ARDUINO_USR_PATH="$HOME/Arduino"
|
||||
fi
|
||||
|
||||
# Updated as of Nov 3rd 2020
|
||||
ARDUINO_IDE_URL="https://github.com/espressif/arduino-esp32/releases/download/1.0.4/arduino-nightly-"
|
||||
|
||||
# Currently not working
|
||||
#ARDUINO_IDE_URL="https://www.arduino.cc/download.php?f=/arduino-nightly-"
|
||||
|
||||
if [ ! -d "$ARDUINO_IDE_PATH" ]; then
|
||||
echo "Installing Arduino IDE on $OS_NAME ..."
|
||||
echo "Downloading '$ARDUINO_IDE_URL$OS_NAME.$ARCHIVE_FORMAT' to 'arduino.$ARCHIVE_FORMAT' ..."
|
||||
if [ "$OS_IS_LINUX" == "1" ]; then
|
||||
wget -O "arduino.$ARCHIVE_FORMAT" "$ARDUINO_IDE_URL$OS_NAME.$ARCHIVE_FORMAT" > /dev/null 2>&1
|
||||
echo "Extracting 'arduino.$ARCHIVE_FORMAT' ..."
|
||||
tar xf "arduino.$ARCHIVE_FORMAT" > /dev/null
|
||||
mv arduino-nightly "$ARDUINO_IDE_PATH"
|
||||
else
|
||||
curl -o "arduino.$ARCHIVE_FORMAT" -L "$ARDUINO_IDE_URL$OS_NAME.$ARCHIVE_FORMAT" > /dev/null 2>&1
|
||||
echo "Extracting 'arduino.$ARCHIVE_FORMAT' ..."
|
||||
unzip "arduino.$ARCHIVE_FORMAT" > /dev/null
|
||||
if [ "$OS_IS_MACOS" == "1" ]; then
|
||||
mv "Arduino.app" "/Applications/Arduino.app"
|
||||
else
|
||||
mv arduino-nightly "$ARDUINO_IDE_PATH"
|
||||
fi
|
||||
fi
|
||||
rm -rf "arduino.$ARCHIVE_FORMAT"
|
||||
|
||||
mkdir -p "$ARDUINO_USR_PATH/libraries"
|
||||
mkdir -p "$ARDUINO_USR_PATH/hardware"
|
||||
|
||||
echo "Arduino IDE Installed in '$ARDUINO_IDE_PATH'"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
function build_sketch(){ # build_sketch <fqbn> <path-to-ino> [extra-options]
|
||||
if [ "$#" -lt 2 ]; then
|
||||
echo "ERROR: Illegal number of parameters"
|
||||
echo "USAGE: build_sketch <fqbn> <path-to-ino> [extra-options]"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local fqbn="$1"
|
||||
local sketch="$2"
|
||||
local xtra_opts="$3"
|
||||
local win_opts=""
|
||||
if [ "$OS_IS_WINDOWS" == "1" ]; then
|
||||
local ctags_version=`ls "$ARDUINO_IDE_PATH/tools-builder/ctags/"`
|
||||
local preprocessor_version=`ls "$ARDUINO_IDE_PATH/tools-builder/arduino-preprocessor/"`
|
||||
win_opts="-prefs=runtime.tools.ctags.path=$ARDUINO_IDE_PATH/tools-builder/ctags/$ctags_version -prefs=runtime.tools.arduino-preprocessor.path=$ARDUINO_IDE_PATH/tools-builder/arduino-preprocessor/$preprocessor_version"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Compiling '"$(basename "$sketch")"' ..."
|
||||
mkdir -p "$ARDUINO_BUILD_DIR"
|
||||
mkdir -p "$ARDUINO_CACHE_DIR"
|
||||
$ARDUINO_IDE_PATH/arduino-builder -compile -logger=human -core-api-version=10810 \
|
||||
-fqbn=$fqbn \
|
||||
-warnings="all" \
|
||||
-tools "$ARDUINO_IDE_PATH/tools-builder" \
|
||||
-tools "$ARDUINO_IDE_PATH/tools" \
|
||||
-built-in-libraries "$ARDUINO_IDE_PATH/libraries" \
|
||||
-hardware "$ARDUINO_IDE_PATH/hardware" \
|
||||
-hardware "$ARDUINO_USR_PATH/hardware" \
|
||||
-libraries "$ARDUINO_USR_PATH/libraries" \
|
||||
-build-cache "$ARDUINO_CACHE_DIR" \
|
||||
-build-path "$ARDUINO_BUILD_DIR" \
|
||||
$win_opts $xtra_opts "$sketch"
|
||||
}
|
||||
|
||||
function count_sketches() # count_sketches <examples-path> <target-mcu>
|
||||
{
|
||||
local examples="$1"
|
||||
local target="$2"
|
||||
rm -rf sketches.txt
|
||||
if [ ! -d "$examples" ]; then
|
||||
touch sketches.txt
|
||||
return 0
|
||||
fi
|
||||
local sketches=$(find $examples -name *.ino)
|
||||
local sketchnum=0
|
||||
for sketch in $sketches; do
|
||||
local sketchdir=$(dirname $sketch)
|
||||
local sketchdirname=$(basename $sketchdir)
|
||||
local sketchname=$(basename $sketch)
|
||||
if [[ "${sketchdirname}.ino" != "$sketchname" ]]; then
|
||||
continue
|
||||
fi;
|
||||
if [[ -f "$sketchdir/.skip.$target" ]]; then
|
||||
continue
|
||||
fi
|
||||
echo $sketch >> sketches.txt
|
||||
sketchnum=$(($sketchnum + 1))
|
||||
done
|
||||
return $sketchnum
|
||||
}
|
||||
|
||||
function build_sketches() # build_sketches <fqbn> <target-mcu> <examples-path> <chunk> <total-chunks> [extra-options]
|
||||
{
|
||||
local fqbn=$1
|
||||
local target="$2"
|
||||
local examples=$3
|
||||
local chunk_idex=$4
|
||||
local chunks_num=$5
|
||||
local xtra_opts=$6
|
||||
|
||||
if [ "$#" -lt 3 ]; then
|
||||
echo "ERROR: Illegal number of parameters"
|
||||
echo "USAGE: build_sketches <fqbn> <target-mcu <examples-path> [<chunk> <total-chunks>] [extra-options]"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$#" -lt 5 ]; then
|
||||
chunk_idex="0"
|
||||
chunks_num="1"
|
||||
xtra_opts=$4
|
||||
fi
|
||||
|
||||
if [ "$chunks_num" -le 0 ]; then
|
||||
echo "ERROR: Chunks count must be positive number"
|
||||
return 1
|
||||
fi
|
||||
if [ "$chunk_idex" -ge "$chunks_num" ]; then
|
||||
echo "ERROR: Chunk index must be less than chunks count"
|
||||
return 1
|
||||
fi
|
||||
|
||||
set +e
|
||||
count_sketches "$examples"
|
||||
local sketchcount=$?
|
||||
set -e
|
||||
local sketches=$(cat sketches.txt)
|
||||
rm -rf sketches.txt
|
||||
|
||||
local chunk_size=$(( $sketchcount / $chunks_num ))
|
||||
local all_chunks=$(( $chunks_num * $chunk_size ))
|
||||
if [ "$all_chunks" -lt "$sketchcount" ]; then
|
||||
chunk_size=$(( $chunk_size + 1 ))
|
||||
fi
|
||||
|
||||
local start_index=$(( $chunk_idex * $chunk_size ))
|
||||
if [ "$sketchcount" -le "$start_index" ]; then
|
||||
echo "Skipping job"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local end_index=$(( $(( $chunk_idex + 1 )) * $chunk_size ))
|
||||
if [ "$end_index" -gt "$sketchcount" ]; then
|
||||
end_index=$sketchcount
|
||||
fi
|
||||
|
||||
local start_num=$(( $start_index + 1 ))
|
||||
echo "Found $sketchcount Sketches";
|
||||
echo "Chunk Count : $chunks_num"
|
||||
echo "Chunk Size : $chunk_size"
|
||||
echo "Start Sketch: $start_num"
|
||||
echo "End Sketch : $end_index"
|
||||
|
||||
local sketchnum=0
|
||||
for sketch in $sketches; do
|
||||
local sketchdir=$(dirname $sketch)
|
||||
local sketchdirname=$(basename $sketchdir)
|
||||
local sketchname=$(basename $sketch)
|
||||
if [ "${sketchdirname}.ino" != "$sketchname" ] \
|
||||
|| [ -f "$sketchdir/.skip.$target" ]; then
|
||||
continue
|
||||
fi
|
||||
sketchnum=$(($sketchnum + 1))
|
||||
if [ "$sketchnum" -le "$start_index" ] \
|
||||
|| [ "$sketchnum" -gt "$end_index" ]; then
|
||||
continue
|
||||
fi
|
||||
build_sketch "$fqbn" "$sketch" "$xtra_opts"
|
||||
local result=$?
|
||||
if [ $result -ne 0 ]; then
|
||||
return $result
|
||||
fi
|
||||
done
|
||||
return 0
|
||||
}
|
151
.github/scripts/install-platformio-esp32.sh
vendored
Executable file
151
.github/scripts/install-platformio-esp32.sh
vendored
Executable file
@ -0,0 +1,151 @@
|
||||
#!/bin/bash
|
||||
|
||||
export PLATFORMIO_ESP32_PATH="$HOME/.platformio/packages/framework-arduinoespressif32"
|
||||
PLATFORMIO_ESP32_URL="https://github.com/platformio/platform-espressif32.git#feature/idf-v4.0"
|
||||
|
||||
echo "Installing Python Wheel ..."
|
||||
pip install wheel > /dev/null 2>&1
|
||||
|
||||
echo "Installing PlatformIO ..."
|
||||
pip install -U https://github.com/platformio/platformio/archive/develop.zip > /dev/null 2>&1
|
||||
|
||||
echo "Installing Platform ESP32 ..."
|
||||
python -m platformio platform install $PLATFORMIO_ESP32_URL > /dev/null 2>&1
|
||||
|
||||
echo "Replacing the framework version ..."
|
||||
python -c "import json; import os; fp=open(os.path.expanduser('~/.platformio/platforms/espressif32/platform.json'), 'r+'); data=json.load(fp); data['packages']['framework-arduinoespressif32']['version'] = '*'; del data['packages']['framework-arduinoespressif32']['owner']; fp.seek(0); fp.truncate(); json.dump(data, fp); fp.close()"
|
||||
|
||||
if [ "$GITHUB_REPOSITORY" == "espressif/arduino-esp32" ]; then
|
||||
echo "Linking Core..."
|
||||
ln -s $GITHUB_WORKSPACE "$PLATFORMIO_ESP32_PATH"
|
||||
else
|
||||
echo "Cloning Core Repository ..."
|
||||
git clone --recursive https://github.com/espressif/arduino-esp32.git "$PLATFORMIO_ESP32_PATH" > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
echo "PlatformIO for ESP32 has been installed"
|
||||
echo ""
|
||||
|
||||
function build_pio_sketch(){ # build_pio_sketch <board> <options> <path-to-ino>
|
||||
if [ "$#" -lt 3 ]; then
|
||||
echo "ERROR: Illegal number of parameters"
|
||||
echo "USAGE: build_pio_sketch <board> <options> <path-to-ino>"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local board="$1"
|
||||
local options="$2"
|
||||
local sketch="$3"
|
||||
local sketch_dir=$(dirname "$sketch")
|
||||
echo ""
|
||||
echo "Compiling '"$(basename "$sketch")"' ..."
|
||||
python -m platformio ci --board "$board" "$sketch_dir" --project-option="$options"
|
||||
}
|
||||
|
||||
function count_sketches() # count_sketches <examples-path>
|
||||
{
|
||||
local examples="$1"
|
||||
rm -rf sketches.txt
|
||||
if [ ! -d "$examples" ]; then
|
||||
touch sketches.txt
|
||||
return 0
|
||||
fi
|
||||
local sketches=$(find $examples -name *.ino)
|
||||
local sketchnum=0
|
||||
for sketch in $sketches; do
|
||||
local sketchdir=$(dirname $sketch)
|
||||
local sketchdirname=$(basename $sketchdir)
|
||||
local sketchname=$(basename $sketch)
|
||||
if [[ "${sketchdirname}.ino" != "$sketchname" ]]; then
|
||||
continue
|
||||
fi;
|
||||
if [[ -f "$sketchdir/.test.skip" ]]; then
|
||||
continue
|
||||
fi
|
||||
echo $sketch >> sketches.txt
|
||||
sketchnum=$(($sketchnum + 1))
|
||||
done
|
||||
return $sketchnum
|
||||
}
|
||||
|
||||
function build_pio_sketches() # build_pio_sketches <board> <options> <examples-path> <chunk> <total-chunks>
|
||||
{
|
||||
if [ "$#" -lt 3 ]; then
|
||||
echo "ERROR: Illegal number of parameters"
|
||||
echo "USAGE: build_pio_sketches <board> <options> <examples-path> [<chunk> <total-chunks>]"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local board=$1
|
||||
local options="$2"
|
||||
local examples=$3
|
||||
local chunk_idex=$4
|
||||
local chunks_num=$5
|
||||
|
||||
if [ "$#" -lt 5 ]; then
|
||||
chunk_idex="0"
|
||||
chunks_num="1"
|
||||
fi
|
||||
|
||||
if [ "$chunks_num" -le 0 ]; then
|
||||
echo "ERROR: Chunks count must be positive number"
|
||||
return 1
|
||||
fi
|
||||
if [ "$chunk_idex" -ge "$chunks_num" ]; then
|
||||
echo "ERROR: Chunk index must be less than chunks count"
|
||||
return 1
|
||||
fi
|
||||
|
||||
set +e
|
||||
count_sketches "$examples"
|
||||
local sketchcount=$?
|
||||
set -e
|
||||
local sketches=$(cat sketches.txt)
|
||||
rm -rf sketches.txt
|
||||
|
||||
local chunk_size=$(( $sketchcount / $chunks_num ))
|
||||
local all_chunks=$(( $chunks_num * $chunk_size ))
|
||||
if [ "$all_chunks" -lt "$sketchcount" ]; then
|
||||
chunk_size=$(( $chunk_size + 1 ))
|
||||
fi
|
||||
|
||||
local start_index=$(( $chunk_idex * $chunk_size ))
|
||||
if [ "$sketchcount" -le "$start_index" ]; then
|
||||
echo "Skipping job"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local end_index=$(( $(( $chunk_idex + 1 )) * $chunk_size ))
|
||||
if [ "$end_index" -gt "$sketchcount" ]; then
|
||||
end_index=$sketchcount
|
||||
fi
|
||||
|
||||
local start_num=$(( $start_index + 1 ))
|
||||
echo "Found $sketchcount Sketches";
|
||||
echo "Chunk Count : $chunks_num"
|
||||
echo "Chunk Size : $chunk_size"
|
||||
echo "Start Sketch: $start_num"
|
||||
echo "End Sketch : $end_index"
|
||||
|
||||
local sketchnum=0
|
||||
for sketch in $sketches; do
|
||||
local sketchdir=$(dirname $sketch)
|
||||
local sketchdirname=$(basename $sketchdir)
|
||||
local sketchname=$(basename $sketch)
|
||||
if [ "${sketchdirname}.ino" != "$sketchname" ] \
|
||||
|| [ -f "$sketchdir/.test.skip" ]; then
|
||||
continue
|
||||
fi
|
||||
sketchnum=$(($sketchnum + 1))
|
||||
if [ "$sketchnum" -le "$start_index" ] \
|
||||
|| [ "$sketchnum" -gt "$end_index" ]; then
|
||||
continue
|
||||
fi
|
||||
build_pio_sketch "$board" "$options" "$sketch"
|
||||
local result=$?
|
||||
if [ $result -ne 0 ]; then
|
||||
return $result
|
||||
fi
|
||||
done
|
||||
return 0
|
||||
}
|
4
package/merge_packages.py → .github/scripts/merge_packages.py
vendored
Normal file → Executable file
4
package/merge_packages.py → .github/scripts/merge_packages.py
vendored
Normal file → Executable file
@ -36,7 +36,11 @@ def pkgVersionNormalized(versionString):
|
||||
verParts = re.split('\.|-rc', verStr, flags=re.IGNORECASE)
|
||||
|
||||
if len(verParts) == 3:
|
||||
if (sys.version_info > (3, 0)): # Python 3
|
||||
verStr = str(versionString) + '-rc' + str(sys.maxsize)
|
||||
else: # Python 2
|
||||
verStr = str(versionString) + '-rc' + str(sys.maxint)
|
||||
|
||||
elif len(verParts) != 4:
|
||||
print("pkgVersionNormalized WARNING: unexpected version format: {0})".format(verStr), file=sys.stderr)
|
||||
|
131
.github/scripts/on-pages.sh
vendored
Normal file
131
.github/scripts/on-pages.sh
vendored
Normal file
@ -0,0 +1,131 @@
|
||||
#/bin/bash
|
||||
set -e
|
||||
|
||||
function get_file_size(){
|
||||
local file="$1"
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
eval `stat -s "$file"`
|
||||
local res="$?"
|
||||
echo "$st_size"
|
||||
return $res
|
||||
else
|
||||
stat --printf="%s" "$file"
|
||||
return $?
|
||||
fi
|
||||
}
|
||||
|
||||
#git_remove_from_pages <file>
|
||||
function git_remove_from_pages(){
|
||||
local path=$1
|
||||
local info=`curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.object+json" -X GET "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path?ref=gh-pages"`
|
||||
local type=`echo "$info" | jq -r '.type'`
|
||||
if [ ! $type == "file" ]; then
|
||||
if [ ! $type == "null" ]; then
|
||||
echo "Wrong type '$type'"
|
||||
else
|
||||
echo "File is not on Pages"
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
local sha=`echo "$info" | jq -r '.sha'`
|
||||
local message="Deleting "$(basename $path)
|
||||
local json="{\"branch\":\"gh-pages\",\"message\":\"$message\",\"sha\":\"$sha\"}"
|
||||
echo "$json" | curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.raw+json" -X DELETE --data @- "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path"
|
||||
}
|
||||
|
||||
function git_upload_to_pages(){
|
||||
local path=$1
|
||||
local src=$2
|
||||
|
||||
if [ ! -f "$src" ]; then
|
||||
>&2 echo "Input is not a file! Aborting..."
|
||||
return 1
|
||||
fi
|
||||
|
||||
local info=`curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.object+json" -X GET "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path?ref=gh-pages"`
|
||||
local type=`echo "$info" | jq -r '.type'`
|
||||
local message=$(basename $path)
|
||||
local sha=""
|
||||
local content=""
|
||||
|
||||
if [ $type == "file" ]; then
|
||||
sha=`echo "$info" | jq -r '.sha'`
|
||||
sha=",\"sha\":\"$sha\""
|
||||
message="Updating $message"
|
||||
elif [ ! $type == "null" ]; then
|
||||
>&2 echo "Wrong type '$type'"
|
||||
return 1
|
||||
else
|
||||
message="Creating $message"
|
||||
fi
|
||||
|
||||
content=`base64 -i "$src"`
|
||||
data="{\"branch\":\"gh-pages\",\"message\":\"$message\",\"content\":\"$content\"$sha}"
|
||||
|
||||
echo "$data" | curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.raw+json" -X PUT --data @- "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path"
|
||||
}
|
||||
|
||||
function git_safe_upload_to_pages(){
|
||||
local path=$1
|
||||
local file="$2"
|
||||
local name=$(basename "$file")
|
||||
local size=`get_file_size "$file"`
|
||||
local upload_res=`git_upload_to_pages "$path" "$file"`
|
||||
if [ $? -ne 0 ]; then
|
||||
>&2 echo "ERROR: Failed to upload '$name' ($?)"
|
||||
return 1
|
||||
fi
|
||||
up_size=`echo "$upload_res" | jq -r '.content.size'`
|
||||
if [ $up_size -ne $size ]; then
|
||||
>&2 echo "ERROR: Uploaded size does not match! $up_size != $size"
|
||||
#git_delete_asset
|
||||
return 1
|
||||
fi
|
||||
echo "$upload_res" | jq -r '.content.download_url'
|
||||
return $?
|
||||
}
|
||||
|
||||
EVENT_JSON=`cat $GITHUB_EVENT_PATH`
|
||||
|
||||
pages_added=`echo "$EVENT_JSON" | jq -r '.commits[].added[]'`
|
||||
pages_modified=`echo "$EVENT_JSON" | jq -r '.commits[].modified[]'`
|
||||
pages_removed=`echo "$EVENT_JSON" | jq -r '.commits[].removed[]'`
|
||||
|
||||
for page in $pages_added; do
|
||||
if [[ $page != "README.md" && $page != "docs/"* ]]; then
|
||||
continue
|
||||
fi
|
||||
echo "Adding '$page' to pages ..."
|
||||
if [[ $page == "README.md" ]]; then
|
||||
git_safe_upload_to_pages "index.md" "README.md"
|
||||
else
|
||||
git_safe_upload_to_pages "$page" "$page"
|
||||
fi
|
||||
done
|
||||
|
||||
for page in $pages_modified; do
|
||||
if [[ $page != "README.md" && $page != "docs/"* ]]; then
|
||||
continue
|
||||
fi
|
||||
echo "Modifying '$page' ..."
|
||||
if [[ $page == "README.md" ]]; then
|
||||
git_safe_upload_to_pages "index.md" "README.md"
|
||||
else
|
||||
git_safe_upload_to_pages "$page" "$page"
|
||||
fi
|
||||
done
|
||||
|
||||
for page in $pages_removed; do
|
||||
if [[ $page != "README.md" && $page != "docs/"* ]]; then
|
||||
continue
|
||||
fi
|
||||
echo "Removing '$page' from pages ..."
|
||||
if [[ $page == "README.md" ]]; then
|
||||
git_remove_from_pages "README.md" > /dev/null
|
||||
else
|
||||
git_remove_from_pages "$page" > /dev/null
|
||||
fi
|
||||
done
|
||||
|
||||
echo
|
||||
echo "DONE!"
|
91
.github/scripts/on-push.sh
vendored
Executable file
91
.github/scripts/on-push.sh
vendored
Executable file
@ -0,0 +1,91 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
if [ ! -z "$TRAVIS_TAG" ]; then
|
||||
echo "Skipping Test: Tagged build"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ ! -z "$GITHUB_WORKSPACE" ]; then
|
||||
export TRAVIS_BUILD_DIR="$GITHUB_WORKSPACE"
|
||||
export TRAVIS_REPO_SLUG="$GITHUB_REPOSITORY"
|
||||
elif [ ! -z "$TRAVIS_BUILD_DIR" ]; then
|
||||
export GITHUB_WORKSPACE="$TRAVIS_BUILD_DIR"
|
||||
export GITHUB_REPOSITORY="$TRAVIS_REPO_SLUG"
|
||||
else
|
||||
export GITHUB_WORKSPACE="$PWD"
|
||||
export GITHUB_REPOSITORY="espressif/arduino-esp32"
|
||||
fi
|
||||
|
||||
CHUNK_INDEX=$1
|
||||
CHUNKS_CNT=$2
|
||||
BUILD_PIO=0
|
||||
if [ "$#" -lt 2 ] || [ "$CHUNKS_CNT" -le 0 ]; then
|
||||
CHUNK_INDEX=0
|
||||
CHUNKS_CNT=1
|
||||
elif [ "$CHUNK_INDEX" -gt "$CHUNKS_CNT" ]; then
|
||||
CHUNK_INDEX=$CHUNKS_CNT
|
||||
elif [ "$CHUNK_INDEX" -eq "$CHUNKS_CNT" ]; then
|
||||
BUILD_PIO=1
|
||||
fi
|
||||
|
||||
#echo "Updating submodules ..."
|
||||
#git -C "$GITHUB_WORKSPACE" submodule update --init --recursive > /dev/null 2>&1
|
||||
|
||||
if [ "$BUILD_PIO" -eq 0 ]; then
|
||||
# ArduinoIDE ESP32 Test
|
||||
TARGET="esp32"
|
||||
FQBN="espressif:esp32:esp32:PSRAM=enabled,PartitionScheme=huge_app"
|
||||
source ./.github/scripts/install-arduino-ide.sh
|
||||
source ./.github/scripts/install-arduino-core-esp32.sh
|
||||
if [ "$OS_IS_WINDOWS" == "1" ]; then
|
||||
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino" && \
|
||||
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/BLE/examples/BLE_server/BLE_server.ino" && \
|
||||
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino"
|
||||
elif [ "$OS_IS_MACOS" == "1" ]; then
|
||||
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFi/examples/WiFiClient/WiFiClient.ino" && \
|
||||
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino" && \
|
||||
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino" && \
|
||||
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/BLE/examples/BLE_server/BLE_server.ino" && \
|
||||
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino"
|
||||
else
|
||||
# CMake Test
|
||||
if [ "$CHUNK_INDEX" -eq 0 ]; then
|
||||
bash "$ARDUINO_ESP32_PATH/.github/scripts/check-cmakelists.sh"
|
||||
fi
|
||||
build_sketches "$FQBN" "$TARGET" "$ARDUINO_ESP32_PATH/libraries" "$CHUNK_INDEX" "$CHUNKS_CNT"
|
||||
fi
|
||||
|
||||
# ArduinoIDE ESP32S2 Test
|
||||
TARGET="esp32s2"
|
||||
FQBN="espressif:esp32:esp32s2:PSRAM=enabled,PartitionScheme=huge_app"
|
||||
if [ "$OS_IS_WINDOWS" == "1" ]; then
|
||||
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFi/examples/WiFiClient/WiFiClient.ino" && \
|
||||
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino"
|
||||
elif [ "$OS_IS_MACOS" == "1" ]; then
|
||||
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFi/examples/WiFiClient/WiFiClient.ino" && \
|
||||
build_sketch "$FQBN" "$ARDUINO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino"
|
||||
else
|
||||
build_sketches "$FQBN" "$TARGET" "$ARDUINO_ESP32_PATH/libraries" "$CHUNK_INDEX" "$CHUNKS_CNT"
|
||||
fi
|
||||
else
|
||||
source ./.github/scripts/install-platformio-esp32.sh
|
||||
# PlatformIO ESP32 Test
|
||||
BOARD="esp32dev"
|
||||
OPTIONS="board_build.partitions = huge_app.csv"
|
||||
build_pio_sketch "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries/WiFi/examples/WiFiClient/WiFiClient.ino" && \
|
||||
build_pio_sketch "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino" && \
|
||||
build_pio_sketch "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino" && \
|
||||
build_pio_sketch "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries/BLE/examples/BLE_server/BLE_server.ino" && \
|
||||
build_pio_sketch "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino"
|
||||
|
||||
# PlatformIO ESP32 Test
|
||||
# OPTIONS="board_build.mcu = esp32s2"
|
||||
# build_pio_sketch "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries/WiFi/examples/WiFiClient/WiFiClient.ino" && \
|
||||
# build_pio_sketch "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino"
|
||||
|
||||
python -m platformio ci --board "$BOARD" "$PLATFORMIO_ESP32_PATH/libraries/WiFi/examples/WiFiClient" --project-option="board_build.mcu = esp32s2" --project-option="board_build.partitions = huge_app.csv"
|
||||
|
||||
#build_pio_sketches "$BOARD" "$OPTIONS" "$PLATFORMIO_ESP32_PATH/libraries"
|
||||
fi
|
380
.github/scripts/on-release.sh
vendored
Executable file
380
.github/scripts/on-release.sh
vendored
Executable file
@ -0,0 +1,380 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ ! $GITHUB_EVENT_NAME == "release" ]; then
|
||||
echo "Wrong event '$GITHUB_EVENT_NAME'!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
EVENT_JSON=`cat $GITHUB_EVENT_PATH`
|
||||
|
||||
action=`echo $EVENT_JSON | jq -r '.action'`
|
||||
if [ ! $action == "published" ]; then
|
||||
echo "Wrong action '$action'. Exiting now..."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
draft=`echo $EVENT_JSON | jq -r '.release.draft'`
|
||||
if [ $draft == "true" ]; then
|
||||
echo "It's a draft release. Exiting now..."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
RELEASE_PRE=`echo $EVENT_JSON | jq -r '.release.prerelease'`
|
||||
RELEASE_TAG=`echo $EVENT_JSON | jq -r '.release.tag_name'`
|
||||
RELEASE_BRANCH=`echo $EVENT_JSON | jq -r '.release.target_commitish'`
|
||||
RELEASE_ID=`echo $EVENT_JSON | jq -r '.release.id'`
|
||||
RELEASE_BODY=`echo $EVENT_JSON | jq -r '.release.body'`
|
||||
|
||||
OUTPUT_DIR="$GITHUB_WORKSPACE/build"
|
||||
PACKAGE_NAME="esp32-$RELEASE_TAG"
|
||||
PACKAGE_JSON_MERGE="$GITHUB_WORKSPACE/.github/scripts/merge_packages.py"
|
||||
PACKAGE_JSON_TEMPLATE="$GITHUB_WORKSPACE/package/package_esp32_index.template.json"
|
||||
PACKAGE_JSON_DEV="package_esp32_dev_index.json"
|
||||
PACKAGE_JSON_REL="package_esp32_index.json"
|
||||
|
||||
echo "Event: $GITHUB_EVENT_NAME, Repo: $GITHUB_REPOSITORY, Path: $GITHUB_WORKSPACE, Ref: $GITHUB_REF"
|
||||
echo "Action: $action, Branch: $RELEASE_BRANCH, ID: $RELEASE_ID"
|
||||
echo "Tag: $RELEASE_TAG, Draft: $draft, Pre-Release: $RELEASE_PRE"
|
||||
|
||||
function get_file_size(){
|
||||
local file="$1"
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
eval `stat -s "$file"`
|
||||
local res="$?"
|
||||
echo "$st_size"
|
||||
return $res
|
||||
else
|
||||
stat --printf="%s" "$file"
|
||||
return $?
|
||||
fi
|
||||
}
|
||||
|
||||
function git_upload_asset(){
|
||||
local name=$(basename "$1")
|
||||
# local mime=$(file -b --mime-type "$1")
|
||||
curl -k -X POST -sH "Authorization: token $GITHUB_TOKEN" -H "Content-Type: application/octet-stream" --data-binary @"$1" "https://uploads.github.com/repos/$GITHUB_REPOSITORY/releases/$RELEASE_ID/assets?name=$name"
|
||||
}
|
||||
|
||||
function git_safe_upload_asset(){
|
||||
local file="$1"
|
||||
local name=$(basename "$file")
|
||||
local size=`get_file_size "$file"`
|
||||
local upload_res=`git_upload_asset "$file"`
|
||||
if [ $? -ne 0 ]; then
|
||||
>&2 echo "ERROR: Failed to upload '$name' ($?)"
|
||||
return 1
|
||||
fi
|
||||
up_size=`echo "$upload_res" | jq -r '.size'`
|
||||
if [ $up_size -ne $size ]; then
|
||||
>&2 echo "ERROR: Uploaded size does not match! $up_size != $size"
|
||||
#git_delete_asset
|
||||
return 1
|
||||
fi
|
||||
echo "$upload_res" | jq -r '.browser_download_url'
|
||||
return $?
|
||||
}
|
||||
|
||||
function git_upload_to_pages(){
|
||||
local path=$1
|
||||
local src=$2
|
||||
|
||||
if [ ! -f "$src" ]; then
|
||||
>&2 echo "Input is not a file! Aborting..."
|
||||
return 1
|
||||
fi
|
||||
|
||||
local info=`curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.object+json" -X GET "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path?ref=gh-pages"`
|
||||
local type=`echo "$info" | jq -r '.type'`
|
||||
local message=$(basename $path)
|
||||
local sha=""
|
||||
local content=""
|
||||
|
||||
if [ $type == "file" ]; then
|
||||
sha=`echo "$info" | jq -r '.sha'`
|
||||
sha=",\"sha\":\"$sha\""
|
||||
message="Updating $message"
|
||||
elif [ ! $type == "null" ]; then
|
||||
>&2 echo "Wrong type '$type'"
|
||||
return 1
|
||||
else
|
||||
message="Creating $message"
|
||||
fi
|
||||
|
||||
content=`base64 -i "$src"`
|
||||
data="{\"branch\":\"gh-pages\",\"message\":\"$message\",\"content\":\"$content\"$sha}"
|
||||
|
||||
echo "$data" | curl -s -k -H "Authorization: token $GITHUB_TOKEN" -H "Accept: application/vnd.github.v3.raw+json" -X PUT --data @- "https://api.github.com/repos/$GITHUB_REPOSITORY/contents/$path"
|
||||
}
|
||||
|
||||
function git_safe_upload_to_pages(){
|
||||
local path=$1
|
||||
local file="$2"
|
||||
local name=$(basename "$file")
|
||||
local size=`get_file_size "$file"`
|
||||
local upload_res=`git_upload_to_pages "$path" "$file"`
|
||||
if [ $? -ne 0 ]; then
|
||||
>&2 echo "ERROR: Failed to upload '$name' ($?)"
|
||||
return 1
|
||||
fi
|
||||
up_size=`echo "$upload_res" | jq -r '.content.size'`
|
||||
if [ $up_size -ne $size ]; then
|
||||
>&2 echo "ERROR: Uploaded size does not match! $up_size != $size"
|
||||
#git_delete_asset
|
||||
return 1
|
||||
fi
|
||||
echo "$upload_res" | jq -r '.content.download_url'
|
||||
return $?
|
||||
}
|
||||
|
||||
function merge_package_json(){
|
||||
local jsonLink=$1
|
||||
local jsonOut=$2
|
||||
local old_json=$OUTPUT_DIR/oldJson.json
|
||||
local merged_json=$OUTPUT_DIR/mergedJson.json
|
||||
|
||||
echo "Downloading previous JSON $jsonLink ..."
|
||||
curl -L -o "$old_json" "https://github.com/$GITHUB_REPOSITORY/releases/download/$jsonLink?access_token=$GITHUB_TOKEN" 2>/dev/null
|
||||
if [ $? -ne 0 ]; then echo "ERROR: Download Failed! $?"; exit 1; fi
|
||||
|
||||
echo "Creating new JSON ..."
|
||||
set +e
|
||||
stdbuf -oL python "$PACKAGE_JSON_MERGE" "$jsonOut" "$old_json" > "$merged_json"
|
||||
set -e
|
||||
|
||||
set -v
|
||||
if [ ! -s $merged_json ]; then
|
||||
rm -f "$merged_json"
|
||||
echo "Nothing to merge"
|
||||
else
|
||||
rm -f "$jsonOut"
|
||||
mv "$merged_json" "$jsonOut"
|
||||
echo "JSON data successfully merged"
|
||||
fi
|
||||
rm -f "$old_json"
|
||||
set +v
|
||||
}
|
||||
|
||||
set -e
|
||||
|
||||
##
|
||||
## PACKAGE ZIP
|
||||
##
|
||||
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
PKG_DIR="$OUTPUT_DIR/$PACKAGE_NAME"
|
||||
PACKAGE_ZIP="$PACKAGE_NAME.zip"
|
||||
|
||||
echo "Updating submodules ..."
|
||||
git -C "$GITHUB_WORKSPACE" submodule update --init --recursive > /dev/null 2>&1
|
||||
|
||||
mkdir -p "$PKG_DIR/tools"
|
||||
|
||||
# Copy all core files to the package folder
|
||||
echo "Copying files for packaging ..."
|
||||
cp -f "$GITHUB_WORKSPACE/boards.txt" "$PKG_DIR/"
|
||||
cp -f "$GITHUB_WORKSPACE/programmers.txt" "$PKG_DIR/"
|
||||
cp -Rf "$GITHUB_WORKSPACE/cores" "$PKG_DIR/"
|
||||
cp -Rf "$GITHUB_WORKSPACE/libraries" "$PKG_DIR/"
|
||||
cp -Rf "$GITHUB_WORKSPACE/variants" "$PKG_DIR/"
|
||||
cp -f "$GITHUB_WORKSPACE/tools/espota.exe" "$PKG_DIR/tools/"
|
||||
cp -f "$GITHUB_WORKSPACE/tools/espota.py" "$PKG_DIR/tools/"
|
||||
cp -f "$GITHUB_WORKSPACE/tools/esptool.py" "$PKG_DIR/tools/"
|
||||
cp -f "$GITHUB_WORKSPACE/tools/gen_esp32part.py" "$PKG_DIR/tools/"
|
||||
cp -f "$GITHUB_WORKSPACE/tools/gen_esp32part.exe" "$PKG_DIR/tools/"
|
||||
cp -Rf "$GITHUB_WORKSPACE/tools/partitions" "$PKG_DIR/tools/"
|
||||
cp -Rf "$GITHUB_WORKSPACE/tools/sdk" "$PKG_DIR/tools/"
|
||||
|
||||
# Remove unnecessary files in the package folder
|
||||
echo "Cleaning up folders ..."
|
||||
find "$PKG_DIR" -name '*.DS_Store' -exec rm -f {} \;
|
||||
find "$PKG_DIR" -name '*.git*' -type f -delete
|
||||
|
||||
# Replace tools locations in platform.txt
|
||||
echo "Generating platform.txt..."
|
||||
cat "$GITHUB_WORKSPACE/platform.txt" | \
|
||||
sed "s/version=.*/version=$ver$extent/g" | \
|
||||
sed 's/runtime.tools.xtensa-esp32-elf-gcc.path={runtime.platform.path}\/tools\/xtensa-esp32-elf//g' | \
|
||||
sed 's/tools.esptool_py.path={runtime.platform.path}\/tools\/esptool/tools.esptool_py.path=\{runtime.tools.esptool_py.path\}/g' \
|
||||
> "$PKG_DIR/platform.txt"
|
||||
|
||||
# Add header with version information
|
||||
echo "Generating core_version.h ..."
|
||||
ver_define=`echo $RELEASE_TAG | tr "[:lower:].\055" "[:upper:]_"`
|
||||
ver_hex=`git -C "$GITHUB_WORKSPACE" rev-parse --short=8 HEAD 2>/dev/null`
|
||||
echo \#define ARDUINO_ESP32_GIT_VER 0x$ver_hex > "$PKG_DIR/cores/esp32/core_version.h"
|
||||
echo \#define ARDUINO_ESP32_GIT_DESC `git -C "$GITHUB_WORKSPACE" describe --tags 2>/dev/null` >> "$PKG_DIR/cores/esp32/core_version.h"
|
||||
echo \#define ARDUINO_ESP32_RELEASE_$ver_define >> "$PKG_DIR/cores/esp32/core_version.h"
|
||||
echo \#define ARDUINO_ESP32_RELEASE \"$ver_define\" >> "$PKG_DIR/cores/esp32/core_version.h"
|
||||
|
||||
# Compress package folder
|
||||
echo "Creating ZIP ..."
|
||||
pushd "$OUTPUT_DIR" >/dev/null
|
||||
zip -qr "$PACKAGE_ZIP" "$PACKAGE_NAME"
|
||||
if [ $? -ne 0 ]; then echo "ERROR: Failed to create $PACKAGE_ZIP ($?)"; exit 1; fi
|
||||
|
||||
# Calculate SHA-256
|
||||
echo "Calculating SHA sum ..."
|
||||
PACKAGE_PATH="$OUTPUT_DIR/$PACKAGE_ZIP"
|
||||
PACKAGE_SHA=`shasum -a 256 "$PACKAGE_ZIP" | cut -f 1 -d ' '`
|
||||
PACKAGE_SIZE=`get_file_size "$PACKAGE_ZIP"`
|
||||
popd >/dev/null
|
||||
rm -rf "$PKG_DIR"
|
||||
echo "'$PACKAGE_ZIP' Created! Size: $PACKAGE_SIZE, SHA-256: $PACKAGE_SHA"
|
||||
echo
|
||||
|
||||
# Upload package to release page
|
||||
echo "Uploading package to release page ..."
|
||||
PACKAGE_URL=`git_safe_upload_asset "$PACKAGE_PATH"`
|
||||
echo "Package Uploaded"
|
||||
echo "Download URL: $PACKAGE_URL"
|
||||
echo
|
||||
|
||||
##
|
||||
## PACKAGE JSON
|
||||
##
|
||||
|
||||
# Construct JQ argument with package data
|
||||
jq_arg=".packages[0].platforms[0].version = \"$RELEASE_TAG\" | \
|
||||
.packages[0].platforms[0].url = \"$PACKAGE_URL\" |\
|
||||
.packages[0].platforms[0].archiveFileName = \"$PACKAGE_ZIP\" |\
|
||||
.packages[0].platforms[0].size = \"$PACKAGE_SIZE\" |\
|
||||
.packages[0].platforms[0].checksum = \"SHA-256:$PACKAGE_SHA\""
|
||||
|
||||
# Generate package JSONs
|
||||
echo "Genarating $PACKAGE_JSON_DEV ..."
|
||||
cat "$PACKAGE_JSON_TEMPLATE" | jq "$jq_arg" > "$OUTPUT_DIR/$PACKAGE_JSON_DEV"
|
||||
if [ "$RELEASE_PRE" == "false" ]; then
|
||||
echo "Genarating $PACKAGE_JSON_REL ..."
|
||||
cat "$PACKAGE_JSON_TEMPLATE" | jq "$jq_arg" > "$OUTPUT_DIR/$PACKAGE_JSON_REL"
|
||||
fi
|
||||
|
||||
# Figure out the last release or pre-release
|
||||
echo "Getting previous releases ..."
|
||||
releasesJson=`curl -sH "Authorization: token $GITHUB_TOKEN" "https://api.github.com/repos/$GITHUB_REPOSITORY/releases" 2>/dev/null`
|
||||
if [ $? -ne 0 ]; then echo "ERROR: Get Releases Failed! ($?)"; exit 1; fi
|
||||
|
||||
set +e
|
||||
prev_release=$(echo "$releasesJson" | jq -e -r '. | map(select(.draft == false and .prerelease == false)) | sort_by(.created_at | - fromdateiso8601) | .[0].tag_name')
|
||||
prev_any_release=$(echo "$releasesJson" | jq -e -r '. | map(select(.draft == false)) | sort_by(.created_at | - fromdateiso8601) | .[0].tag_name')
|
||||
shopt -s nocasematch
|
||||
if [ "$prev_any_release" == "$RELEASE_TAG" ]; then
|
||||
prev_release=$(echo "$releasesJson" | jq -e -r '. | map(select(.draft == false and .prerelease == false)) | sort_by(.created_at | - fromdateiso8601) | .[1].tag_name')
|
||||
prev_any_release=$(echo "$releasesJson" | jq -e -r '. | map(select(.draft == false)) | sort_by(.created_at | - fromdateiso8601) | .[1].tag_name')
|
||||
fi
|
||||
COMMITS_SINCE_RELEASE="$prev_any_release"
|
||||
shopt -u nocasematch
|
||||
set -e
|
||||
|
||||
# Merge package JSONs with previous releases
|
||||
if [ ! -z "$prev_any_release" ] && [ "$prev_any_release" != "null" ]; then
|
||||
echo "Merging with JSON from $prev_any_release ..."
|
||||
merge_package_json "$prev_any_release/$PACKAGE_JSON_DEV" "$OUTPUT_DIR/$PACKAGE_JSON_DEV"
|
||||
fi
|
||||
|
||||
if [ "$RELEASE_PRE" == "false" ]; then
|
||||
COMMITS_SINCE_RELEASE="$prev_release"
|
||||
if [ ! -z "$prev_release" ] && [ "$prev_release" != "null" ]; then
|
||||
echo "Merging with JSON from $prev_release ..."
|
||||
merge_package_json "$prev_release/$PACKAGE_JSON_REL" "$OUTPUT_DIR/$PACKAGE_JSON_REL"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Previous Release: $prev_release"
|
||||
echo "Previous (any)release: $prev_any_release"
|
||||
echo
|
||||
|
||||
# Upload package JSONs
|
||||
echo "Uploading $PACKAGE_JSON_DEV ..."
|
||||
echo "Download URL: "`git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_DEV"`
|
||||
echo "Pages URL: "`git_safe_upload_to_pages "$PACKAGE_JSON_DEV" "$OUTPUT_DIR/$PACKAGE_JSON_DEV"`
|
||||
echo
|
||||
if [ "$RELEASE_PRE" == "false" ]; then
|
||||
echo "Uploading $PACKAGE_JSON_REL ..."
|
||||
echo "Download URL: "`git_safe_upload_asset "$OUTPUT_DIR/$PACKAGE_JSON_REL"`
|
||||
echo "Pages URL: "`git_safe_upload_to_pages "$PACKAGE_JSON_REL" "$OUTPUT_DIR/$PACKAGE_JSON_REL"`
|
||||
echo
|
||||
fi
|
||||
|
||||
##
|
||||
## RELEASE NOTES
|
||||
##
|
||||
|
||||
# Create release notes
|
||||
echo "Preparing release notes ..."
|
||||
releaseNotes=""
|
||||
|
||||
# Process annotated tags
|
||||
relNotesRaw=`git -C "$GITHUB_WORKSPACE" show -s --format=%b $RELEASE_TAG`
|
||||
readarray -t msgArray <<<"$relNotesRaw"
|
||||
arrLen=${#msgArray[@]}
|
||||
if [ $arrLen > 3 ] && [ "${msgArray[0]:0:3}" == "tag" ]; then
|
||||
ind=3
|
||||
while [ $ind -lt $arrLen ]; do
|
||||
if [ $ind -eq 3 ]; then
|
||||
releaseNotes="#### ${msgArray[ind]}"
|
||||
releaseNotes+=$'\r\n'
|
||||
else
|
||||
oneLine="$(echo -e "${msgArray[ind]}" | sed -e 's/^[[:space:]]*//')"
|
||||
if [ ${#oneLine} -gt 0 ]; then
|
||||
if [ "${oneLine:0:2}" == "* " ]; then oneLine=$(echo ${oneLine/\*/-}); fi
|
||||
if [ "${oneLine:0:2}" != "- " ]; then releaseNotes+="- "; fi
|
||||
releaseNotes+="$oneLine"
|
||||
releaseNotes+=$'\r\n'
|
||||
fi
|
||||
fi
|
||||
let ind=$ind+1
|
||||
done
|
||||
fi
|
||||
|
||||
# Append Commit Messages
|
||||
if [ ! -z "$COMMITS_SINCE_RELEASE" ] && [ "$COMMITS_SINCE_RELEASE" != "null" ]; then
|
||||
echo "Getting commits since $COMMITS_SINCE_RELEASE ..."
|
||||
commitFile=$OUTPUT_DIR/commits.txt
|
||||
git -C "$GITHUB_WORKSPACE" log --oneline $COMMITS_SINCE_RELEASE.. > "$OUTPUT_DIR/commits.txt"
|
||||
releaseNotes+=$'\r\n##### Commits\r\n'
|
||||
IFS=$'\n'
|
||||
for next in `cat $commitFile`
|
||||
do
|
||||
IFS=' ' read -r commitId commitMsg <<< "$next"
|
||||
commitLine="- [$commitId](https://github.com/$GITHUB_REPOSITORY/commit/$commitId) $commitMsg"
|
||||
releaseNotes+="$commitLine"
|
||||
releaseNotes+=$'\r\n'
|
||||
done
|
||||
rm -f $commitFile
|
||||
fi
|
||||
|
||||
# Prepend the original release body
|
||||
if [ "${RELEASE_BODY: -1}" == $'\r' ]; then
|
||||
RELEASE_BODY="${RELEASE_BODY:0:-1}"
|
||||
else
|
||||
RELEASE_BODY="$RELEASE_BODY"
|
||||
fi
|
||||
RELEASE_BODY+=$'\r\n'
|
||||
releaseNotes="$RELEASE_BODY$releaseNotes"
|
||||
|
||||
# Update release page
|
||||
echo "Updating release notes ..."
|
||||
releaseNotes=$(printf '%s' "$releaseNotes" | python -c 'import json,sys; print(json.dumps(sys.stdin.read()))')
|
||||
releaseNotes=${releaseNotes:1:-1}
|
||||
curlData="{\"body\": \"$releaseNotes\"}"
|
||||
releaseData=`curl --data "$curlData" "https://api.github.com/repos/$GITHUB_REPOSITORY/releases/$RELEASE_ID?access_token=$GITHUB_TOKEN" 2>/dev/null`
|
||||
if [ $? -ne 0 ]; then echo "ERROR: Updating Release Failed: $?"; exit 1; fi
|
||||
echo "Release notes successfully updated"
|
||||
echo
|
||||
|
||||
##
|
||||
## SUBMODULE VERSIONS
|
||||
##
|
||||
|
||||
# Upload submodules versions
|
||||
echo "Generating submodules.txt ..."
|
||||
git -C "$GITHUB_WORKSPACE" submodule status > "$OUTPUT_DIR/submodules.txt"
|
||||
echo "Uploading submodules.txt ..."
|
||||
echo "Download URL: "`git_safe_upload_asset "$OUTPUT_DIR/submodules.txt"`
|
||||
echo ""
|
||||
set +e
|
||||
|
||||
##
|
||||
## DONE
|
||||
##
|
||||
echo "DONE!"
|
64
.github/stale.yml
vendored
Normal file
64
.github/stale.yml
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
# Configuration for probot-stale - https://github.com/probot/stale
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request becomes stale
|
||||
daysUntilStale: 60
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
|
||||
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
|
||||
daysUntilClose: 14
|
||||
|
||||
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
|
||||
onlyLabels: []
|
||||
|
||||
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
|
||||
exemptLabels:
|
||||
- pinned
|
||||
- security
|
||||
- "to be implemented"
|
||||
- "for reference"
|
||||
- "move to PR"
|
||||
- "enhancement"
|
||||
|
||||
# Set to true to ignore issues in a project (defaults to false)
|
||||
exemptProjects: false
|
||||
|
||||
# Set to true to ignore issues in a milestone (defaults to false)
|
||||
exemptMilestones: false
|
||||
|
||||
# Set to true to ignore issues with an assignee (defaults to false)
|
||||
exemptAssignees: false
|
||||
|
||||
# Label to use when marking as stale
|
||||
staleLabel: stale
|
||||
|
||||
# Comment to post when marking as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
[STALE_SET] This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed in 14 days if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
|
||||
# Comment to post when removing the stale label.
|
||||
unmarkComment: >
|
||||
[STALE_CLR] This issue has been removed from the stale queue. Please ensure activity to keep it openin the future.
|
||||
|
||||
# Comment to post when closing a stale Issue or Pull Request.
|
||||
closeComment: >
|
||||
[STALE_DEL] This stale issue has been automatically closed. Thank you for your contributions.
|
||||
|
||||
# Limit the number of actions per hour, from 1-30. Default is 30
|
||||
limitPerRun: 30
|
||||
|
||||
# Limit to only `issues` or `pulls`
|
||||
only: issues
|
||||
|
||||
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
|
||||
# pulls:
|
||||
# daysUntilStale: 30
|
||||
# markComment: >
|
||||
# This pull request has been automatically marked as stale because it has not had
|
||||
# recent activity. It will be closed if no further activity occurs. Thank you
|
||||
# for your contributions.
|
||||
|
||||
# issues:
|
||||
# exemptLabels:
|
||||
# - confirmed
|
21
.github/workflows/gh-pages.yml
vendored
Normal file
21
.github/workflows/gh-pages.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
name: GitHub Pages CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- 'README.md'
|
||||
- 'docs/**'
|
||||
|
||||
jobs:
|
||||
|
||||
build-pages:
|
||||
name: Build GitHub Pages
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Copy Files
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: bash ./.github/scripts/on-pages.sh
|
58
.github/workflows/push.yml
vendored
Normal file
58
.github/workflows/push.yml
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
name: ESP32 Arduino CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- release/*
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
|
||||
# Ubuntu
|
||||
build-arduino-linux:
|
||||
name: Arduino ${{ matrix.chunk }} on ubuntu-latest
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
chunk: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Build Sketches
|
||||
run: bash ./.github/scripts/on-push.sh ${{ matrix.chunk }} 15
|
||||
|
||||
# Windows and MacOS
|
||||
build-arduino-win-mac:
|
||||
name: Arduino on ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows-latest, macOS-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Build Sketches
|
||||
run: bash ./.github/scripts/on-push.sh
|
||||
|
||||
# PlatformIO on Windows, Ubuntu and Mac
|
||||
build-platformio:
|
||||
name: PlatformIO on ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Build Sketches
|
||||
run: bash ./.github/scripts/on-push.sh 1 1 #equal and non-zero to trigger PIO
|
20
.github/workflows/release.yml
vendored
Normal file
20
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
name: ESP32 Arduino Release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: published
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Publish Release
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Build Release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: bash ./.github/scripts/on-release.sh
|
11
.gitignore
vendored
11
.gitignore
vendored
@ -1,7 +1,18 @@
|
||||
tools/xtensa-esp32-elf
|
||||
tools/xtensa-esp32s2-elf
|
||||
tools/dist
|
||||
tools/esptool
|
||||
tools/esptool.exe
|
||||
tools/mkspiffs/mkspiffs
|
||||
tools/mkspiffs/mkspiffs.exe
|
||||
.DS_Store
|
||||
|
||||
#Ignore files built by Visual Studio/Visual Micro
|
||||
[Dd]ebug*/
|
||||
[Rr]elease*/
|
||||
.vs/
|
||||
__vm/
|
||||
*.vcxproj*
|
||||
.vscode/
|
||||
platform.sloeber.txt
|
||||
boards.sloeber.txt
|
||||
|
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -1,6 +0,0 @@
|
||||
[submodule "libraries/BLE"]
|
||||
path = libraries/BLE
|
||||
url = https://github.com/nkolban/ESP32_BLE_Arduino.git
|
||||
[submodule "libraries/AzureIoT"]
|
||||
path = libraries/AzureIoT
|
||||
url = https://github.com/VSChina/ESP32_AzureIoT_Arduino
|
||||
|
47
.travis.yml
47
.travis.yml
@ -1,28 +1,47 @@
|
||||
sudo: false
|
||||
|
||||
language: python
|
||||
python:
|
||||
- "2.7"
|
||||
|
||||
os:
|
||||
- linux
|
||||
|
||||
env:
|
||||
global:
|
||||
- secure: "l/4Dt+KQ/mACtGAHDUsPr66fUte840PZoQ4xpPikqWZI0uARu4l+Ym7+sHinnT6fBqrj8AJeBYGz4nFa8NK4LutZn9mSD40w+sxl0wSV4oHV8rzKe3Cd8+sMG3+o33yWoikMNjSvqa73Q0rm+SgrlInNdZbuAyixL+a2alaWSnGPm4F2xwUGj+S33TOy5P/Xp77CYtCV5S8vzyk/eEdNhoF0GYePJVdfuzCOUjXMyT5OWxORkzzQ7Hnn/Ka/RDfV8Si4HgujLQBrK5q6iPnNBFqBSqilYBepSMn4opnOBpIm0SCgePz7XQEFC83buA7GUcnCnfg38bf+dCwHaODf1d1PmqVRYt2QmfinexXtM4afAtL0iBUDtvrfnXHzwW9w82VeZhpbJSVh9DUQvB0IlsZeCz9J9PUBAi3N+SMX+9l+BomYwRUlPuKY+Ef2JKk9q6mxtUkky5R0daAlVxEhpVdQks1rT+T+NMoDMemxQ3SKEiqAHh6EgHecruszffmZ71uLX9MpERpew0qN+UFiafws+jkTjx+3yF9yut0Hf9sMbeAYzzkGzRqJTUEBJ6B29Cql8M0yRXCNN/8wuuTHhG8esstozga4ZQoIVrq7mEAgup376PTcNfr1+imbbWVQ7lJdYIuDe6OS5V3OX6np11vgK/DbhfyzvQv9Z1zAGnM="
|
||||
- REMOTE_URL=https://github.com/$TRAVIS_REPO_SLUG/releases/download/$TRAVIS_TAG
|
||||
git:
|
||||
depth: false
|
||||
|
||||
script:
|
||||
- bash $TRAVIS_BUILD_DIR/tools/build.sh
|
||||
before_install:
|
||||
- git submodule update --init --recursive
|
||||
|
||||
deploy:
|
||||
provider: script
|
||||
skip_cleanup: true
|
||||
script: bash $TRAVIS_BUILD_DIR/tools/deploy.sh -t$TRAVIS_TAG -a$ESP32_GITHUB_TOKEN -s$TRAVIS_REPO_SLUG -drelease
|
||||
stages:
|
||||
- build
|
||||
- deploy
|
||||
|
||||
on:
|
||||
tags: true
|
||||
jobs:
|
||||
include:
|
||||
|
||||
- name: "Build Arduino 0"
|
||||
if: tag IS blank AND (type = pull_request OR (type = push AND branch = master))
|
||||
stage: build
|
||||
script: $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh 0 10
|
||||
|
||||
- name: "Build Arduino 1"
|
||||
if: tag IS blank AND (type = pull_request OR (type = push AND branch = master))
|
||||
stage: build
|
||||
script: $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh 1 10
|
||||
|
||||
- name: "Build Arduino 2"
|
||||
if: tag IS blank AND (type = pull_request OR (type = push AND branch = master))
|
||||
stage: build
|
||||
script: $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh 2 10
|
||||
|
||||
- name: "Build Arduino 3"
|
||||
if: tag IS blank AND (type = pull_request OR (type = push AND branch = master))
|
||||
stage: build
|
||||
script: $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh 3 10
|
||||
|
||||
- name: "Build PlatformIO"
|
||||
if: tag IS blank AND (type = pull_request OR (type = push AND branch = master))
|
||||
stage: build
|
||||
script: $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh 1 1
|
||||
|
||||
notifications:
|
||||
email:
|
||||
|
@ -3,6 +3,7 @@ set(CORE_SRCS
|
||||
cores/esp32/cbuf.cpp
|
||||
cores/esp32/esp32-hal-adc.c
|
||||
cores/esp32/esp32-hal-bt.c
|
||||
cores/esp32/esp32-hal-cpu.c
|
||||
cores/esp32/esp32-hal-dac.c
|
||||
cores/esp32/esp32-hal-gpio.c
|
||||
cores/esp32/esp32-hal-i2c.c
|
||||
@ -14,19 +15,25 @@ set(CORE_SRCS
|
||||
cores/esp32/esp32-hal-spi.c
|
||||
cores/esp32/esp32-hal-time.c
|
||||
cores/esp32/esp32-hal-timer.c
|
||||
cores/esp32/esp32-hal-tinyusb.c
|
||||
cores/esp32/esp32-hal-touch.c
|
||||
cores/esp32/esp32-hal-uart.c
|
||||
cores/esp32/esp32-hal-rmt.c
|
||||
cores/esp32/Esp.cpp
|
||||
cores/esp32/FunctionalInterrupt.cpp
|
||||
cores/esp32/HardwareSerial.cpp
|
||||
cores/esp32/IPAddress.cpp
|
||||
cores/esp32/IPv6Address.cpp
|
||||
cores/esp32/libb64/cdecode.c
|
||||
cores/esp32/libb64/cencode.c
|
||||
cores/esp32/main.cpp
|
||||
cores/esp32/MD5Builder.cpp
|
||||
cores/esp32/Print.cpp
|
||||
cores/esp32/stdlib_noniso.c
|
||||
cores/esp32/Stream.cpp
|
||||
cores/esp32/StreamString.cpp
|
||||
cores/esp32/USB.cpp
|
||||
cores/esp32/USBCDC.cpp
|
||||
cores/esp32/wiring_pulse.c
|
||||
cores/esp32/wiring_shift.c
|
||||
cores/esp32/WMath.cpp
|
||||
@ -38,11 +45,14 @@ set(LIBRARY_SRCS
|
||||
libraries/AsyncUDP/src/AsyncUDP.cpp
|
||||
libraries/BluetoothSerial/src/BluetoothSerial.cpp
|
||||
libraries/DNSServer/src/DNSServer.cpp
|
||||
libraries/EEPROM/EEPROM.cpp
|
||||
libraries/EEPROM/src/EEPROM.cpp
|
||||
libraries/ESPmDNS/src/ESPmDNS.cpp
|
||||
libraries/FFat/src/FFat.cpp
|
||||
libraries/FS/src/FS.cpp
|
||||
libraries/FS/src/vfs_api.cpp
|
||||
libraries/HTTPClient/src/HTTPClient.cpp
|
||||
libraries/HTTPUpdate/src/HTTPUpdate.cpp
|
||||
libraries/LITTLEFS/src/LITTLEFS.cpp
|
||||
libraries/NetBIOS/src/NetBIOS.cpp
|
||||
libraries/Preferences/src/Preferences.cpp
|
||||
libraries/SD_MMC/src/SD_MMC.cpp
|
||||
@ -65,6 +75,7 @@ set(LIBRARY_SRCS
|
||||
libraries/WiFi/src/WiFi.cpp
|
||||
libraries/WiFi/src/WiFiGeneric.cpp
|
||||
libraries/WiFi/src/WiFiMulti.cpp
|
||||
libraries/WiFi/src/WiFiProv.cpp
|
||||
libraries/WiFi/src/WiFiScan.cpp
|
||||
libraries/WiFi/src/WiFiServer.cpp
|
||||
libraries/WiFi/src/WiFiSTA.cpp
|
||||
@ -72,66 +83,6 @@ set(LIBRARY_SRCS
|
||||
libraries/Wire/src/Wire.cpp
|
||||
)
|
||||
|
||||
set(AZURE_SRCS
|
||||
libraries/AzureIoT/src/az_iot/azureiotcerts.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/pal/agenttime.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/pal/dns_async.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/pal/freertos/lock.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/pal/freertos/threadapi.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/pal/freertos/tickcounter.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/pal/lwip/sntp_lwip.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/pal/socket_async.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/pal/src/platform_openssl_compact.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/pal/src/tlsio_openssl_compact.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/pal/tlsio_options.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/base64.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/buffer.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/connection_string_parser.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/consolelogger.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/constbuffer.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/constmap.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/crt_abstractions.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/doublylinkedlist.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/gballoc.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/gb_stdio.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/gb_time.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/hmac.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/hmacsha256.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/httpapiex.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/httpapiexsas.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/httpheaders.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/http_proxy_io.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/map.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/optionhandler.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/sastoken.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/sha1.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/sha224.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/sha384-512.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/singlylinkedlist.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/strings.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/string_tokenizer.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/urlencode.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/usha.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/vector.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/xio.c
|
||||
libraries/AzureIoT/src/az_iot/c-utility/src/xlogging.c
|
||||
libraries/AzureIoT/src/az_iot/iothub_client/src/blob.c
|
||||
libraries/AzureIoT/src/az_iot/iothub_client/src/iothub_client_authorization.c
|
||||
libraries/AzureIoT/src/az_iot/iothub_client/src/iothub_client.c
|
||||
libraries/AzureIoT/src/az_iot/iothub_client/src/iothub_client_ll.c
|
||||
libraries/AzureIoT/src/az_iot/iothub_client/src/iothub_client_retry_control.c
|
||||
libraries/AzureIoT/src/az_iot/iothub_client/src/iothub_message.c
|
||||
libraries/AzureIoT/src/az_iot/iothub_client/src/iothubtransport.c
|
||||
libraries/AzureIoT/src/az_iot/iothub_client/src/iothubtransportmqtt.c
|
||||
libraries/AzureIoT/src/az_iot/iothub_client/src/iothubtransport_mqtt_common.c
|
||||
libraries/AzureIoT/src/az_iot/iothub_client/src/version.c
|
||||
libraries/AzureIoT/src/az_iot/umqtt/src/mqtt_client.c
|
||||
libraries/AzureIoT/src/az_iot/umqtt/src/mqtt_codec.c
|
||||
libraries/AzureIoT/src/az_iot/umqtt/src/mqtt_message.c
|
||||
libraries/AzureIoT/src/AzureIotHub.cpp
|
||||
libraries/AzureIoT/src/Esp32MQTTClient.cpp
|
||||
)
|
||||
|
||||
set(BLE_SRCS
|
||||
libraries/BLE/src/BLE2902.cpp
|
||||
libraries/BLE/src/BLE2904.cpp
|
||||
@ -145,6 +96,8 @@ set(BLE_SRCS
|
||||
libraries/BLE/src/BLEDescriptor.cpp
|
||||
libraries/BLE/src/BLEDescriptorMap.cpp
|
||||
libraries/BLE/src/BLEDevice.cpp
|
||||
libraries/BLE/src/BLEEddystoneTLM.cpp
|
||||
libraries/BLE/src/BLEEddystoneURL.cpp
|
||||
libraries/BLE/src/BLEExceptions.cpp
|
||||
libraries/BLE/src/BLEHIDDevice.cpp
|
||||
libraries/BLE/src/BLERemoteCharacteristic.cpp
|
||||
@ -162,21 +115,23 @@ set(BLE_SRCS
|
||||
libraries/BLE/src/GeneralUtils.cpp
|
||||
)
|
||||
|
||||
set(COMPONENT_SRCS ${CORE_SRCS} ${LIBRARY_SRCS} ${AZURE_SRCS} ${BLE_SRCS})
|
||||
|
||||
set(COMPONENT_ADD_INCLUDEDIRS
|
||||
set(includedirs
|
||||
variants/esp32/
|
||||
cores/esp32/
|
||||
libraries/ArduinoOTA/src
|
||||
libraries/AsyncUDP/src
|
||||
libraries/AzureIoT/src
|
||||
libraries/BLE/src
|
||||
libraries/BluetoothSerial/src
|
||||
libraries/DNSServer/src
|
||||
libraries/EEPROM/src
|
||||
libraries/ESP32/src
|
||||
libraries/ESPmDNS/src
|
||||
libraries/FFat/src
|
||||
libraries/FS/src
|
||||
libraries/HTTPClient/src
|
||||
libraries/HTTPUpdate/src
|
||||
libraries/LITTLEFS/src
|
||||
libraries/NetBIOS/src
|
||||
libraries/Preferences/src
|
||||
libraries/SD_MMC/src
|
||||
@ -192,9 +147,16 @@ set(COMPONENT_ADD_INCLUDEDIRS
|
||||
libraries/Wire/src
|
||||
)
|
||||
|
||||
set(COMPONENT_PRIV_INCLUDEDIRS cores/esp32/libb64)
|
||||
set(srcs ${CORE_SRCS} ${LIBRARY_SRCS} ${BLE_SRCS})
|
||||
set(priv_includes cores/esp32/libb64)
|
||||
set(requires spi_flash mbedtls mdns esp_adc_cal)
|
||||
set(priv_requires fatfs nvs_flash app_update spiffs bootloader_support openssl bt tinyusb main)
|
||||
|
||||
set(COMPONENT_REQUIRES spi_flash mbedtls mdns ethernet)
|
||||
set(COMPONENT_PRIV_REQUIRES fatfs nvs_flash app_update spiffs bootloader_support openssl)
|
||||
idf_component_register(INCLUDE_DIRS ${includedirs} PRIV_INCLUDE_DIRS ${priv_includes} SRCS ${srcs} REQUIRES ${requires} PRIV_REQUIRES ${priv_requires})
|
||||
|
||||
register_component()
|
||||
if(IDF_TARGET STREQUAL "esp32")
|
||||
target_compile_options(${COMPONENT_TARGET} PUBLIC -DARDUINO=10812 -DARDUINO_ESP32_DEV -DARDUINO_ARCH_ESP32 -DARDUINO_BOARD="ESP32_DEV" -DARDUINO_VARIANT="esp32" -DESP32)
|
||||
endif()
|
||||
if(IDF_TARGET STREQUAL "esp32s2")
|
||||
target_compile_options(${COMPONENT_TARGET} PUBLIC -DARDUINO=10812 -DARDUINO_ESP32S2_DEV -DARDUINO_ARCH_ESP32 -DARDUINO_BOARD="ESP32S2_DEV" -DARDUINO_VARIANT="esp32s2" -DESP32)
|
||||
endif()
|
||||
|
@ -5,7 +5,7 @@ config ENABLE_ARDUINO_DEPENDS
|
||||
select LWIP_SO_RCVBUF
|
||||
select ETHERNET
|
||||
select WIFI_ENABLED
|
||||
select ESP32_PHY_CALIBRATION_AND_DATA_STORAGE
|
||||
select ESP32_PHY_CALIBRATION_AND_DATA_STORAGE if IDF_TARGET_ESP32
|
||||
select MEMMAP_SMP
|
||||
default "y"
|
||||
|
||||
@ -19,6 +19,79 @@ config AUTOSTART_ARDUINO
|
||||
If disabled, you can call initArduino() to run any preparations
|
||||
required by the framework
|
||||
|
||||
choice ARDUINO_RUNNING_CORE
|
||||
bool "Core on which Arduino's setup() and loop() are running"
|
||||
default ARDUINO_RUN_CORE1
|
||||
help
|
||||
Select on which core Arduino's setup() and loop() functions run
|
||||
|
||||
config ARDUINO_RUN_CORE0
|
||||
bool "CORE 0"
|
||||
config ARDUINO_RUN_CORE1
|
||||
bool "CORE 1"
|
||||
config ARDUINO_RUN_NO_AFFINITY
|
||||
bool "BOTH"
|
||||
|
||||
endchoice
|
||||
|
||||
config ARDUINO_RUNNING_CORE
|
||||
int
|
||||
default 0 if ARDUINO_RUN_CORE0
|
||||
default 1 if ARDUINO_RUN_CORE1
|
||||
default -1 if ARDUINO_RUN_NO_AFFINITY
|
||||
|
||||
choice ARDUINO_EVENT_RUNNING_CORE
|
||||
bool "Core on which Arduino's event handler is running"
|
||||
default ARDUINO_EVENT_RUN_CORE1
|
||||
help
|
||||
Select on which core Arduino's WiFi.onEvent() run
|
||||
|
||||
config ARDUINO_EVENT_RUN_CORE0
|
||||
bool "CORE 0"
|
||||
config ARDUINO_EVENT_RUN_CORE1
|
||||
bool "CORE 1"
|
||||
config ARDUINO_EVENT_RUN_NO_AFFINITY
|
||||
bool "BOTH"
|
||||
|
||||
endchoice
|
||||
|
||||
config ARDUINO_EVENT_RUNNING_CORE
|
||||
int
|
||||
default 0 if ARDUINO_EVENT_RUN_CORE0
|
||||
default 1 if ARDUINO_EVENT_RUN_CORE1
|
||||
default -1 if ARDUINO_EVENT_RUN_NO_AFFINITY
|
||||
|
||||
choice ARDUINO_UDP_RUNNING_CORE
|
||||
bool "Core on which Arduino's UDP is running"
|
||||
default ARDUINO_UDP_RUN_CORE1
|
||||
help
|
||||
Select on which core Arduino's UDP run
|
||||
|
||||
config ARDUINO_UDP_RUN_CORE0
|
||||
bool "CORE 0"
|
||||
config ARDUINO_UDP_RUN_CORE1
|
||||
bool "CORE 1"
|
||||
config ARDUINO_UDP_RUN_NO_AFFINITY
|
||||
bool "BOTH"
|
||||
|
||||
endchoice
|
||||
|
||||
config ARDUINO_UDP_RUNNING_CORE
|
||||
int
|
||||
default 0 if ARDUINO_UDP_RUN_CORE0
|
||||
default 1 if ARDUINO_UDP_RUN_CORE1
|
||||
default -1 if ARDUINO_UDP_RUN_NO_AFFINITY
|
||||
|
||||
config ARDUINO_ISR_IRAM
|
||||
bool "Run interrupts in IRAM"
|
||||
default "n"
|
||||
help
|
||||
Enabling this option will Attach all interrupts with the IRAm flag.
|
||||
It will also make some HAL function, like, digitalRead/Write and more
|
||||
be loaded into IRAM for access inside ISRs.
|
||||
Beware that this is a very dangerous setting. Enable it only if you
|
||||
are fully aware of the consequences.
|
||||
|
||||
config DISABLE_HAL_LOCKS
|
||||
bool "Disable mutex locks for HAL"
|
||||
default "n"
|
||||
@ -90,6 +163,8 @@ config ARDUHAL_PARTITION_SCHEME_MINIMAL
|
||||
bool "Minimal (for 2MB FLASH)"
|
||||
config ARDUHAL_PARTITION_SCHEME_NO_OTA
|
||||
bool "No OTA (for large apps)"
|
||||
config ARDUHAL_PARTITION_SCHEME_HUGE_APP
|
||||
bool "Huge App (for very large apps)"
|
||||
config ARDUHAL_PARTITION_SCHEME_MIN_SPIFFS
|
||||
bool "Minimal SPIFFS (for large apps with OTA)"
|
||||
endchoice
|
||||
@ -99,6 +174,7 @@ config ARDUHAL_PARTITION_SCHEME
|
||||
default "default" if ARDUHAL_PARTITION_SCHEME_DEFAULT
|
||||
default "minimal" if ARDUHAL_PARTITION_SCHEME_MINIMAL
|
||||
default "no_ota" if ARDUHAL_PARTITION_SCHEME_NO_OTA
|
||||
default "huge_app" if ARDUHAL_PARTITION_SCHEME_HUGE_APP
|
||||
default "min_spiffs" if ARDUHAL_PARTITION_SCHEME_MIN_SPIFFS
|
||||
|
||||
|
||||
@ -106,8 +182,153 @@ config AUTOCONNECT_WIFI
|
||||
bool "Autoconnect WiFi on boot"
|
||||
default "n"
|
||||
depends on AUTOSTART_ARDUINO
|
||||
select ARDUINO_SELECTIVE_WiFi
|
||||
help
|
||||
If enabled, WiFi will connect to the last used SSID (if station was enabled),
|
||||
else connection will be started only after calling WiFi.begin(ssid, password)
|
||||
|
||||
config ARDUINO_SELECTIVE_COMPILATION
|
||||
bool "Include only specific Arduino libraries"
|
||||
default n
|
||||
|
||||
config ARDUINO_SELECTIVE_ArduinoOTA
|
||||
bool "Enable ArduinoOTA"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
select ARDUINO_SELECTIVE_WiFi
|
||||
select ARDUINO_SELECTIVE_ESPmDNS
|
||||
default y
|
||||
|
||||
config ARDUINO_SELECTIVE_AsyncUDP
|
||||
bool "Enable AsyncUDP"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
default y
|
||||
|
||||
config ARDUINO_SELECTIVE_AzureIoT
|
||||
bool "Enable AzureIoT"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
select ARDUINO_SELECTIVE_HTTPClient
|
||||
default y
|
||||
|
||||
config ARDUINO_SELECTIVE_BLE
|
||||
bool "Enable BLE"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
default y
|
||||
|
||||
config ARDUINO_SELECTIVE_BluetoothSerial
|
||||
bool "Enable BluetoothSerial"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
default y
|
||||
|
||||
config ARDUINO_SELECTIVE_DNSServer
|
||||
bool "Enable DNSServer"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
select ARDUINO_SELECTIVE_WiFi
|
||||
default y
|
||||
|
||||
config ARDUINO_SELECTIVE_EEPROM
|
||||
bool "Enable EEPROM"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
default y
|
||||
|
||||
config ARDUINO_SELECTIVE_ESP32
|
||||
bool "Enable ESP32"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
default y
|
||||
|
||||
config ARDUINO_SELECTIVE_ESPmDNS
|
||||
bool "Enable ESPmDNS"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
select ARDUINO_SELECTIVE_WiFi
|
||||
default y
|
||||
|
||||
config ARDUINO_SELECTIVE_FFat
|
||||
bool "Enable FFat"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
select ARDUINO_SELECTIVE_FS
|
||||
default y
|
||||
|
||||
config ARDUINO_SELECTIVE_FS
|
||||
bool "Enable FS"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
default y
|
||||
|
||||
config ARDUINO_SELECTIVE_HTTPClient
|
||||
bool "Enable HTTPClient"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
select ARDUINO_SELECTIVE_WiFi
|
||||
select ARDUINO_SELECTIVE_WiFiClientSecure
|
||||
default y
|
||||
|
||||
config ARDUINO_SELECTIVE_NetBIOS
|
||||
bool "Enable NetBIOS"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
select ARDUINO_SELECTIVE_WiFi
|
||||
default y
|
||||
|
||||
config ARDUINO_SELECTIVE_Preferences
|
||||
bool "Enable Preferences"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
default y
|
||||
|
||||
config ARDUINO_SELECTIVE_SD
|
||||
bool "Enable SD"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
select ARDUINO_SELECTIVE_FS
|
||||
default y
|
||||
|
||||
config ARDUINO_SELECTIVE_SD_MMC
|
||||
bool "Enable SD_MMC"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
select ARDUINO_SELECTIVE_FS
|
||||
default y
|
||||
|
||||
config ARDUINO_SELECTIVE_SimpleBLE
|
||||
bool "Enable SimpleBLE"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
default y
|
||||
|
||||
config ARDUINO_SELECTIVE_SPI
|
||||
bool "Enable SPI"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
default y
|
||||
|
||||
config ARDUINO_SELECTIVE_SPIFFS
|
||||
bool "Enable SPIFFS"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
select ARDUINO_SELECTIVE_FS
|
||||
default y
|
||||
|
||||
config ARDUINO_SELECTIVE_Ticker
|
||||
bool "Enable Ticker"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
default y
|
||||
|
||||
config ARDUINO_SELECTIVE_Update
|
||||
bool "Enable Update"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
default y
|
||||
|
||||
config ARDUINO_SELECTIVE_WebServer
|
||||
bool "Enable WebServer"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
default y
|
||||
select ARDUINO_SELECTIVE_FS
|
||||
|
||||
config ARDUINO_SELECTIVE_WiFi
|
||||
bool "Enable WiFi"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
default y
|
||||
|
||||
config ARDUINO_SELECTIVE_WiFiClientSecure
|
||||
bool "Enable WiFiClientSecure"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
select ARDUINO_SELECTIVE_WiFi
|
||||
default y
|
||||
|
||||
config ARDUINO_SELECTIVE_Wire
|
||||
bool "Enable Wire"
|
||||
depends on ARDUINO_SELECTIVE_COMPILATION
|
||||
default y
|
||||
|
||||
|
||||
endmenu
|
||||
|
503
LICENSE.md
Normal file
503
LICENSE.md
Normal file
@ -0,0 +1,503 @@
|
||||
### GNU LESSER GENERAL PUBLIC LICENSE
|
||||
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
### Preamble
|
||||
|
||||
The licenses for most software are designed to take away your freedom
|
||||
to share and change it. By contrast, the GNU General Public Licenses
|
||||
are intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations
|
||||
below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that there
|
||||
is no warranty for the free library. Also, if the library is modified
|
||||
by someone else and passed on, the recipients should know that what
|
||||
they have is not the original version, so that the original author's
|
||||
reputation will not be affected by problems that might be introduced
|
||||
by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using a
|
||||
shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it
|
||||
becomes a de-facto standard. To achieve this, non-free programs must
|
||||
be allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
**0.** This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License"). Each
|
||||
licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control
|
||||
compilation and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does and
|
||||
what the program that uses the Library does.
|
||||
|
||||
**1.** You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
**2.** You may modify your copy or copies of the Library or any
|
||||
portion of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
- **a)** The modified work must itself be a software library.
|
||||
- **b)** You must cause the files modified to carry prominent
|
||||
notices stating that you changed the files and the date of
|
||||
any change.
|
||||
- **c)** You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
- **d)** If a facility in the modified Library refers to a function
|
||||
or a table of data to be supplied by an application program that
|
||||
uses the facility, other than as an argument passed when the
|
||||
facility is invoked, then you must make a good faith effort to
|
||||
ensure that, in the event an application does not supply such
|
||||
function or table, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of
|
||||
the application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
**3.** You may opt to apply the terms of the ordinary GNU General
|
||||
Public License instead of this License to a given copy of the Library.
|
||||
To do this, you must alter all the notices that refer to this License,
|
||||
so that they refer to the ordinary GNU General Public License, version
|
||||
2, instead of to this License. (If a newer version than version 2 of
|
||||
the ordinary GNU General Public License has appeared, then you can
|
||||
specify that version instead if you wish.) Do not make any other
|
||||
change in these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for that
|
||||
copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of the
|
||||
Library into a program that is not a library.
|
||||
|
||||
**4.** You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy from
|
||||
a designated place, then offering equivalent access to copy the source
|
||||
code from the same place satisfies the requirement to distribute the
|
||||
source code, even though third parties are not compelled to copy the
|
||||
source along with the object code.
|
||||
|
||||
**5.** A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a work,
|
||||
in isolation, is not a derivative work of the Library, and therefore
|
||||
falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License. Section
|
||||
6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data structure
|
||||
layouts and accessors, and small macros and small inline functions
|
||||
(ten lines or less in length), then the use of the object file is
|
||||
unrestricted, regardless of whether it is legally a derivative work.
|
||||
(Executables containing this object code plus portions of the Library
|
||||
will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
**6.** As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a work
|
||||
containing portions of the Library, and distribute that work under
|
||||
terms of your choice, provided that the terms permit modification of
|
||||
the work for the customer's own use and reverse engineering for
|
||||
debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
- **a)** Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood that
|
||||
the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
- **b)** Use a suitable shared library mechanism for linking with
|
||||
the Library. A suitable mechanism is one that (1) uses at run time
|
||||
a copy of the library already present on the user's computer
|
||||
system, rather than copying library functions into the executable,
|
||||
and (2) will operate properly with a modified version of the
|
||||
library, if the user installs one, as long as the modified version
|
||||
is interface-compatible with the version that the work was
|
||||
made with.
|
||||
- **c)** Accompany the work with a written offer, valid for at least
|
||||
three years, to give the same user the materials specified in
|
||||
Subsection 6a, above, for a charge no more than the cost of
|
||||
performing this distribution.
|
||||
- **d)** If distribution of the work is made by offering access to
|
||||
copy from a designated place, offer equivalent access to copy the
|
||||
above specified materials from the same place.
|
||||
- **e)** Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
**7.** You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
- **a)** Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other
|
||||
library facilities. This must be distributed under the terms of
|
||||
the Sections above.
|
||||
- **b)** Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
**8.** You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
**9.** You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
**10.** Each time you redistribute the Library (or any work based on
|
||||
the Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
**11.** If, as a consequence of a court judgment or allegation of
|
||||
patent infringement or for any other reason (not limited to patent
|
||||
issues), conditions are imposed on you (whether by court order,
|
||||
agreement or otherwise) that contradict the conditions of this
|
||||
License, they do not excuse you from the conditions of this License.
|
||||
If you cannot distribute so as to satisfy simultaneously your
|
||||
obligations under this License and any other pertinent obligations,
|
||||
then as a consequence you may not distribute the Library at all. For
|
||||
example, if a patent license would not permit royalty-free
|
||||
redistribution of the Library by all those who receive copies directly
|
||||
or indirectly through you, then the only way you could satisfy both it
|
||||
and this License would be to refrain entirely from distribution of the
|
||||
Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply, and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
**12.** If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
**13.** The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time. Such
|
||||
new versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
**14.** If you wish to incorporate parts of the Library into other
|
||||
free programs whose distribution conditions are incompatible with
|
||||
these, write to the author to ask for permission. For software which
|
||||
is copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
**NO WARRANTY**
|
||||
|
||||
**15.** BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
**16.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
### END OF TERMS AND CONDITIONS
|
||||
|
||||
### How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms
|
||||
of the ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It
|
||||
is safest to attach them to the start of each source file to most
|
||||
effectively convey the exclusion of warranty; and each file should
|
||||
have at least the "copyright" line and a pointer to where the full
|
||||
notice is found.
|
||||
|
||||
one line to give the library's name and an idea of what it does.
|
||||
Copyright (C) year name of author
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper
|
||||
mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or
|
||||
your school, if any, to sign a "copyright disclaimer" for the library,
|
||||
if necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in
|
||||
the library `Frob' (a library for tweaking knobs) written
|
||||
by James Random Hacker.
|
||||
|
||||
signature of Ty Coon, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
@ -1,17 +1,7 @@
|
||||
BOOT_APP_BIN_OFFSET := 0xe000
|
||||
BOOT_APP_BIN_ROOT := $(call dequote,$(COMPONENT_PATH))
|
||||
BOOT_APP_BIN_PATH := $(call dequote,$(abspath $(BOOT_APP_BIN_ROOT)/$(subst $(quote),,tools/partitions/boot_app0.bin)))
|
||||
|
||||
ifndef CONFIG_PARTITION_TABLE_CUSTOM
|
||||
PARTITION_TABLE_CSV_PATH = $(call dequote,$(abspath $(BOOT_APP_BIN_ROOT)/$(subst $(quote),,tools/partitions/$(CONFIG_ARDUHAL_PARTITION_SCHEME).csv)))
|
||||
endif
|
||||
|
||||
BOOT_APP_BIN_FLASH_CMD = $(ESPTOOLPY_SERIAL) write_flash $(BOOT_APP_BIN_OFFSET) $(BOOT_APP_BIN_PATH)
|
||||
ESPTOOL_ALL_FLASH_ARGS += $(BOOT_APP_BIN_OFFSET) $(BOOT_APP_BIN_PATH)
|
||||
|
||||
CPPFLAGS += -DARDUINO=10800 -DESP32=1 -DARDUINO_ARCH_ESP32=1
|
||||
|
||||
boot-app0:
|
||||
@echo "Rebooting to APP0"
|
||||
$(BOOT_APP_BIN_FLASH_CMD)
|
||||
|
||||
CPPFLAGS += -DARDUINO=10800 -DESP32=1 -DARDUINO_ARCH_ESP32=1 -DBOARD_HAS_PSRAM
|
||||
|
31
README.md
31
README.md
@ -1,6 +1,5 @@
|
||||
# Arduino core for ESP32 WiFi chip
|
||||
|
||||
[](https://travis-ci.org/espressif/arduino-esp32)
|
||||
# Arduino core for the ESP32
|
||||
[](https://travis-ci.org/espressif/arduino-esp32) 
|
||||
|
||||
### Need help or have a question? Join the chat at [](https://gitter.im/espressif/arduino-esp32?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
@ -11,15 +10,15 @@
|
||||
- [Issue/Bug report template](#issuebug-report-template)
|
||||
- [ESP32Dev Board PINMAP](#esp32dev-board-pinmap)
|
||||
|
||||
## Development Status
|
||||
Most of the framework is implemented. Most noticable is the missing analogWrite. While analogWrite is on it's way, there are a few other options that you can use:
|
||||
- 16 channels [LEDC](cores/esp32/esp32-hal-ledc.h) which is PWM
|
||||
- 8 channels [SigmaDelta](cores/esp32/esp32-hal-sigmadelta.h) which uses SigmaDelta modulation
|
||||
- 2 channels [DAC](cores/esp32/esp32-hal-dac.h) which gives real analog output
|
||||
### Development Status
|
||||
[Latest stable release  ](https://github.com/espressif/arduino-esp32/releases/latest/) 
|
||||
|
||||
## Installation Instructions
|
||||
[Latest development release  ](https://github.com/espressif/arduino-esp32/releases/latest/) 
|
||||
|
||||
- Using Arduino IDE
|
||||
### Installation Instructions
|
||||
- Using Arduino IDE Boards Manager (preferred)
|
||||
+ [Instructions for Boards Manager](docs/arduino-ide/boards_manager.md)
|
||||
- Using Arduino IDE with the development repository
|
||||
+ [Instructions for Windows](docs/arduino-ide/windows.md)
|
||||
+ [Instructions for Mac](docs/arduino-ide/mac.md)
|
||||
+ [Instructions for Debian/Ubuntu Linux](docs/arduino-ide/debian_ubuntu.md)
|
||||
@ -28,21 +27,21 @@ Most of the framework is implemented. Most noticable is the missing analogWrite.
|
||||
- [Using PlatformIO](docs/platformio.md)
|
||||
- [Building with make](docs/make.md)
|
||||
- [Using as ESP-IDF component](docs/esp-idf_component.md)
|
||||
- [Using OTAWebUpdater](docs/OTAWebUpdate/OTAWebUpdate.md)
|
||||
|
||||
#### Decoding exceptions
|
||||
### Decoding exceptions
|
||||
|
||||
You can use [EspExceptionDecoder](https://github.com/me-no-dev/EspExceptionDecoder) to get meaningful call trace.
|
||||
|
||||
#### Issue/Bug report template
|
||||
### Issue/Bug report template
|
||||
Before reporting an issue, make sure you've searched for similar one that was already created. Also make sure to go through all the issues labelled as [for reference](https://github.com/espressif/arduino-esp32/issues?utf8=%E2%9C%93&q=is%3Aissue%20label%3A%22for%20reference%22%20).
|
||||
|
||||
Finally, if you're sure no one else had the issue, follow the [ISSUE_TEMPLATE](docs/ISSUE_TEMPLATE.md) while reporting any issue.
|
||||
Finally, if you are sure no one else had the issue, follow the [ISSUE_TEMPLATE](docs/ISSUE_TEMPLATE.md) while reporting any issue.
|
||||
|
||||
|
||||
## ESP32Dev Board PINMAP
|
||||
### ESP32Dev Board PINMAP
|
||||
|
||||

|
||||
|
||||
## Hint
|
||||
### Tip
|
||||
|
||||
Sometimes to program ESP32 via serial you must keep GPIO0 LOW during the programming process
|
||||
|
19
appveyor.yml
19
appveyor.yml
@ -1,19 +0,0 @@
|
||||
build: off
|
||||
environment:
|
||||
|
||||
matrix:
|
||||
- PLATFORMIO_CI_SRC: "libraries/WiFi/examples/WiFiClient"
|
||||
- PLATFORMIO_CI_SRC: "libraries/WiFi/examples/WiFiClientBasic"
|
||||
- PLATFORMIO_CI_SRC: "libraries/WiFi/examples/WiFiClientEvents"
|
||||
- PLATFORMIO_CI_SRC: "libraries/WiFi/examples/WiFiIPv6"
|
||||
- PLATFORMIO_CI_SRC: "libraries/WiFi/examples/WiFiScan"
|
||||
- PLATFORMIO_CI_SRC: "libraries/WiFi/examples/WiFiSmartConfig"
|
||||
|
||||
install:
|
||||
- cmd: git submodule update --init --recursive
|
||||
- cmd: SET PATH=%PATH%;C:\Python27\Scripts
|
||||
- cmd: pip install -U https://github.com/platformio/platformio/archive/develop.zip
|
||||
- cmd: platformio platform install https://github.com/platformio/platform-espressif32.git#feature/stage
|
||||
|
||||
test_script:
|
||||
- cmd: platformio ci -b esp32dev -b nano32 -b node32s
|
4167
boards.txt
4167
boards.txt
File diff suppressed because it is too large
Load Diff
36
component.mk
36
component.mk
@ -1,6 +1,36 @@
|
||||
ARDUINO_CORE_LIBS := $(patsubst $(COMPONENT_PATH)/%,%,$(sort $(dir $(wildcard $(COMPONENT_PATH)/libraries/*/*/))))
|
||||
ARDUINO_ALL_LIBRARIES := $(patsubst $(COMPONENT_PATH)/libraries/%,%,$(wildcard $(COMPONENT_PATH)/libraries/*))
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := cores/esp32 variants/esp32 $(ARDUINO_CORE_LIBS)
|
||||
# Macro returns non-empty if Arduino library $(1) should be included in the build
|
||||
# (either because selective compilation is of, or this library is enabled
|
||||
define ARDUINO_LIBRARY_ENABLED
|
||||
$(if $(CONFIG_ARDUINO_SELECTIVE_COMPILATION),$(CONFIG_ARDUINO_SELECTIVE_$(1)),y)
|
||||
endef
|
||||
|
||||
ARDUINO_ENABLED_LIBRARIES := $(foreach LIBRARY,$(sort $(ARDUINO_ALL_LIBRARIES)),$(if $(call ARDUINO_LIBRARY_ENABLED,$(LIBRARY)),$(LIBRARY)))
|
||||
|
||||
$(info Arduino libraries in build: $(ARDUINO_ENABLED_LIBRARIES))
|
||||
|
||||
# Expand all subdirs under $(1)
|
||||
define EXPAND_SUBDIRS
|
||||
$(sort $(dir $(wildcard $(1)/* $(1)/*/* $(1)/*/*/* $(1)/*/*/*/* $(1)/*/*/*/*/*)))
|
||||
endef
|
||||
|
||||
# Macro returns SRCDIRS for library
|
||||
define ARDUINO_LIBRARY_GET_SRCDIRS
|
||||
$(if $(wildcard $(COMPONENT_PATH)/libraries/$(1)/src/.), \
|
||||
$(call EXPAND_SUBDIRS,$(COMPONENT_PATH)/libraries/$(1)/src), \
|
||||
$(filter-out $(call EXPAND_SUBDIRS,$(COMPONENT_PATH)/libraries/$(1)/examples), \
|
||||
$(call EXPAND_SUBDIRS,$(COMPONENT_PATH)/libraries/$(1)) \
|
||||
) \
|
||||
)
|
||||
endef
|
||||
|
||||
# Make a list of all srcdirs in enabled libraries
|
||||
ARDUINO_LIBRARY_SRCDIRS := $(patsubst $(COMPONENT_PATH)/%,%,$(foreach LIBRARY,$(ARDUINO_ENABLED_LIBRARIES),$(call ARDUINO_LIBRARY_GET_SRCDIRS,$(LIBRARY))))
|
||||
|
||||
#$(info Arduino libraries src dirs: $(ARDUINO_LIBRARY_SRCDIRS))
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := cores/esp32 variants/esp32 $(ARDUINO_LIBRARY_SRCDIRS)
|
||||
COMPONENT_PRIV_INCLUDEDIRS := cores/esp32/libb64
|
||||
COMPONENT_SRCDIRS := cores/esp32/libb64 cores/esp32 variants/esp32 $(ARDUINO_CORE_LIBS)
|
||||
COMPONENT_SRCDIRS := cores/esp32/libb64 cores/esp32 variants/esp32 $(ARDUINO_LIBRARY_SRCDIRS)
|
||||
CXXFLAGS += -fno-rtti
|
||||
|
@ -68,14 +68,7 @@
|
||||
#define __STRINGIFY(a) #a
|
||||
#endif
|
||||
|
||||
// undefine stdlib's abs if encountered
|
||||
#ifdef abs
|
||||
#undef abs
|
||||
#endif
|
||||
|
||||
#define abs(x) ((x)>0?(x):-(x))
|
||||
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
|
||||
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
|
||||
#define radians(deg) ((deg)*DEG_TO_RAD)
|
||||
#define degrees(rad) ((rad)*RAD_TO_DEG)
|
||||
#define sq(x) ((x)*(x))
|
||||
@ -122,10 +115,12 @@ typedef bool boolean;
|
||||
typedef uint8_t byte;
|
||||
typedef unsigned int word;
|
||||
|
||||
#ifdef __cplusplus
|
||||
void setup(void);
|
||||
void loop(void);
|
||||
|
||||
long random(long, long);
|
||||
#endif
|
||||
void randomSeed(unsigned long);
|
||||
long map(long, long, long, long, long);
|
||||
|
||||
@ -146,6 +141,9 @@ void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
#include "WCharacter.h"
|
||||
#include "WString.h"
|
||||
#include "Stream.h"
|
||||
@ -158,6 +156,13 @@ void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
|
||||
#include "HardwareSerial.h"
|
||||
#include "Esp.h"
|
||||
|
||||
using std::abs;
|
||||
using std::isinf;
|
||||
using std::isnan;
|
||||
using std::max;
|
||||
using std::min;
|
||||
using ::round;
|
||||
|
||||
uint16_t makeWord(uint16_t w);
|
||||
uint16_t makeWord(byte h, byte l);
|
||||
|
||||
@ -176,12 +181,6 @@ extern "C" void configTzTime(const char* tz,
|
||||
long random(long);
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#ifndef _GLIBCXX_VECTOR
|
||||
// arduino is not compatible with std::vector
|
||||
#define min(a,b) ((a)<(b)?(a):(b))
|
||||
#define max(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
#define _min(a,b) ((a)<(b)?(a):(b))
|
||||
#define _max(a,b) ((a)>(b)?(a):(b))
|
||||
|
||||
|
@ -19,26 +19,30 @@
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "Esp.h"
|
||||
#include "rom/spi_flash.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "esp_spi_flash.h"
|
||||
#include <memory>
|
||||
#include <soc/soc.h>
|
||||
#include <soc/efuse_reg.h>
|
||||
#include <esp_partition.h>
|
||||
extern "C" {
|
||||
#include "esp_ota_ops.h"
|
||||
#include "esp_image_format.h"
|
||||
}
|
||||
#include <MD5Builder.h>
|
||||
|
||||
/* Main header of binary image */
|
||||
typedef struct {
|
||||
uint8_t magic;
|
||||
uint8_t segment_count;
|
||||
uint8_t spi_mode; /* flash read mode (esp_image_spi_mode_t as uint8_t) */
|
||||
uint8_t spi_speed: 4; /* flash frequency (esp_image_spi_freq_t as uint8_t) */
|
||||
uint8_t spi_size: 4; /* flash chip size (esp_image_flash_size_t as uint8_t) */
|
||||
uint32_t entry_addr;
|
||||
uint8_t encrypt_flag; /* encrypt flag */
|
||||
uint8_t extra_header[15]; /* ESP32 additional header, unused by second bootloader */
|
||||
} esp_image_header_t;
|
||||
|
||||
#define ESP_IMAGE_HEADER_MAGIC 0xE9
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/spi_flash.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/spi_flash.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/spi_flash.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* User-defined Literals
|
||||
@ -100,21 +104,135 @@ void EspClass::deepSleep(uint32_t time_us)
|
||||
esp_deep_sleep(time_us);
|
||||
}
|
||||
|
||||
uint32_t EspClass::getCycleCount()
|
||||
{
|
||||
uint32_t ccount;
|
||||
__asm__ __volatile__("esync; rsr %0,ccount":"=a" (ccount));
|
||||
return ccount;
|
||||
}
|
||||
|
||||
void EspClass::restart(void)
|
||||
{
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
uint32_t EspClass::getHeapSize(void)
|
||||
{
|
||||
multi_heap_info_t info;
|
||||
heap_caps_get_info(&info, MALLOC_CAP_INTERNAL);
|
||||
return info.total_free_bytes + info.total_allocated_bytes;
|
||||
}
|
||||
|
||||
uint32_t EspClass::getFreeHeap(void)
|
||||
{
|
||||
return esp_get_free_heap_size();
|
||||
return heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
|
||||
}
|
||||
|
||||
uint32_t EspClass::getMinFreeHeap(void)
|
||||
{
|
||||
return heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL);
|
||||
}
|
||||
|
||||
uint32_t EspClass::getMaxAllocHeap(void)
|
||||
{
|
||||
return heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL);
|
||||
}
|
||||
|
||||
uint32_t EspClass::getPsramSize(void)
|
||||
{
|
||||
if(psramFound()){
|
||||
multi_heap_info_t info;
|
||||
heap_caps_get_info(&info, MALLOC_CAP_SPIRAM);
|
||||
return info.total_free_bytes + info.total_allocated_bytes;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t EspClass::getFreePsram(void)
|
||||
{
|
||||
if(psramFound()){
|
||||
return heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t EspClass::getMinFreePsram(void)
|
||||
{
|
||||
if(psramFound()){
|
||||
return heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t EspClass::getMaxAllocPsram(void)
|
||||
{
|
||||
if(psramFound()){
|
||||
return heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t sketchSize(sketchSize_t response) {
|
||||
esp_image_metadata_t data;
|
||||
const esp_partition_t *running = esp_ota_get_running_partition();
|
||||
if (!running) return 0;
|
||||
const esp_partition_pos_t running_pos = {
|
||||
.offset = running->address,
|
||||
.size = running->size,
|
||||
};
|
||||
data.start_addr = running_pos.offset;
|
||||
esp_image_verify(ESP_IMAGE_VERIFY, &running_pos, &data);
|
||||
if (response) {
|
||||
return running_pos.size - data.image_len;
|
||||
} else {
|
||||
return data.image_len;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t EspClass::getSketchSize () {
|
||||
return sketchSize(SKETCH_SIZE_TOTAL);
|
||||
}
|
||||
|
||||
String EspClass::getSketchMD5()
|
||||
{
|
||||
static String result;
|
||||
if (result.length()) {
|
||||
return result;
|
||||
}
|
||||
uint32_t lengthLeft = getSketchSize();
|
||||
|
||||
const esp_partition_t *running = esp_ota_get_running_partition();
|
||||
if (!running) {
|
||||
log_e("Partition could not be found");
|
||||
|
||||
return String();
|
||||
}
|
||||
const size_t bufSize = SPI_FLASH_SEC_SIZE;
|
||||
std::unique_ptr<uint8_t[]> buf(new uint8_t[bufSize]);
|
||||
uint32_t offset = 0;
|
||||
if(!buf.get()) {
|
||||
log_e("Not enough memory to allocate buffer");
|
||||
|
||||
return String();
|
||||
}
|
||||
MD5Builder md5;
|
||||
md5.begin();
|
||||
while( lengthLeft > 0) {
|
||||
size_t readBytes = (lengthLeft < bufSize) ? lengthLeft : bufSize;
|
||||
if (!ESP.flashRead(running->address + offset, reinterpret_cast<uint32_t*>(buf.get()), (readBytes + 3) & ~3)) {
|
||||
log_e("Could not read buffer from flash");
|
||||
|
||||
return String();
|
||||
}
|
||||
md5.add(buf.get(), readBytes);
|
||||
lengthLeft -= readBytes;
|
||||
offset += readBytes;
|
||||
}
|
||||
md5.calculate();
|
||||
result = md5.toString();
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t EspClass::getFreeSketchSpace () {
|
||||
const esp_partition_t* _partition = esp_ota_get_next_update_partition(NULL);
|
||||
if(!_partition){
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _partition->size;
|
||||
}
|
||||
|
||||
uint8_t EspClass::getChipRevision(void)
|
||||
|
@ -50,16 +50,33 @@ typedef enum {
|
||||
FM_UNKNOWN = 0xff
|
||||
} FlashMode_t;
|
||||
|
||||
typedef enum {
|
||||
SKETCH_SIZE_TOTAL = 0,
|
||||
SKETCH_SIZE_FREE = 1
|
||||
} sketchSize_t;
|
||||
|
||||
class EspClass
|
||||
{
|
||||
public:
|
||||
EspClass() {}
|
||||
~EspClass() {}
|
||||
void restart();
|
||||
uint32_t getFreeHeap();
|
||||
|
||||
//Internal RAM
|
||||
uint32_t getHeapSize(); //total heap size
|
||||
uint32_t getFreeHeap(); //available heap
|
||||
uint32_t getMinFreeHeap(); //lowest level of free heap since boot
|
||||
uint32_t getMaxAllocHeap(); //largest block of heap that can be allocated at once
|
||||
|
||||
//SPI RAM
|
||||
uint32_t getPsramSize();
|
||||
uint32_t getFreePsram();
|
||||
uint32_t getMinFreePsram();
|
||||
uint32_t getMaxAllocPsram();
|
||||
|
||||
uint8_t getChipRevision();
|
||||
uint8_t getCpuFreqMHz(){ return CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ; }
|
||||
uint32_t getCycleCount();
|
||||
uint32_t getCpuFreqMHz(){ return getCpuFrequencyMhz(); }
|
||||
inline uint32_t getCycleCount() __attribute__((always_inline));
|
||||
const char * getSdkVersion();
|
||||
|
||||
void deepSleep(uint32_t time_us);
|
||||
@ -72,6 +89,10 @@ public:
|
||||
uint32_t magicFlashChipSpeed(uint8_t byte);
|
||||
FlashMode_t magicFlashChipMode(uint8_t byte);
|
||||
|
||||
uint32_t getSketchSize();
|
||||
String getSketchMD5();
|
||||
uint32_t getFreeSketchSpace();
|
||||
|
||||
bool flashEraseSector(uint32_t sector);
|
||||
bool flashWrite(uint32_t offset, uint32_t *data, size_t size);
|
||||
bool flashRead(uint32_t offset, uint32_t *data, size_t size);
|
||||
@ -80,6 +101,13 @@ public:
|
||||
|
||||
};
|
||||
|
||||
uint32_t ARDUINO_ISR_ATTR EspClass::getCycleCount()
|
||||
{
|
||||
uint32_t ccount;
|
||||
__asm__ __volatile__("esync; rsr %0,ccount":"=a" (ccount));
|
||||
return ccount;
|
||||
}
|
||||
|
||||
extern EspClass ESP;
|
||||
|
||||
#endif //ESP_H
|
||||
|
44
cores/esp32/FunctionalInterrupt.cpp
Normal file
44
cores/esp32/FunctionalInterrupt.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* FunctionalInterrupt.cpp
|
||||
*
|
||||
* Created on: 8 jul. 2018
|
||||
* Author: Herman
|
||||
*/
|
||||
|
||||
#include "FunctionalInterrupt.h"
|
||||
#include "Arduino.h"
|
||||
|
||||
typedef void (*voidFuncPtr)(void);
|
||||
typedef void (*voidFuncPtrArg)(void*);
|
||||
|
||||
extern "C"
|
||||
{
|
||||
extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type, bool functional);
|
||||
}
|
||||
|
||||
void ARDUINO_ISR_ATTR interruptFunctional(void* arg)
|
||||
{
|
||||
InterruptArgStructure* localArg = (InterruptArgStructure*)arg;
|
||||
if (localArg->interruptFunction)
|
||||
{
|
||||
localArg->interruptFunction();
|
||||
}
|
||||
}
|
||||
|
||||
void attachInterrupt(uint8_t pin, std::function<void(void)> intRoutine, int mode)
|
||||
{
|
||||
// use the local interrupt routine which takes the ArgStructure as argument
|
||||
__attachInterruptFunctionalArg (pin, (voidFuncPtrArg)interruptFunctional, new InterruptArgStructure{intRoutine}, mode, true);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void cleanupFunctional(void* arg)
|
||||
{
|
||||
delete (InterruptArgStructure*)arg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
20
cores/esp32/FunctionalInterrupt.h
Normal file
20
cores/esp32/FunctionalInterrupt.h
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* FunctionalInterrupt.h
|
||||
*
|
||||
* Created on: 8 jul. 2018
|
||||
* Author: Herman
|
||||
*/
|
||||
|
||||
#ifndef CORE_CORE_FUNCTIONALINTERRUPT_H_
|
||||
#define CORE_CORE_FUNCTIONALINTERRUPT_H_
|
||||
|
||||
#include <functional>
|
||||
|
||||
struct InterruptArgStructure {
|
||||
std::function<void(void)> interruptFunction;
|
||||
};
|
||||
|
||||
void attachInterrupt(uint8_t pin, std::function<void(void)> intRoutine, int mode);
|
||||
|
||||
|
||||
#endif /* CORE_CORE_FUNCTIONALINTERRUPT_H_ */
|
@ -3,15 +3,54 @@
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "pins_arduino.h"
|
||||
#include "HardwareSerial.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
#ifndef RX1
|
||||
#define RX1 9
|
||||
#endif
|
||||
|
||||
#ifndef TX1
|
||||
#define TX1 10
|
||||
#endif
|
||||
|
||||
#ifndef RX2
|
||||
#define RX2 16
|
||||
#endif
|
||||
|
||||
#ifndef TX2
|
||||
#define TX2 17
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#ifndef RX1
|
||||
#define RX1 18
|
||||
#endif
|
||||
|
||||
#ifndef TX1
|
||||
#define TX1 17
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
|
||||
#if ARDUINO_SERIAL_PORT //Serial used for USB CDC
|
||||
HardwareSerial Serial0(0);
|
||||
#else
|
||||
HardwareSerial Serial(0);
|
||||
#endif
|
||||
HardwareSerial Serial1(1);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
HardwareSerial Serial2(2);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
HardwareSerial::HardwareSerial(int uart_nr) : _uart_nr(uart_nr), _uart(NULL) {}
|
||||
|
||||
void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert)
|
||||
void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert, unsigned long timeout_ms)
|
||||
{
|
||||
if(0 > _uart_nr || _uart_nr > 2) {
|
||||
log_e("Serial number is invalid, please use 0, 1 or 2");
|
||||
@ -21,18 +60,49 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
|
||||
end();
|
||||
}
|
||||
if(_uart_nr == 0 && rxPin < 0 && txPin < 0) {
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
rxPin = 3;
|
||||
txPin = 1;
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
rxPin = 44;
|
||||
txPin = 43;
|
||||
#endif
|
||||
}
|
||||
if(_uart_nr == 1 && rxPin < 0 && txPin < 0) {
|
||||
rxPin = 9;
|
||||
txPin = 10;
|
||||
rxPin = RX1;
|
||||
txPin = TX1;
|
||||
}
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
if(_uart_nr == 2 && rxPin < 0 && txPin < 0) {
|
||||
rxPin = 16;
|
||||
txPin = 17;
|
||||
rxPin = RX2;
|
||||
txPin = TX2;
|
||||
}
|
||||
_uart = uartBegin(_uart_nr, baud, config, rxPin, txPin, 256, invert);
|
||||
#endif
|
||||
_uart = uartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, 256, invert);
|
||||
|
||||
if(!baud) {
|
||||
uartStartDetectBaudrate(_uart);
|
||||
time_t startMillis = millis();
|
||||
unsigned long detectedBaudRate = 0;
|
||||
while(millis() - startMillis < timeout_ms && !(detectedBaudRate = uartDetectBaudrate(_uart))) {
|
||||
yield();
|
||||
}
|
||||
|
||||
end();
|
||||
|
||||
if(detectedBaudRate) {
|
||||
delay(100); // Give some time...
|
||||
_uart = uartBegin(_uart_nr, detectedBaudRate, config, rxPin, txPin, 256, invert);
|
||||
} else {
|
||||
log_e("Could not detect baudrate. Serial data at the port must be present within the timeout for detection to be possible");
|
||||
_uart = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HardwareSerial::updateBaudRate(unsigned long baud)
|
||||
{
|
||||
uartSetBaudRate(_uart, baud);
|
||||
}
|
||||
|
||||
void HardwareSerial::end()
|
||||
@ -44,6 +114,10 @@ void HardwareSerial::end()
|
||||
_uart = 0;
|
||||
}
|
||||
|
||||
size_t HardwareSerial::setRxBufferSize(size_t new_size) {
|
||||
return uartResizeRxBuffer(_uart, new_size);
|
||||
}
|
||||
|
||||
void HardwareSerial::setDebugOutput(bool en)
|
||||
{
|
||||
if(_uart == 0) {
|
||||
@ -53,7 +127,7 @@ void HardwareSerial::setDebugOutput(bool en)
|
||||
uartSetDebug(_uart);
|
||||
} else {
|
||||
if(uartGetDebug() == _uart_nr) {
|
||||
uartSetDebug(0);
|
||||
uartSetDebug(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -83,11 +157,34 @@ int HardwareSerial::read(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
void HardwareSerial::flush()
|
||||
// read characters into buffer
|
||||
// terminates if size characters have been read, or no further are pending
|
||||
// returns the number of characters placed in the buffer
|
||||
// the buffer is NOT null terminated.
|
||||
size_t HardwareSerial::read(uint8_t *buffer, size_t size)
|
||||
{
|
||||
size_t avail = available();
|
||||
if (size < avail) {
|
||||
avail = size;
|
||||
}
|
||||
size_t count = 0;
|
||||
while(count < avail) {
|
||||
*buffer++ = uartRead(_uart);
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void HardwareSerial::flush(void)
|
||||
{
|
||||
uartFlush(_uart);
|
||||
}
|
||||
|
||||
void HardwareSerial::flush(bool txOnly)
|
||||
{
|
||||
uartFlushTxOnly(_uart, txOnly);
|
||||
}
|
||||
|
||||
size_t HardwareSerial::write(uint8_t c)
|
||||
{
|
||||
uartWrite(_uart, c);
|
||||
|
@ -22,6 +22,24 @@
|
||||
Modified 18 December 2014 by Ivan Grokhotkov (esp8266 platform support)
|
||||
Modified 31 March 2015 by Markus Sattler (rewrite the code for UART0 + UART1 support in ESP8266)
|
||||
Modified 25 April 2015 by Thomas Flayols (add configuration different from 8N1 in ESP8266)
|
||||
Modified 13 October 2018 by Jeroen Döll (add baudrate detection)
|
||||
Baudrate detection example usage (detection on Serial1):
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(100);
|
||||
Serial.println();
|
||||
|
||||
Serial1.begin(0, SERIAL_8N1, -1, -1, true, 11000UL); // Passing 0 for baudrate to detect it, the last parameter is a timeout in ms
|
||||
|
||||
unsigned long detectedBaudRate = Serial1.baudRate();
|
||||
if(detectedBaudRate) {
|
||||
Serial.printf("Detected baudrate is %lu\n", detectedBaudRate);
|
||||
} else {
|
||||
Serial.println("No baudrate detected, Serial1 will not work!");
|
||||
}
|
||||
}
|
||||
|
||||
Pay attention: the baudrate returned by baudRate() may be rounded, eg 115200 returns 115201
|
||||
*/
|
||||
|
||||
#ifndef HardwareSerial_h
|
||||
@ -37,16 +55,26 @@ class HardwareSerial: public Stream
|
||||
public:
|
||||
HardwareSerial(int uart_nr);
|
||||
|
||||
void begin(unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1, bool invert=false);
|
||||
void begin(unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1, bool invert=false, unsigned long timeout_ms = 20000UL);
|
||||
void end();
|
||||
void updateBaudRate(unsigned long baud);
|
||||
int available(void);
|
||||
int availableForWrite(void);
|
||||
int peek(void);
|
||||
int read(void);
|
||||
size_t read(uint8_t *buffer, size_t size);
|
||||
inline size_t read(char * buffer, size_t size)
|
||||
{
|
||||
return read((uint8_t*) buffer, size);
|
||||
}
|
||||
void flush(void);
|
||||
void flush( bool txOnly);
|
||||
size_t write(uint8_t);
|
||||
size_t write(const uint8_t *buffer, size_t size);
|
||||
|
||||
inline size_t write(const char * buffer, size_t size)
|
||||
{
|
||||
return write((uint8_t*) buffer, size);
|
||||
}
|
||||
inline size_t write(const char * s)
|
||||
{
|
||||
return write((uint8_t*) s, strlen(s));
|
||||
@ -70,6 +98,7 @@ public:
|
||||
uint32_t baudRate();
|
||||
operator bool() const;
|
||||
|
||||
size_t setRxBufferSize(size_t);
|
||||
void setDebugOutput(bool);
|
||||
|
||||
protected:
|
||||
@ -77,8 +106,23 @@ protected:
|
||||
uart_t* _uart;
|
||||
};
|
||||
|
||||
extern void serialEventRun(void) __attribute__((weak));
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
|
||||
#ifndef ARDUINO_SERIAL_PORT
|
||||
#define ARDUINO_SERIAL_PORT 0
|
||||
#endif
|
||||
#if ARDUINO_SERIAL_PORT //Serial used for USB CDC
|
||||
#include "USB.h"
|
||||
#include "USBCDC.h"
|
||||
extern HardwareSerial Serial0;
|
||||
#else
|
||||
extern HardwareSerial Serial;
|
||||
#endif
|
||||
|
||||
extern HardwareSerial Serial1;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
extern HardwareSerial Serial2;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // HardwareSerial_h
|
||||
|
@ -21,7 +21,19 @@
|
||||
|
||||
#include <WString.h>
|
||||
#include <Stream.h>
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/md5_hash.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/md5_hash.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/md5_hash.h"
|
||||
#endif
|
||||
|
||||
class MD5Builder
|
||||
{
|
||||
|
@ -52,19 +52,24 @@ size_t Print::printf(const char *format, ...)
|
||||
va_list copy;
|
||||
va_start(arg, format);
|
||||
va_copy(copy, arg);
|
||||
size_t len = vsnprintf(NULL, 0, format, arg);
|
||||
int len = vsnprintf(temp, sizeof(loc_buf), format, copy);
|
||||
va_end(copy);
|
||||
if(len < 0) {
|
||||
va_end(arg);
|
||||
return 0;
|
||||
};
|
||||
if(len >= sizeof(loc_buf)){
|
||||
temp = new char[len+1];
|
||||
temp = (char*) malloc(len+1);
|
||||
if(temp == NULL) {
|
||||
va_end(arg);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
len = vsnprintf(temp, len+1, format, arg);
|
||||
write((uint8_t*)temp, len);
|
||||
}
|
||||
va_end(arg);
|
||||
if(len > 64){
|
||||
delete[] temp;
|
||||
len = write((uint8_t*)temp, len);
|
||||
if(temp != loc_buf){
|
||||
free(temp);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
@ -154,9 +159,11 @@ size_t Print::print(struct tm * timeinfo, const char * format)
|
||||
}
|
||||
char buf[64];
|
||||
size_t written = strftime(buf, 64, f, timeinfo);
|
||||
print(buf);
|
||||
if(written == 0){
|
||||
return written;
|
||||
}
|
||||
return print(buf);
|
||||
}
|
||||
|
||||
size_t Print::println(void)
|
||||
{
|
||||
|
@ -82,6 +82,9 @@ void Stream::setTimeout(unsigned long timeout) // sets the maximum number of mi
|
||||
{
|
||||
_timeout = timeout;
|
||||
}
|
||||
unsigned long Stream::getTimeout(void) {
|
||||
return _timeout;
|
||||
}
|
||||
|
||||
// find returns true if the target string is found
|
||||
bool Stream::find(const char *target)
|
||||
|
@ -59,7 +59,7 @@ public:
|
||||
// parsing methods
|
||||
|
||||
void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second
|
||||
|
||||
unsigned long getTimeout(void);
|
||||
bool find(const char *target); // reads data from the stream until the target string is found
|
||||
bool find(uint8_t *target)
|
||||
{
|
||||
@ -97,8 +97,8 @@ public:
|
||||
|
||||
float parseFloat(); // float version of parseInt
|
||||
|
||||
size_t readBytes(char *buffer, size_t length); // read chars from stream into buffer
|
||||
size_t readBytes(uint8_t *buffer, size_t length)
|
||||
virtual size_t readBytes(char *buffer, size_t length); // read chars from stream into buffer
|
||||
virtual size_t readBytes(uint8_t *buffer, size_t length)
|
||||
{
|
||||
return readBytes((char *) buffer, length);
|
||||
}
|
||||
@ -114,7 +114,7 @@ public:
|
||||
// returns the number of characters placed in the buffer (0 means no valid data found)
|
||||
|
||||
// Arduino String functions to be added here
|
||||
String readString();
|
||||
virtual String readString();
|
||||
String readStringUntil(char terminator);
|
||||
|
||||
protected:
|
||||
|
@ -2,6 +2,7 @@
|
||||
StreamString.cpp
|
||||
|
||||
Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
@ -22,31 +23,28 @@
|
||||
#include <Arduino.h>
|
||||
#include "StreamString.h"
|
||||
|
||||
size_t StreamString::write(const uint8_t *data, size_t size)
|
||||
{
|
||||
size_t StreamString::write(const uint8_t *data, size_t size) {
|
||||
if(size && data) {
|
||||
if(reserve(length() + size + 1)) {
|
||||
memcpy((void *) (buffer + len), (const void *) data, size);
|
||||
len += size;
|
||||
*(buffer + len) = 0x00; // add null for string end
|
||||
const unsigned int newlen = length() + size;
|
||||
if(reserve(newlen + 1)) {
|
||||
memcpy((void *) (wbuffer() + len()), (const void *) data, size);
|
||||
setLen(newlen);
|
||||
*(wbuffer() + newlen) = 0x00; // add null for string end
|
||||
return size;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t StreamString::write(uint8_t data)
|
||||
{
|
||||
size_t StreamString::write(uint8_t data) {
|
||||
return concat((char) data);
|
||||
}
|
||||
|
||||
int StreamString::available()
|
||||
{
|
||||
int StreamString::available() {
|
||||
return length();
|
||||
}
|
||||
|
||||
int StreamString::read()
|
||||
{
|
||||
int StreamString::read() {
|
||||
if(length()) {
|
||||
char c = charAt(0);
|
||||
remove(0, 1);
|
||||
@ -56,8 +54,7 @@ int StreamString::read()
|
||||
return -1;
|
||||
}
|
||||
|
||||
int StreamString::peek()
|
||||
{
|
||||
int StreamString::peek() {
|
||||
if(length()) {
|
||||
char c = charAt(0);
|
||||
return c;
|
||||
@ -65,7 +62,6 @@ int StreamString::peek()
|
||||
return -1;
|
||||
}
|
||||
|
||||
void StreamString::flush()
|
||||
{
|
||||
void StreamString::flush() {
|
||||
}
|
||||
|
||||
|
338
cores/esp32/USB.cpp
Normal file
338
cores/esp32/USB.cpp
Normal file
@ -0,0 +1,338 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "esp32-hal.h"
|
||||
#include "esp32-hal-tinyusb.h"
|
||||
#include "USB.h"
|
||||
#if CONFIG_USB_ENABLED
|
||||
|
||||
#ifndef USB_VID
|
||||
#define USB_VID USB_ESPRESSIF_VID
|
||||
#endif
|
||||
#ifndef USB_PID
|
||||
#define USB_PID 0x0002
|
||||
#endif
|
||||
#ifndef USB_MANUFACTURER
|
||||
#define USB_MANUFACTURER "Espressif Systems"
|
||||
#endif
|
||||
#ifndef USB_PRODUCT
|
||||
#define USB_PRODUCT ARDUINO_BOARD
|
||||
#endif
|
||||
#ifndef USB_SERIAL
|
||||
#define USB_SERIAL "0"
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
#include "tinyusb.h"
|
||||
}
|
||||
|
||||
#if CFG_TUD_DFU_RT
|
||||
static uint16_t load_dfu_descriptor(uint8_t * dst, uint8_t * itf)
|
||||
{
|
||||
#define DFU_ATTR_CAN_DOWNLOAD 1
|
||||
#define DFU_ATTR_CAN_UPLOAD 2
|
||||
#define DFU_ATTR_MANIFESTATION_TOLERANT 4
|
||||
#define DFU_ATTR_WILL_DETACH 8
|
||||
#define DFU_ATTRS (DFU_ATTR_CAN_DOWNLOAD | DFU_ATTR_CAN_UPLOAD | DFU_ATTR_MANIFESTATION_TOLERANT)
|
||||
|
||||
uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB DFU_RT");
|
||||
uint8_t descriptor[TUD_DFU_RT_DESC_LEN] = {
|
||||
// Interface number, string index, attributes, detach timeout, transfer size */
|
||||
TUD_DFU_RT_DESCRIPTOR(*itf, str_index, DFU_ATTRS, 700, 64)
|
||||
};
|
||||
*itf+=1;
|
||||
memcpy(dst, descriptor, TUD_DFU_RT_DESC_LEN);
|
||||
return TUD_DFU_RT_DESC_LEN;
|
||||
}
|
||||
// Invoked on DFU_DETACH request to reboot to the bootloader
|
||||
void tud_dfu_rt_reboot_to_dfu(void)
|
||||
{
|
||||
usb_persist_restart(RESTART_BOOTLOADER_DFU);
|
||||
}
|
||||
#endif /* CFG_TUD_DFU_RT */
|
||||
|
||||
ESP_EVENT_DEFINE_BASE(ARDUINO_USB_EVENTS);
|
||||
|
||||
static esp_event_loop_handle_t arduino_usb_event_loop_handle = NULL;
|
||||
|
||||
esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait){
|
||||
if(arduino_usb_event_loop_handle == NULL){
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return esp_event_post_to(arduino_usb_event_loop_handle, event_base, event_id, event_data, event_data_size, ticks_to_wait);
|
||||
}
|
||||
esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg){
|
||||
if(arduino_usb_event_loop_handle == NULL){
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return esp_event_handler_register_with(arduino_usb_event_loop_handle, event_base, event_id, event_handler, event_handler_arg);
|
||||
}
|
||||
|
||||
static bool tinyusb_device_mounted = false;
|
||||
static bool tinyusb_device_suspended = false;
|
||||
|
||||
// Invoked when device is mounted (configured)
|
||||
void tud_mount_cb(void){
|
||||
tinyusb_device_mounted = true;
|
||||
arduino_usb_event_data_t p = {0};
|
||||
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STARTED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
||||
// Invoked when device is unmounted
|
||||
void tud_umount_cb(void){
|
||||
tinyusb_device_mounted = false;
|
||||
arduino_usb_event_data_t p = {0};
|
||||
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
||||
// Invoked when usb bus is suspended
|
||||
// Within 7ms, device must draw an average of current less than 2.5 mA from bus
|
||||
void tud_suspend_cb(bool remote_wakeup_en){
|
||||
tinyusb_device_suspended = true;
|
||||
arduino_usb_event_data_t p = {0};
|
||||
p.suspend.remote_wakeup_en = remote_wakeup_en;
|
||||
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_SUSPEND_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
||||
// Invoked when usb bus is resumed
|
||||
void tud_resume_cb(void){
|
||||
tinyusb_device_suspended = false;
|
||||
arduino_usb_event_data_t p = {0};
|
||||
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_RESUME_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
||||
ESPUSB::ESPUSB(size_t task_stack_size, uint8_t event_task_priority)
|
||||
:vid(USB_VID)
|
||||
,pid(USB_PID)
|
||||
,product_name(USB_PRODUCT)
|
||||
,manufacturer_name(USB_MANUFACTURER)
|
||||
,serial_number(USB_SERIAL)
|
||||
,fw_version(0x0100)
|
||||
,usb_version(0x0200)// at least 2.1 or 3.x for BOS & webUSB
|
||||
,usb_class(TUSB_CLASS_MISC)
|
||||
,usb_subclass(MISC_SUBCLASS_COMMON)
|
||||
,usb_protocol(MISC_PROTOCOL_IAD)
|
||||
,usb_attributes(TUSB_DESC_CONFIG_ATT_SELF_POWERED)
|
||||
,usb_power_ma(500)
|
||||
,webusb_enabled(false)
|
||||
,webusb_url("espressif.github.io/arduino-esp32/webusb.html")
|
||||
,_started(false)
|
||||
,_task_stack_size(task_stack_size)
|
||||
,_event_task_priority(event_task_priority)
|
||||
{
|
||||
if (!arduino_usb_event_loop_handle) {
|
||||
esp_event_loop_args_t event_task_args = {
|
||||
.queue_size = 5,
|
||||
.task_name = "arduino_usb_events",
|
||||
.task_priority = _event_task_priority,
|
||||
.task_stack_size = _task_stack_size,
|
||||
.task_core_id = tskNO_AFFINITY
|
||||
};
|
||||
if (esp_event_loop_create(&event_task_args, &arduino_usb_event_loop_handle) != ESP_OK) {
|
||||
log_e("esp_event_loop_create failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ESPUSB::~ESPUSB(){
|
||||
if (arduino_usb_event_loop_handle) {
|
||||
esp_event_loop_delete(arduino_usb_event_loop_handle);
|
||||
arduino_usb_event_loop_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool ESPUSB::begin(){
|
||||
if(!_started){
|
||||
tinyusb_device_config_t tinyusb_device_config = {
|
||||
.vid = vid,
|
||||
.pid = pid,
|
||||
.product_name = product_name.c_str(),
|
||||
.manufacturer_name = manufacturer_name.c_str(),
|
||||
.serial_number = serial_number.c_str(),
|
||||
.fw_version = fw_version,
|
||||
.usb_version = usb_version,
|
||||
.usb_class = usb_class,
|
||||
.usb_subclass = usb_subclass,
|
||||
.usb_protocol = usb_protocol,
|
||||
.usb_attributes = usb_attributes,
|
||||
.usb_power_ma = usb_power_ma,
|
||||
.webusb_enabled = webusb_enabled,
|
||||
.webusb_url = webusb_url.c_str()
|
||||
};
|
||||
_started = tinyusb_init(&tinyusb_device_config) == ESP_OK;
|
||||
}
|
||||
return _started;
|
||||
}
|
||||
|
||||
void ESPUSB::onEvent(esp_event_handler_t callback){
|
||||
onEvent(ARDUINO_USB_ANY_EVENT, callback);
|
||||
}
|
||||
void ESPUSB::onEvent(arduino_usb_event_t event, esp_event_handler_t callback){
|
||||
arduino_usb_event_handler_register_with(ARDUINO_USB_EVENTS, event, callback, this);
|
||||
}
|
||||
|
||||
ESPUSB::operator bool() const
|
||||
{
|
||||
return _started && tinyusb_device_mounted;
|
||||
}
|
||||
|
||||
bool ESPUSB::enableDFU(){
|
||||
#if CFG_TUD_DFU_RT
|
||||
return tinyusb_enable_interface(USB_INTERFACE_DFU, TUD_DFU_RT_DESC_LEN, load_dfu_descriptor) == ESP_OK;
|
||||
#endif /* CFG_TUD_DFU_RT */
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ESPUSB::VID(uint16_t v){
|
||||
if(!_started){
|
||||
vid = v;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
uint16_t ESPUSB::VID(void){
|
||||
return vid;
|
||||
}
|
||||
|
||||
bool ESPUSB::PID(uint16_t p){
|
||||
if(!_started){
|
||||
pid = p;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
uint16_t ESPUSB::PID(void){
|
||||
return pid;
|
||||
}
|
||||
|
||||
bool ESPUSB::firmwareVersion(uint16_t version){
|
||||
if(!_started){
|
||||
fw_version = version;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
uint16_t ESPUSB::firmwareVersion(void){
|
||||
return fw_version;
|
||||
}
|
||||
|
||||
bool ESPUSB::usbVersion(uint16_t version){
|
||||
if(!_started){
|
||||
usb_version = version;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
uint16_t ESPUSB::usbVersion(void){
|
||||
return usb_version;
|
||||
}
|
||||
|
||||
bool ESPUSB::usbPower(uint16_t mA){
|
||||
if(!_started){
|
||||
usb_power_ma = mA;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
uint16_t ESPUSB::usbPower(void){
|
||||
return usb_power_ma;
|
||||
}
|
||||
|
||||
bool ESPUSB::usbClass(uint8_t _class){
|
||||
if(!_started){
|
||||
usb_class = _class;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
uint8_t ESPUSB::usbClass(void){
|
||||
return usb_class;
|
||||
}
|
||||
|
||||
bool ESPUSB::usbSubClass(uint8_t subClass){
|
||||
if(!_started){
|
||||
usb_subclass = subClass;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
uint8_t ESPUSB::usbSubClass(void){
|
||||
return usb_subclass;
|
||||
}
|
||||
|
||||
bool ESPUSB::usbProtocol(uint8_t protocol){
|
||||
if(!_started){
|
||||
usb_protocol = protocol;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
uint8_t ESPUSB::usbProtocol(void){
|
||||
return usb_protocol;
|
||||
}
|
||||
|
||||
bool ESPUSB::usbAttributes(uint8_t attr){
|
||||
if(!_started){
|
||||
usb_attributes = attr;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
uint8_t ESPUSB::usbAttributes(void){
|
||||
return usb_attributes;
|
||||
}
|
||||
|
||||
bool ESPUSB::webUSB(bool enabled){
|
||||
if(!_started){
|
||||
webusb_enabled = enabled;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
bool ESPUSB::webUSB(void){
|
||||
return webusb_enabled;
|
||||
}
|
||||
|
||||
bool ESPUSB::productName(const char * name){
|
||||
if(!_started){
|
||||
product_name = name;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
const char * ESPUSB::productName(void){
|
||||
return product_name.c_str();
|
||||
}
|
||||
|
||||
bool ESPUSB::manufacturerName(const char * name){
|
||||
if(!_started){
|
||||
manufacturer_name = name;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
const char * ESPUSB::manufacturerName(void){
|
||||
return manufacturer_name.c_str();
|
||||
}
|
||||
|
||||
bool ESPUSB::serialNumber(const char * name){
|
||||
if(!_started){
|
||||
serial_number = name;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
const char * ESPUSB::serialNumber(void){
|
||||
return serial_number.c_str();
|
||||
}
|
||||
|
||||
bool ESPUSB::webUSBURL(const char * name){
|
||||
if(!_started){
|
||||
webusb_url = name;
|
||||
}
|
||||
return !_started;
|
||||
}
|
||||
const char * ESPUSB::webUSBURL(void){
|
||||
return webusb_url.c_str();
|
||||
}
|
||||
|
||||
ESPUSB USB;
|
||||
|
||||
#endif /* CONFIG_USB_ENABLED */
|
118
cores/esp32/USB.h
Normal file
118
cores/esp32/USB.h
Normal file
@ -0,0 +1,118 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#if CONFIG_USB_ENABLED
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "USBCDC.h"
|
||||
|
||||
#include "esp_event.h"
|
||||
|
||||
ESP_EVENT_DECLARE_BASE(ARDUINO_USB_EVENTS);
|
||||
|
||||
typedef enum {
|
||||
ARDUINO_USB_ANY_EVENT = ESP_EVENT_ANY_ID,
|
||||
ARDUINO_USB_STARTED_EVENT = 0,
|
||||
ARDUINO_USB_STOPPED_EVENT,
|
||||
ARDUINO_USB_SUSPEND_EVENT,
|
||||
ARDUINO_USB_RESUME_EVENT,
|
||||
ARDUINO_USB_MAX_EVENT,
|
||||
} arduino_usb_event_t;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
bool remote_wakeup_en;
|
||||
} suspend;
|
||||
} arduino_usb_event_data_t;
|
||||
|
||||
class ESPUSB {
|
||||
public:
|
||||
ESPUSB(size_t event_task_stack_size=2048, uint8_t event_task_priority=5);
|
||||
~ESPUSB();
|
||||
|
||||
void onEvent(esp_event_handler_t callback);
|
||||
void onEvent(arduino_usb_event_t event, esp_event_handler_t callback);
|
||||
|
||||
bool VID(uint16_t v);
|
||||
uint16_t VID(void);
|
||||
|
||||
bool PID(uint16_t p);
|
||||
uint16_t PID(void);
|
||||
|
||||
bool firmwareVersion(uint16_t version);
|
||||
uint16_t firmwareVersion(void);
|
||||
|
||||
bool usbVersion(uint16_t version);
|
||||
uint16_t usbVersion(void);
|
||||
|
||||
bool usbPower(uint16_t mA);
|
||||
uint16_t usbPower(void);
|
||||
|
||||
bool usbClass(uint8_t _class);
|
||||
uint8_t usbClass(void);
|
||||
|
||||
bool usbSubClass(uint8_t subClass);
|
||||
uint8_t usbSubClass(void);
|
||||
|
||||
bool usbProtocol(uint8_t protocol);
|
||||
uint8_t usbProtocol(void);
|
||||
|
||||
bool usbAttributes(uint8_t attr);
|
||||
uint8_t usbAttributes(void);
|
||||
|
||||
bool webUSB(bool enabled);
|
||||
bool webUSB(void);
|
||||
|
||||
bool productName(const char * name);
|
||||
const char * productName(void);
|
||||
|
||||
bool manufacturerName(const char * name);
|
||||
const char * manufacturerName(void);
|
||||
|
||||
bool serialNumber(const char * name);
|
||||
const char * serialNumber(void);
|
||||
|
||||
bool webUSBURL(const char * name);
|
||||
const char * webUSBURL(void);
|
||||
|
||||
bool enableDFU();
|
||||
bool begin();
|
||||
operator bool() const;
|
||||
|
||||
private:
|
||||
uint16_t vid;
|
||||
uint16_t pid;
|
||||
String product_name;
|
||||
String manufacturer_name;
|
||||
String serial_number;
|
||||
uint16_t fw_version;
|
||||
uint16_t usb_version;
|
||||
uint8_t usb_class;
|
||||
uint8_t usb_subclass;
|
||||
uint8_t usb_protocol;
|
||||
uint8_t usb_attributes;
|
||||
uint16_t usb_power_ma;
|
||||
bool webusb_enabled;
|
||||
String webusb_url;
|
||||
|
||||
bool _started;
|
||||
size_t _task_stack_size;
|
||||
uint8_t _event_task_priority;
|
||||
};
|
||||
|
||||
extern ESPUSB USB;
|
||||
|
||||
#endif /* CONFIG_USB_ENABLED */
|
338
cores/esp32/USBCDC.cpp
Normal file
338
cores/esp32/USBCDC.cpp
Normal file
@ -0,0 +1,338 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "esp32-hal.h"
|
||||
#include "esp32-hal-tinyusb.h"
|
||||
#include "USB.h"
|
||||
#include "USBCDC.h"
|
||||
#if CONFIG_USB_ENABLED
|
||||
|
||||
ESP_EVENT_DEFINE_BASE(ARDUINO_USB_CDC_EVENTS);
|
||||
esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait);
|
||||
esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg);
|
||||
|
||||
extern "C" {
|
||||
#include "tinyusb.h"
|
||||
}
|
||||
|
||||
#if CFG_TUD_CDC
|
||||
#define MAX_USB_CDC_DEVICES 2
|
||||
USBCDC * devices[MAX_USB_CDC_DEVICES] = {NULL, NULL};
|
||||
|
||||
static uint16_t load_cdc_descriptor(uint8_t * dst, uint8_t * itf)
|
||||
{
|
||||
uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB CDC");
|
||||
// Interface number, string index, attributes, detach timeout, transfer size */
|
||||
uint8_t descriptor[TUD_CDC_DESC_LEN] = {
|
||||
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
|
||||
TUD_CDC_DESCRIPTOR(*itf, str_index, 0x85, 64, 0x03, 0x84, 64)
|
||||
};
|
||||
*itf+=2;
|
||||
memcpy(dst, descriptor, TUD_CDC_DESC_LEN);
|
||||
return TUD_CDC_DESC_LEN;
|
||||
}
|
||||
|
||||
void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
|
||||
{
|
||||
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){
|
||||
devices[itf]->_onLineState(dtr, rts);
|
||||
}
|
||||
}
|
||||
|
||||
void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding)
|
||||
{
|
||||
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){
|
||||
devices[itf]->_onLineCoding(p_line_coding->bit_rate, p_line_coding->stop_bits, p_line_coding->parity, p_line_coding->data_bits);
|
||||
}
|
||||
}
|
||||
|
||||
void tud_cdc_rx_cb(uint8_t itf)
|
||||
{
|
||||
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){
|
||||
devices[itf]->_onRX();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static size_t tinyusb_cdc_write(uint8_t itf, const uint8_t *buffer, size_t size){
|
||||
if(itf >= MAX_USB_CDC_DEVICES){
|
||||
return 0;
|
||||
}
|
||||
if(!tud_cdc_n_connected(itf)){
|
||||
return 0;
|
||||
}
|
||||
size_t tosend = size, sofar = 0;
|
||||
while(tosend){
|
||||
uint32_t space = tud_cdc_n_write_available(itf);
|
||||
if(!space){
|
||||
delay(1);
|
||||
continue;
|
||||
}
|
||||
if(tosend < space){
|
||||
space = tosend;
|
||||
}
|
||||
uint32_t sent = tud_cdc_n_write(itf, buffer + sofar, space);
|
||||
if(!sent){
|
||||
return sofar;
|
||||
}
|
||||
sofar += sent;
|
||||
tosend -= sent;
|
||||
tud_cdc_n_write_flush(itf);
|
||||
}
|
||||
return sofar;
|
||||
}
|
||||
|
||||
static void ARDUINO_ISR_ATTR cdc0_write_char(char c)
|
||||
{
|
||||
tinyusb_cdc_write(0, (const uint8_t *)&c, 1);
|
||||
}
|
||||
|
||||
//void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char);
|
||||
|
||||
static void usb_unplugged_cb(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){
|
||||
((USBCDC*)arg)->_onUnplugged();
|
||||
}
|
||||
|
||||
USBCDC::USBCDC(uint8_t itfn) : itf(itfn), bit_rate(0), stop_bits(0), parity(0), data_bits(0), dtr(false), rts(false), connected(false), reboot_enable(true), rx_queue(NULL) {
|
||||
tinyusb_enable_interface(USB_INTERFACE_CDC, TUD_CDC_DESC_LEN, load_cdc_descriptor);
|
||||
if(itf < MAX_USB_CDC_DEVICES){
|
||||
devices[itf] = this;
|
||||
arduino_usb_event_handler_register_with(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, usb_unplugged_cb, this);
|
||||
}
|
||||
}
|
||||
|
||||
void USBCDC::onEvent(esp_event_handler_t callback){
|
||||
onEvent(ARDUINO_USB_CDC_ANY_EVENT, callback);
|
||||
}
|
||||
void USBCDC::onEvent(arduino_usb_cdc_event_t event, esp_event_handler_t callback){
|
||||
arduino_usb_event_handler_register_with(ARDUINO_USB_CDC_EVENTS, event, callback, this);
|
||||
}
|
||||
|
||||
size_t USBCDC::setRxBufferSize(size_t rx_queue_len){
|
||||
if(rx_queue){
|
||||
return 0;
|
||||
}
|
||||
rx_queue = xQueueCreate(rx_queue_len, sizeof(uint8_t));
|
||||
if(!rx_queue){
|
||||
return 0;
|
||||
}
|
||||
return rx_queue_len;
|
||||
}
|
||||
|
||||
void USBCDC::begin(unsigned long baud)
|
||||
{
|
||||
setRxBufferSize(256);//default if not preset
|
||||
}
|
||||
|
||||
void USBCDC::end()
|
||||
{
|
||||
}
|
||||
|
||||
void USBCDC::_onUnplugged(void){
|
||||
if(connected){
|
||||
connected = false;
|
||||
dtr = false;
|
||||
rts = false;
|
||||
arduino_usb_cdc_event_data_t p = {0};
|
||||
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_DISCONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
enum { CDC_LINE_IDLE, CDC_LINE_1, CDC_LINE_2, CDC_LINE_3 };
|
||||
void USBCDC::_onLineState(bool _dtr, bool _rts){
|
||||
static uint8_t lineState = CDC_LINE_IDLE;
|
||||
dtr = _dtr;
|
||||
rts = _rts;
|
||||
|
||||
if(reboot_enable){
|
||||
if(!dtr && rts){
|
||||
if(lineState == CDC_LINE_IDLE){
|
||||
lineState++;
|
||||
} else {
|
||||
lineState = CDC_LINE_IDLE;
|
||||
}
|
||||
} else if(dtr && rts){
|
||||
if(lineState == CDC_LINE_1){
|
||||
lineState++;
|
||||
} else {
|
||||
lineState = CDC_LINE_IDLE;
|
||||
}
|
||||
} else if(dtr && !rts){
|
||||
if(lineState == CDC_LINE_2){
|
||||
lineState++;
|
||||
} else {
|
||||
lineState = CDC_LINE_IDLE;
|
||||
}
|
||||
} else if(!dtr && !rts){
|
||||
if(lineState == CDC_LINE_3){
|
||||
usb_persist_restart(RESTART_BOOTLOADER);
|
||||
} else {
|
||||
lineState = CDC_LINE_IDLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(lineState == CDC_LINE_IDLE){
|
||||
if(dtr && rts && !connected){
|
||||
connected = true;
|
||||
arduino_usb_cdc_event_data_t p = {0};
|
||||
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_CONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
|
||||
} else if(!dtr && !rts && connected){
|
||||
connected = false;
|
||||
arduino_usb_cdc_event_data_t p = {0};
|
||||
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_DISCONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
arduino_usb_cdc_event_data_t l = {0};
|
||||
l.line_state.dtr = dtr;
|
||||
l.line_state.rts = rts;
|
||||
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_LINE_STATE_EVENT, &l, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void USBCDC::_onLineCoding(uint32_t _bit_rate, uint8_t _stop_bits, uint8_t _parity, uint8_t _data_bits){
|
||||
if(bit_rate != _bit_rate || data_bits != _data_bits || stop_bits != _stop_bits || parity != _parity){
|
||||
bit_rate = _bit_rate;
|
||||
data_bits = _data_bits;
|
||||
stop_bits = _stop_bits;
|
||||
parity = _parity;
|
||||
arduino_usb_cdc_event_data_t p = {0};
|
||||
p.line_coding.bit_rate = bit_rate;
|
||||
p.line_coding.data_bits = data_bits;
|
||||
p.line_coding.stop_bits = stop_bits;
|
||||
p.line_coding.parity = parity;
|
||||
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_LINE_CODING_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
void USBCDC::_onRX(){
|
||||
uint8_t buf[CONFIG_USB_CDC_RX_BUFSIZE+1];
|
||||
uint32_t count = tud_cdc_n_read(itf, buf, CONFIG_USB_CDC_RX_BUFSIZE);
|
||||
for(uint32_t i=0; i<count; i++){
|
||||
if(rx_queue == NULL || !xQueueSend(rx_queue, buf+i, 0)){
|
||||
return;
|
||||
}
|
||||
}
|
||||
arduino_usb_cdc_event_data_t p = {0};
|
||||
p.rx.len = count;
|
||||
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_RX_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
||||
void USBCDC::enableReboot(bool enable){
|
||||
reboot_enable = enable;
|
||||
}
|
||||
bool USBCDC::rebootEnabled(void){
|
||||
return reboot_enable;
|
||||
}
|
||||
|
||||
int USBCDC::available(void)
|
||||
{
|
||||
if(itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL){
|
||||
return -1;
|
||||
}
|
||||
return uxQueueMessagesWaiting(rx_queue);
|
||||
}
|
||||
|
||||
int USBCDC::peek(void)
|
||||
{
|
||||
if(itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL){
|
||||
return -1;
|
||||
}
|
||||
uint8_t c;
|
||||
if(xQueuePeek(rx_queue, &c, 0)) {
|
||||
return c;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int USBCDC::read(void)
|
||||
{
|
||||
if(itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL){
|
||||
return -1;
|
||||
}
|
||||
uint8_t c = 0;
|
||||
if(xQueueReceive(rx_queue, &c, 0)) {
|
||||
return c;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t USBCDC::read(uint8_t *buffer, size_t size)
|
||||
{
|
||||
if(itf >= MAX_USB_CDC_DEVICES || rx_queue == NULL){
|
||||
return -1;
|
||||
}
|
||||
uint8_t c = 0;
|
||||
size_t count = 0;
|
||||
while(count < size && xQueueReceive(rx_queue, &c, 0)){
|
||||
buffer[count++] = c;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void USBCDC::flush(void)
|
||||
{
|
||||
if(itf >= MAX_USB_CDC_DEVICES){
|
||||
return;
|
||||
}
|
||||
tud_cdc_n_write_flush(itf);
|
||||
}
|
||||
|
||||
int USBCDC::availableForWrite(void)
|
||||
{
|
||||
if(itf >= MAX_USB_CDC_DEVICES){
|
||||
return -1;
|
||||
}
|
||||
return tud_cdc_n_write_available(itf);
|
||||
}
|
||||
|
||||
size_t USBCDC::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
return tinyusb_cdc_write(itf, buffer, size);
|
||||
}
|
||||
|
||||
size_t USBCDC::write(uint8_t c)
|
||||
{
|
||||
return write(&c, 1);
|
||||
}
|
||||
|
||||
uint32_t USBCDC::baudRate()
|
||||
{
|
||||
return bit_rate;
|
||||
}
|
||||
|
||||
void USBCDC::setDebugOutput(bool en)
|
||||
{
|
||||
if(en) {
|
||||
uartSetDebug(NULL);
|
||||
ets_install_putc1((void (*)(char)) &cdc0_write_char);
|
||||
} else {
|
||||
ets_install_putc1(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
USBCDC::operator bool() const
|
||||
{
|
||||
if(itf >= MAX_USB_CDC_DEVICES){
|
||||
return false;
|
||||
}
|
||||
return connected;
|
||||
}
|
||||
|
||||
#if ARDUINO_SERIAL_PORT //Serial used for USB CDC
|
||||
USBCDC Serial(0);
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_USB_CDC_ENABLED */
|
||||
|
||||
#endif /* CONFIG_USB_ENABLED */
|
133
cores/esp32/USBCDC.h
Normal file
133
cores/esp32/USBCDC.h
Normal file
@ -0,0 +1,133 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "Stream.h"
|
||||
#include "esp32-hal.h"
|
||||
#if CONFIG_USB_CDC_ENABLED
|
||||
|
||||
#include "esp_event.h"
|
||||
|
||||
ESP_EVENT_DECLARE_BASE(ARDUINO_USB_CDC_EVENTS);
|
||||
|
||||
typedef enum {
|
||||
ARDUINO_USB_CDC_ANY_EVENT = ESP_EVENT_ANY_ID,
|
||||
ARDUINO_USB_CDC_CONNECTED_EVENT = 0,
|
||||
ARDUINO_USB_CDC_DISCONNECTED_EVENT,
|
||||
ARDUINO_USB_CDC_LINE_STATE_EVENT,
|
||||
ARDUINO_USB_CDC_LINE_CODING_EVENT,
|
||||
ARDUINO_USB_CDC_RX_EVENT,
|
||||
ARDUINO_USB_CDC_MAX_EVENT,
|
||||
} arduino_usb_cdc_event_t;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
bool dtr;
|
||||
bool rts;
|
||||
} line_state;
|
||||
struct {
|
||||
uint32_t bit_rate;
|
||||
uint8_t stop_bits; ///< 0: 1 stop bit - 1: 1.5 stop bits - 2: 2 stop bits
|
||||
uint8_t parity; ///< 0: None - 1: Odd - 2: Even - 3: Mark - 4: Space
|
||||
uint8_t data_bits; ///< can be 5, 6, 7, 8 or 16
|
||||
} line_coding;
|
||||
struct {
|
||||
size_t len;
|
||||
} rx;
|
||||
} arduino_usb_cdc_event_data_t;
|
||||
|
||||
class USBCDC: public Stream
|
||||
{
|
||||
public:
|
||||
USBCDC(uint8_t itf=0);
|
||||
|
||||
void onEvent(esp_event_handler_t callback);
|
||||
void onEvent(arduino_usb_cdc_event_t event, esp_event_handler_t callback);
|
||||
|
||||
size_t setRxBufferSize(size_t);
|
||||
void begin(unsigned long baud=0);
|
||||
void end();
|
||||
|
||||
int available(void);
|
||||
int availableForWrite(void);
|
||||
int peek(void);
|
||||
int read(void);
|
||||
size_t read(uint8_t *buffer, size_t size);
|
||||
size_t write(uint8_t);
|
||||
size_t write(const uint8_t *buffer, size_t size);
|
||||
void flush(void);
|
||||
|
||||
inline size_t read(char * buffer, size_t size)
|
||||
{
|
||||
return read((uint8_t*) buffer, size);
|
||||
}
|
||||
inline size_t write(const char * buffer, size_t size)
|
||||
{
|
||||
return write((uint8_t*) buffer, size);
|
||||
}
|
||||
inline size_t write(const char * s)
|
||||
{
|
||||
return write((uint8_t*) s, strlen(s));
|
||||
}
|
||||
inline size_t write(unsigned long n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(long n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(unsigned int n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(int n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
uint32_t baudRate();
|
||||
void setDebugOutput(bool);
|
||||
operator bool() const;
|
||||
|
||||
void enableReboot(bool enable);
|
||||
bool rebootEnabled(void);
|
||||
|
||||
//internal methods
|
||||
void _onDFU(void);
|
||||
void _onLineState(bool _dtr, bool _rts);
|
||||
void _onLineCoding(uint32_t _bit_rate, uint8_t _stop_bits, uint8_t _parity, uint8_t _data_bits);
|
||||
void _onRX(void);
|
||||
void _onUnplugged(void);
|
||||
|
||||
protected:
|
||||
uint8_t itf;
|
||||
uint32_t bit_rate;
|
||||
uint8_t stop_bits; ///< 0: 1 stop bit - 1: 1.5 stop bits - 2: 2 stop bits
|
||||
uint8_t parity; ///< 0: None - 1: Odd - 2: Even - 3: Mark - 4: Space
|
||||
uint8_t data_bits; ///< can be 5, 6, 7, 8 or 16
|
||||
bool dtr;
|
||||
bool rts;
|
||||
bool connected;
|
||||
bool reboot_enable;
|
||||
xQueueHandle rx_queue;
|
||||
|
||||
};
|
||||
|
||||
#if ARDUINO_SERIAL_PORT //Serial used for USB CDC
|
||||
extern USBCDC Serial;
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_USB_CDC_ENABLED */
|
@ -37,10 +37,23 @@ void randomSeed(unsigned long seed)
|
||||
|
||||
long random(long howbig)
|
||||
{
|
||||
if(howbig == 0) {
|
||||
return 0;
|
||||
uint32_t x = esp_random();
|
||||
uint64_t m = uint64_t(x) * uint64_t(howbig);
|
||||
uint32_t l = uint32_t(m);
|
||||
if (l < howbig) {
|
||||
uint32_t t = -howbig;
|
||||
if (t >= howbig) {
|
||||
t -= howbig;
|
||||
if (t >= howbig)
|
||||
t %= howbig;
|
||||
}
|
||||
return esp_random() % howbig;
|
||||
while (l < t) {
|
||||
x = esp_random();
|
||||
m = uint64_t(x) * uint64_t(howbig);
|
||||
l = uint32_t(m);
|
||||
}
|
||||
}
|
||||
return m >> 32;
|
||||
}
|
||||
|
||||
long random(long howsmall, long howbig)
|
||||
@ -52,9 +65,12 @@ long random(long howsmall, long howbig)
|
||||
return random(diff) + howsmall;
|
||||
}
|
||||
|
||||
long map(long x, long in_min, long in_max, long out_min, long out_max)
|
||||
{
|
||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
long map(long x, long in_min, long in_max, long out_min, long out_max) {
|
||||
long divisor = (in_max - in_min);
|
||||
if(divisor == 0){
|
||||
return -1; //AVR returns -1, SAM returns 0
|
||||
}
|
||||
return (x - in_min) * (out_max - out_min) / divisor + out_min;
|
||||
}
|
||||
|
||||
unsigned int makeWord(unsigned int w)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -27,6 +27,7 @@
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <pgmspace.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// An inherited class for holding the result of a concatenation. These
|
||||
// result objects are assumed to be writable by subsequent concatenations.
|
||||
@ -35,17 +36,16 @@ class StringSumHelper;
|
||||
// an abstract class used as a means to proide a unique pointer type
|
||||
// but really has no body
|
||||
class __FlashStringHelper;
|
||||
#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))
|
||||
#define FPSTR(pstr_pointer) (reinterpret_cast<const __FlashStringHelper *>(pstr_pointer))
|
||||
#define F(string_literal) (FPSTR(PSTR(string_literal)))
|
||||
|
||||
// The string class
|
||||
class String
|
||||
{
|
||||
class String {
|
||||
// use a function pointer to allow for "if (s)" without the
|
||||
// complications of an operator bool(). for more information, see:
|
||||
// http://www.artima.com/cppsource/safebool.html
|
||||
typedef void (String::*StringIfHelperType)() const;
|
||||
void StringIfHelper() const
|
||||
{
|
||||
void StringIfHelper() const {
|
||||
}
|
||||
|
||||
public:
|
||||
@ -56,7 +56,7 @@ public:
|
||||
// be false).
|
||||
String(const char *cstr = "");
|
||||
String(const String &str);
|
||||
String(const __FlashStringHelper *str) : String(reinterpret_cast<const char *>(str)) {};
|
||||
String(const __FlashStringHelper *str);
|
||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
||||
String(String &&rval);
|
||||
String(StringSumHelper &&rval);
|
||||
@ -76,14 +76,19 @@ public:
|
||||
// is left unchanged). reserve(0), if successful, will validate an
|
||||
// invalid string (i.e., "if (s)" will be true afterwards)
|
||||
unsigned char reserve(unsigned int size);
|
||||
inline unsigned int length(void) const
|
||||
{
|
||||
if(buffer) {
|
||||
return len;
|
||||
inline unsigned int length(void) const {
|
||||
if(buffer()) {
|
||||
return len();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
inline void clear(void) {
|
||||
setLen(0);
|
||||
}
|
||||
inline bool isEmpty(void) const {
|
||||
return length() == 0;
|
||||
}
|
||||
|
||||
// creates a copy of the assigned value. if the value is null or
|
||||
// invalid, or if the memory allocation fails, the string will be
|
||||
@ -100,7 +105,7 @@ public:
|
||||
|
||||
// returns true on success, false on failure (in which case, the string
|
||||
// is left unchanged). if the argument is null or invalid, the
|
||||
// concatenation is considered unsucessful.
|
||||
// concatenation is considered unsuccessful.
|
||||
unsigned char concat(const String &str);
|
||||
unsigned char concat(const char *cstr);
|
||||
unsigned char concat(char c);
|
||||
@ -115,58 +120,47 @@ public:
|
||||
|
||||
// if there's not enough memory for the concatenated value, the string
|
||||
// will be left unchanged (but this isn't signalled in any way)
|
||||
String & operator +=(const String &rhs)
|
||||
{
|
||||
String & operator +=(const String &rhs) {
|
||||
concat(rhs);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(const char *cstr)
|
||||
{
|
||||
String & operator +=(const char *cstr) {
|
||||
concat(cstr);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(char c)
|
||||
{
|
||||
String & operator +=(char c) {
|
||||
concat(c);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(unsigned char num)
|
||||
{
|
||||
String & operator +=(unsigned char num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(int num)
|
||||
{
|
||||
String & operator +=(int num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(unsigned int num)
|
||||
{
|
||||
String & operator +=(unsigned int num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(long num)
|
||||
{
|
||||
String & operator +=(long num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(unsigned long num)
|
||||
{
|
||||
String & operator +=(unsigned long num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(float num)
|
||||
{
|
||||
String & operator +=(float num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(double num)
|
||||
{
|
||||
String & operator +=(double num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator += (const __FlashStringHelper *str)
|
||||
{
|
||||
String & operator += (const __FlashStringHelper *str){
|
||||
concat(str);
|
||||
return (*this);
|
||||
}
|
||||
@ -184,27 +178,22 @@ public:
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, const __FlashStringHelper *rhs);
|
||||
|
||||
// comparison (only works w/ Strings and "strings")
|
||||
operator StringIfHelperType() const
|
||||
{
|
||||
return buffer ? &String::StringIfHelper : 0;
|
||||
operator StringIfHelperType() const {
|
||||
return buffer() ? &String::StringIfHelper : 0;
|
||||
}
|
||||
int compareTo(const String &s) const;
|
||||
unsigned char equals(const String &s) const;
|
||||
unsigned char equals(const char *cstr) const;
|
||||
unsigned char operator ==(const String &rhs) const
|
||||
{
|
||||
unsigned char operator ==(const String &rhs) const {
|
||||
return equals(rhs);
|
||||
}
|
||||
unsigned char operator ==(const char *cstr) const
|
||||
{
|
||||
unsigned char operator ==(const char *cstr) const {
|
||||
return equals(cstr);
|
||||
}
|
||||
unsigned char operator !=(const String &rhs) const
|
||||
{
|
||||
unsigned char operator !=(const String &rhs) const {
|
||||
return !equals(rhs);
|
||||
}
|
||||
unsigned char operator !=(const char *cstr) const
|
||||
{
|
||||
unsigned char operator !=(const char *cstr) const {
|
||||
return !equals(cstr);
|
||||
}
|
||||
unsigned char operator <(const String &rhs) const;
|
||||
@ -214,23 +203,35 @@ public:
|
||||
unsigned char equalsIgnoreCase(const String &s) const;
|
||||
unsigned char equalsConstantTime(const String &s) const;
|
||||
unsigned char startsWith(const String &prefix) const;
|
||||
unsigned char startsWith(const char *prefix) const {
|
||||
return this->startsWith(String(prefix));
|
||||
}
|
||||
unsigned char startsWith(const __FlashStringHelper *prefix) const {
|
||||
return this->startsWith(String(prefix));
|
||||
}
|
||||
unsigned char startsWith(const String &prefix, unsigned int offset) const;
|
||||
unsigned char endsWith(const String &suffix) const;
|
||||
unsigned char endsWith(const char *suffix) const {
|
||||
return this->endsWith(String(suffix));
|
||||
}
|
||||
unsigned char endsWith(const __FlashStringHelper * suffix) const {
|
||||
return this->endsWith(String(suffix));
|
||||
}
|
||||
|
||||
// character acccess
|
||||
// character access
|
||||
char charAt(unsigned int index) const;
|
||||
void setCharAt(unsigned int index, char c);
|
||||
char operator [](unsigned int index) const;
|
||||
char& operator [](unsigned int index);
|
||||
void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index = 0) const;
|
||||
void toCharArray(char *buf, unsigned int bufsize, unsigned int index = 0) const
|
||||
{
|
||||
void toCharArray(char *buf, unsigned int bufsize, unsigned int index = 0) const {
|
||||
getBytes((unsigned char *) buf, bufsize, index);
|
||||
}
|
||||
const char * c_str() const
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
const char* c_str() const { return buffer(); }
|
||||
char* begin() { return wbuffer(); }
|
||||
char* end() { return wbuffer() + length(); }
|
||||
const char* begin() const { return c_str(); }
|
||||
const char* end() const { return c_str() + length(); }
|
||||
|
||||
// search
|
||||
int indexOf(char ch) const;
|
||||
@ -241,9 +242,8 @@ public:
|
||||
int lastIndexOf(char ch, unsigned int fromIndex) const;
|
||||
int lastIndexOf(const String &str) const;
|
||||
int lastIndexOf(const String &str, unsigned int fromIndex) const;
|
||||
String substring(unsigned int beginIndex) const
|
||||
{
|
||||
return substring(beginIndex, len);
|
||||
String substring(unsigned int beginIndex) const {
|
||||
return substring(beginIndex, len());
|
||||
}
|
||||
;
|
||||
String substring(unsigned int beginIndex, unsigned int endIndex) const;
|
||||
@ -251,6 +251,21 @@ public:
|
||||
// modification
|
||||
void replace(char find, char replace);
|
||||
void replace(const String &find, const String &replace);
|
||||
void replace(const char *find, const String &replace) {
|
||||
this->replace(String(find), replace);
|
||||
}
|
||||
void replace(const __FlashStringHelper *find, const String &replace) {
|
||||
this->replace(String(find), replace);
|
||||
}
|
||||
void replace(const char *find, const char *replace) {
|
||||
this->replace(String(find), String(replace));
|
||||
}
|
||||
void replace(const __FlashStringHelper *find, const char *replace) {
|
||||
this->replace(String(find), String(replace));
|
||||
}
|
||||
void replace(const __FlashStringHelper *find, const __FlashStringHelper *replace) {
|
||||
this->replace(String(find), String(replace));
|
||||
}
|
||||
void remove(unsigned int index);
|
||||
void remove(unsigned int index, unsigned int count);
|
||||
void toLowerCase(void);
|
||||
@ -260,11 +275,39 @@ public:
|
||||
// parsing/conversion
|
||||
long toInt(void) const;
|
||||
float toFloat(void) const;
|
||||
double toDouble(void) const;
|
||||
|
||||
protected:
|
||||
char *buffer; // the actual char array
|
||||
unsigned int capacity; // the array length minus one (for the '\0')
|
||||
unsigned int len; // the String length (not counting the '\0')
|
||||
// Contains the string info when we're not in SSO mode
|
||||
struct _ptr {
|
||||
char * buff;
|
||||
uint16_t cap;
|
||||
uint16_t len;
|
||||
};
|
||||
// This allows strings up up to 11 (10 + \0 termination) without any extra space.
|
||||
enum { SSOSIZE = sizeof(struct _ptr) + 4 - 1 }; // Characters to allocate space for SSO, must be 12 or more
|
||||
struct _sso {
|
||||
char buff[SSOSIZE];
|
||||
unsigned char len : 7; // Ensure only one byte is allocated by GCC for the bitfields
|
||||
unsigned char isSSO : 1;
|
||||
} __attribute__((packed)); // Ensure that GCC doesn't expand the flag byte to a 32-bit word for alignment issues
|
||||
enum { CAPACITY_MAX = 65535 }; // If typeof(cap) changed from uint16_t, be sure to update this enum to the max value storable in the type
|
||||
union {
|
||||
struct _ptr ptr;
|
||||
struct _sso sso;
|
||||
};
|
||||
// Accessor functions
|
||||
inline bool isSSO() const { return sso.isSSO; }
|
||||
inline unsigned int len() const { return isSSO() ? sso.len : ptr.len; }
|
||||
inline unsigned int capacity() const { return isSSO() ? (unsigned int)SSOSIZE - 1 : ptr.cap; } // Size of max string not including terminal NUL
|
||||
inline void setSSO(bool set) { sso.isSSO = set; }
|
||||
inline void setLen(int len) { if (isSSO()) sso.len = len; else ptr.len = len; }
|
||||
inline void setCapacity(int cap) { if (!isSSO()) ptr.cap = cap; }
|
||||
inline void setBuffer(char *buff) { if (!isSSO()) ptr.buff = buff; }
|
||||
// Buffer accessor functions
|
||||
inline const char *buffer() const { return (const char *)(isSSO() ? sso.buff : ptr.buff); }
|
||||
inline char *wbuffer() const { return isSSO() ? const_cast<char *>(sso.buff) : ptr.buff; } // Writable version of buffer
|
||||
|
||||
protected:
|
||||
void init(void);
|
||||
void invalidate(void);
|
||||
@ -279,50 +322,41 @@ protected:
|
||||
#endif
|
||||
};
|
||||
|
||||
class StringSumHelper: public String
|
||||
{
|
||||
class StringSumHelper: public String {
|
||||
public:
|
||||
StringSumHelper(const String &s) :
|
||||
String(s)
|
||||
{
|
||||
String(s) {
|
||||
}
|
||||
StringSumHelper(const char *p) :
|
||||
String(p)
|
||||
{
|
||||
String(p) {
|
||||
}
|
||||
StringSumHelper(char c) :
|
||||
String(c)
|
||||
{
|
||||
String(c) {
|
||||
}
|
||||
StringSumHelper(unsigned char num) :
|
||||
String(num)
|
||||
{
|
||||
String(num) {
|
||||
}
|
||||
StringSumHelper(int num) :
|
||||
String(num)
|
||||
{
|
||||
String(num) {
|
||||
}
|
||||
StringSumHelper(unsigned int num) :
|
||||
String(num)
|
||||
{
|
||||
String(num) {
|
||||
}
|
||||
StringSumHelper(long num) :
|
||||
String(num)
|
||||
{
|
||||
String(num) {
|
||||
}
|
||||
StringSumHelper(unsigned long num) :
|
||||
String(num)
|
||||
{
|
||||
String(num) {
|
||||
}
|
||||
StringSumHelper(float num) :
|
||||
String(num)
|
||||
{
|
||||
String(num) {
|
||||
}
|
||||
StringSumHelper(double num) :
|
||||
String(num)
|
||||
{
|
||||
String(num) {
|
||||
}
|
||||
};
|
||||
|
||||
extern const String emptyString;
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // String_class_h
|
||||
|
1
cores/esp32/apps/sntp/sntp.h
Normal file
1
cores/esp32/apps/sntp/sntp.h
Normal file
@ -0,0 +1 @@
|
||||
#include "lwip/apps/sntp.h"
|
@ -31,14 +31,13 @@ extern "C" {
|
||||
|
||||
/**
|
||||
* convert input data to base64
|
||||
* @param data uint8_t *
|
||||
* @param data const uint8_t *
|
||||
* @param length size_t
|
||||
* @return String
|
||||
*/
|
||||
String base64::encode(uint8_t * data, size_t length)
|
||||
String base64::encode(const uint8_t * data, size_t length)
|
||||
{
|
||||
// base64 needs more size then the source data
|
||||
size_t size = ((length * 1.6f) + 1);
|
||||
size_t size = base64_encode_expected_len(length) + 1;
|
||||
char * buffer = (char *) malloc(size);
|
||||
if(buffer) {
|
||||
base64_encodestate _state;
|
||||
@ -55,10 +54,10 @@ String base64::encode(uint8_t * data, size_t length)
|
||||
|
||||
/**
|
||||
* convert input data to base64
|
||||
* @param text String
|
||||
* @param text const String&
|
||||
* @return String
|
||||
*/
|
||||
String base64::encode(String text)
|
||||
String base64::encode(const String& text)
|
||||
{
|
||||
return base64::encode((uint8_t *) text.c_str(), text.length());
|
||||
}
|
||||
|
@ -4,8 +4,8 @@
|
||||
class base64
|
||||
{
|
||||
public:
|
||||
static String encode(uint8_t * data, size_t length);
|
||||
static String encode(String text);
|
||||
static String encode(const uint8_t * data, size_t length);
|
||||
static String encode(const String& text);
|
||||
private:
|
||||
};
|
||||
|
||||
|
@ -15,103 +15,72 @@
|
||||
#include "esp32-hal-adc.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_intr.h"
|
||||
#include "soc/rtc_io_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/sens_reg.h"
|
||||
|
||||
#include "driver/adc.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp_adc_cal.h"
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#define DEFAULT_VREF 1100
|
||||
static esp_adc_cal_characteristics_t *__analogCharacteristics[2] = {NULL, NULL};
|
||||
static uint16_t __analogVRef = 0;
|
||||
static uint8_t __analogVRefPin = 0;
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/ets_sys.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_intr.h"
|
||||
#endif
|
||||
|
||||
static uint8_t __analogAttenuation = 3;//11db
|
||||
static uint8_t __analogWidth = 3;//12 bits
|
||||
static uint8_t __analogCycles = 8;
|
||||
static uint8_t __analogSamples = 0;//1 sample
|
||||
static uint8_t __analogClockDiv = 1;
|
||||
|
||||
// Width of returned answer ()
|
||||
static uint8_t __analogReturnedWidth = 12;
|
||||
void __analogSetClockDiv(uint8_t clockDiv){
|
||||
if(!clockDiv){
|
||||
clockDiv = 1;
|
||||
}
|
||||
__analogClockDiv = clockDiv;
|
||||
adc_set_clk_div(__analogClockDiv);
|
||||
}
|
||||
|
||||
void __analogSetAttenuation(adc_attenuation_t attenuation)
|
||||
{
|
||||
__analogAttenuation = attenuation & 3;
|
||||
}
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
void __analogSetWidth(uint8_t bits){
|
||||
if(bits < 9){
|
||||
bits = 9;
|
||||
} else if(bits > 12){
|
||||
bits = 12;
|
||||
}
|
||||
__analogReturnedWidth = bits;
|
||||
__analogWidth = bits - 9;
|
||||
SET_PERI_REG_BITS(SENS_SAR_START_FORCE_REG, SENS_SAR1_BIT_WIDTH, __analogWidth, SENS_SAR1_BIT_WIDTH_S);
|
||||
SET_PERI_REG_BITS(SENS_SAR_READ_CTRL_REG, SENS_SAR1_SAMPLE_BIT, __analogWidth, SENS_SAR1_SAMPLE_BIT_S);
|
||||
adc1_config_width(__analogWidth);
|
||||
}
|
||||
#endif
|
||||
|
||||
SET_PERI_REG_BITS(SENS_SAR_START_FORCE_REG, SENS_SAR2_BIT_WIDTH, __analogWidth, SENS_SAR2_BIT_WIDTH_S);
|
||||
SET_PERI_REG_BITS(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_SAMPLE_BIT, __analogWidth, SENS_SAR2_SAMPLE_BIT_S);
|
||||
}
|
||||
|
||||
void __analogSetCycles(uint8_t cycles){
|
||||
__analogCycles = cycles;
|
||||
SET_PERI_REG_BITS(SENS_SAR_READ_CTRL_REG, SENS_SAR1_SAMPLE_CYCLE, __analogCycles, SENS_SAR1_SAMPLE_CYCLE_S);
|
||||
SET_PERI_REG_BITS(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_SAMPLE_CYCLE, __analogCycles, SENS_SAR2_SAMPLE_CYCLE_S);
|
||||
}
|
||||
|
||||
void __analogSetSamples(uint8_t samples){
|
||||
if(!samples){
|
||||
return;
|
||||
}
|
||||
__analogSamples = samples - 1;
|
||||
SET_PERI_REG_BITS(SENS_SAR_READ_CTRL_REG, SENS_SAR1_SAMPLE_NUM, __analogSamples, SENS_SAR1_SAMPLE_NUM_S);
|
||||
SET_PERI_REG_BITS(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_SAMPLE_NUM, __analogSamples, SENS_SAR2_SAMPLE_NUM_S);
|
||||
}
|
||||
|
||||
void __analogSetClockDiv(uint8_t clockDiv){
|
||||
if(!clockDiv){
|
||||
return;
|
||||
}
|
||||
__analogClockDiv = clockDiv;
|
||||
SET_PERI_REG_BITS(SENS_SAR_READ_CTRL_REG, SENS_SAR1_CLK_DIV, __analogClockDiv, SENS_SAR1_CLK_DIV_S);
|
||||
SET_PERI_REG_BITS(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_CLK_DIV, __analogClockDiv, SENS_SAR2_CLK_DIV_S);
|
||||
}
|
||||
|
||||
void __analogSetAttenuation(adc_attenuation_t attenuation)
|
||||
{
|
||||
__analogAttenuation = attenuation & 3;
|
||||
uint32_t att_data = 0;
|
||||
int i = 10;
|
||||
while(i--){
|
||||
att_data |= __analogAttenuation << (i * 2);
|
||||
}
|
||||
WRITE_PERI_REG(SENS_SAR_ATTEN1_REG, att_data & 0xFFFF);//ADC1 has 8 channels
|
||||
WRITE_PERI_REG(SENS_SAR_ATTEN2_REG, att_data);
|
||||
}
|
||||
|
||||
void IRAM_ATTR __analogInit(){
|
||||
void __analogInit(){
|
||||
static bool initialized = false;
|
||||
if(initialized){
|
||||
return;
|
||||
}
|
||||
|
||||
__analogSetAttenuation(__analogAttenuation);
|
||||
__analogSetCycles(__analogCycles);
|
||||
__analogSetSamples(__analogSamples + 1);//in samples
|
||||
__analogSetClockDiv(__analogClockDiv);
|
||||
__analogSetWidth(__analogWidth + 9);//in bits
|
||||
|
||||
SET_PERI_REG_MASK(SENS_SAR_READ_CTRL_REG, SENS_SAR1_DATA_INV);
|
||||
SET_PERI_REG_MASK(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_DATA_INV);
|
||||
|
||||
SET_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_START_FORCE_M); //SAR ADC1 controller (in RTC) is started by SW
|
||||
SET_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_SAR1_EN_PAD_FORCE_M); //SAR ADC1 pad enable bitmap is controlled by SW
|
||||
SET_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_START_FORCE_M); //SAR ADC2 controller (in RTC) is started by SW
|
||||
SET_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_SAR2_EN_PAD_FORCE_M); //SAR ADC2 pad enable bitmap is controlled by SW
|
||||
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR_M); //force XPD_SAR=0, use XPD_FSM
|
||||
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_AMP, 0x2, SENS_FORCE_XPD_AMP_S); //force XPD_AMP=0
|
||||
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_CTRL_REG, 0xfff << SENS_AMP_RST_FB_FSM_S); //clear FSM
|
||||
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT1_REG, SENS_SAR_AMP_WAIT1, 0x1, SENS_SAR_AMP_WAIT1_S);
|
||||
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT1_REG, SENS_SAR_AMP_WAIT2, 0x1, SENS_SAR_AMP_WAIT2_S);
|
||||
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_SAR_AMP_WAIT3, 0x1, SENS_SAR_AMP_WAIT3_S);
|
||||
while (GET_PERI_REG_BITS2(SENS_SAR_SLAVE_ADDR1_REG, 0x7, SENS_MEAS_STATUS_S) != 0); //wait det_fsm==
|
||||
|
||||
initialized = true;
|
||||
__analogSetClockDiv(__analogClockDiv);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
__analogSetWidth(__analogWidth + 9);//in bits
|
||||
#endif
|
||||
}
|
||||
|
||||
void __analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation)
|
||||
@ -120,23 +89,23 @@ void __analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation)
|
||||
if(channel < 0 || attenuation > 3){
|
||||
return ;
|
||||
}
|
||||
__analogInit();
|
||||
if(channel > 7){
|
||||
SET_PERI_REG_BITS(SENS_SAR_ATTEN2_REG, 3, attenuation, ((channel - 10) * 2));
|
||||
if(channel > 9){
|
||||
adc2_config_channel_atten(channel - 10, attenuation);
|
||||
} else {
|
||||
SET_PERI_REG_BITS(SENS_SAR_ATTEN1_REG, 3, attenuation, (channel * 2));
|
||||
adc1_config_channel_atten(channel, attenuation);
|
||||
}
|
||||
__analogInit();
|
||||
}
|
||||
|
||||
bool IRAM_ATTR __adcAttachPin(uint8_t pin){
|
||||
|
||||
bool __adcAttachPin(uint8_t pin){
|
||||
int8_t channel = digitalPinToAnalogChannel(pin);
|
||||
if(channel < 0){
|
||||
return false;//not adc pin
|
||||
log_e("Pin %u is not ADC pin!", pin);
|
||||
return false;
|
||||
}
|
||||
|
||||
int8_t pad = digitalPinToTouchChannel(pin);
|
||||
if(pad >= 0){
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
uint32_t touch = READ_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG);
|
||||
if(touch & (1 << pad)){
|
||||
touch &= ~((1 << (pad + SENS_TOUCH_PAD_OUTEN2_S))
|
||||
@ -144,6 +113,7 @@ bool IRAM_ATTR __adcAttachPin(uint8_t pin){
|
||||
| (1 << (pad + SENS_TOUCH_PAD_WORKEN_S)));
|
||||
WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, touch);
|
||||
}
|
||||
#endif
|
||||
} else if(pin == 25){
|
||||
CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_XPD_DAC | RTC_IO_PDAC1_DAC_XPD_FORCE);//stop dac1
|
||||
} else if(pin == 26){
|
||||
@ -151,86 +121,120 @@ bool IRAM_ATTR __adcAttachPin(uint8_t pin){
|
||||
}
|
||||
|
||||
pinMode(pin, ANALOG);
|
||||
|
||||
__analogInit();
|
||||
__analogSetPinAttenuation(pin, __analogAttenuation);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IRAM_ATTR __adcStart(uint8_t pin){
|
||||
|
||||
int8_t channel = digitalPinToAnalogChannel(pin);
|
||||
if(channel < 0){
|
||||
return false;//not adc pin
|
||||
}
|
||||
|
||||
if(channel > 9){
|
||||
channel -= 10;
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_START_SAR_M);
|
||||
SET_PERI_REG_BITS(SENS_SAR_MEAS_START2_REG, SENS_SAR2_EN_PAD, (1 << channel), SENS_SAR2_EN_PAD_S);
|
||||
SET_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_START_SAR_M);
|
||||
} else {
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_START_SAR_M);
|
||||
SET_PERI_REG_BITS(SENS_SAR_MEAS_START1_REG, SENS_SAR1_EN_PAD, (1 << channel), SENS_SAR1_EN_PAD_S);
|
||||
SET_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_START_SAR_M);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IRAM_ATTR __adcBusy(uint8_t pin){
|
||||
|
||||
int8_t channel = digitalPinToAnalogChannel(pin);
|
||||
if(channel < 0){
|
||||
return false;//not adc pin
|
||||
}
|
||||
|
||||
if(channel > 7){
|
||||
return (GET_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_DONE_SAR) == 0);
|
||||
}
|
||||
return (GET_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_DONE_SAR) == 0);
|
||||
}
|
||||
|
||||
uint16_t IRAM_ATTR __adcEnd(uint8_t pin)
|
||||
{
|
||||
|
||||
uint16_t value = 0;
|
||||
int8_t channel = digitalPinToAnalogChannel(pin);
|
||||
if(channel < 0){
|
||||
return 0;//not adc pin
|
||||
}
|
||||
if(channel > 7){
|
||||
while (GET_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_DONE_SAR) == 0); //wait for conversion
|
||||
value = GET_PERI_REG_BITS2(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_DATA_SAR, SENS_MEAS2_DATA_SAR_S);
|
||||
} else {
|
||||
while (GET_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_DONE_SAR) == 0); //wait for conversion
|
||||
value = GET_PERI_REG_BITS2(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_DATA_SAR, SENS_MEAS1_DATA_SAR_S);
|
||||
}
|
||||
|
||||
// Shift result if necessary
|
||||
uint8_t from = __analogWidth + 9;
|
||||
if (from == __analogReturnedWidth) {
|
||||
return value;
|
||||
}
|
||||
if (from > __analogReturnedWidth) {
|
||||
return value >> (from - __analogReturnedWidth);
|
||||
}
|
||||
return value << (__analogReturnedWidth - from);
|
||||
}
|
||||
|
||||
uint16_t IRAM_ATTR __analogRead(uint8_t pin)
|
||||
{
|
||||
if(!__adcAttachPin(pin) || !__adcStart(pin)){
|
||||
return 0;
|
||||
}
|
||||
return __adcEnd(pin);
|
||||
}
|
||||
|
||||
void __analogReadResolution(uint8_t bits)
|
||||
{
|
||||
if(!bits || bits > 16){
|
||||
return;
|
||||
}
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
__analogSetWidth(bits); // hadware from 9 to 12
|
||||
__analogReturnedWidth = bits; // software from 1 to 16
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t __analogRead(uint8_t pin)
|
||||
{
|
||||
int8_t channel = digitalPinToAnalogChannel(pin);
|
||||
int value = 0;
|
||||
esp_err_t r = ESP_OK;
|
||||
if(channel < 0){
|
||||
log_e("Pin %u is not ADC pin!", pin);
|
||||
return value;
|
||||
}
|
||||
__adcAttachPin(pin);
|
||||
if(channel > 9){
|
||||
channel -= 10;
|
||||
r = adc2_get_raw( channel, __analogWidth, &value);
|
||||
if ( r == ESP_OK ) {
|
||||
return value;
|
||||
} else if ( r == ESP_ERR_INVALID_STATE ) {
|
||||
log_e("GPIO%u: %s: ADC2 not initialized yet.", pin, esp_err_to_name(r));
|
||||
} else if ( r == ESP_ERR_TIMEOUT ) {
|
||||
log_e("GPIO%u: %s: ADC2 is in use by Wi-Fi.", pin, esp_err_to_name(r));
|
||||
} else {
|
||||
log_e("GPIO%u: %s", pin, esp_err_to_name(r));
|
||||
}
|
||||
} else {
|
||||
return adc1_get_raw(channel);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
uint32_t __analogReadMilliVolts(uint8_t pin){
|
||||
int8_t channel = digitalPinToAnalogChannel(pin);
|
||||
if(channel < 0){
|
||||
log_e("Pin %u is not ADC pin!", pin);
|
||||
return 0;
|
||||
}
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
if(!__analogVRef){
|
||||
if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) {
|
||||
log_d("eFuse Two Point: Supported");
|
||||
__analogVRef = DEFAULT_VREF;
|
||||
}
|
||||
if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_VREF) == ESP_OK) {
|
||||
log_d("eFuse Vref: Supported");
|
||||
__analogVRef = DEFAULT_VREF;
|
||||
}
|
||||
if(!__analogVRef){
|
||||
__analogVRef = DEFAULT_VREF;
|
||||
if(__analogVRefPin){
|
||||
esp_adc_cal_characteristics_t chars;
|
||||
if(adc2_vref_to_gpio(__analogVRefPin) == ESP_OK){
|
||||
__analogVRef = __analogRead(__analogVRefPin);
|
||||
esp_adc_cal_characterize(1, __analogAttenuation, __analogWidth, DEFAULT_VREF, &chars);
|
||||
__analogVRef = esp_adc_cal_raw_to_voltage(__analogVRef, &chars);
|
||||
log_d("Vref to GPIO%u: %u", __analogVRefPin, __analogVRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
uint8_t unit = 1;
|
||||
if(channel > 9){
|
||||
unit = 2;
|
||||
}
|
||||
uint16_t adc_reading = __analogRead(pin);
|
||||
if(__analogCharacteristics[unit - 1] == NULL){
|
||||
__analogCharacteristics[unit - 1] = calloc(1, sizeof(esp_adc_cal_characteristics_t));
|
||||
if(__analogCharacteristics[unit - 1] == NULL){
|
||||
return 0;
|
||||
}
|
||||
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, __analogAttenuation, __analogWidth, __analogVRef, __analogCharacteristics[unit - 1]);
|
||||
if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
|
||||
log_i("ADC%u: Characterized using Two Point Value: %u\n", unit, __analogCharacteristics[unit - 1]->vref);
|
||||
} else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
|
||||
log_i("ADC%u: Characterized using eFuse Vref: %u\n", unit, __analogCharacteristics[unit - 1]->vref);
|
||||
} else if(__analogVRef != DEFAULT_VREF){
|
||||
log_i("ADC%u: Characterized using Vref to GPIO%u: %u\n", unit, __analogVRefPin, __analogCharacteristics[unit - 1]->vref);
|
||||
} else {
|
||||
log_i("ADC%u: Characterized using Default Vref: %u\n", unit, __analogCharacteristics[unit - 1]->vref);
|
||||
}
|
||||
}
|
||||
return esp_adc_cal_raw_to_voltage(adc_reading, __analogCharacteristics[unit - 1]);
|
||||
#else
|
||||
uint16_t adc_reading = __analogRead(pin);
|
||||
uint16_t max_reading = 8191;
|
||||
uint16_t max_mv = 1100;
|
||||
switch(__analogAttenuation){
|
||||
case 3: max_mv = 3900; break;
|
||||
case 2: max_mv = 2200; break;
|
||||
case 1: max_mv = 1500; break;
|
||||
default: break;
|
||||
}
|
||||
return (adc_reading * max_mv) / max_reading;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
void __analogSetVRefPin(uint8_t pin){
|
||||
if(pin <25 || pin > 27){
|
||||
pin = 0;
|
||||
}
|
||||
__analogVRefPin = pin;
|
||||
}
|
||||
|
||||
int __hallRead() //hall sensor without LNA
|
||||
@ -256,18 +260,20 @@ int __hallRead() //hall sensor without LNA
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_HALL_PHASE_FORCE);
|
||||
return (Sens_Vp1 - Sens_Vp0) - (Sens_Vn1 - Sens_Vn0);
|
||||
}
|
||||
#endif
|
||||
|
||||
extern uint16_t analogRead(uint8_t pin) __attribute__ ((weak, alias("__analogRead")));
|
||||
extern uint32_t analogReadMilliVolts(uint8_t pin) __attribute__ ((weak, alias("__analogReadMilliVolts")));
|
||||
extern void analogReadResolution(uint8_t bits) __attribute__ ((weak, alias("__analogReadResolution")));
|
||||
extern void analogSetWidth(uint8_t bits) __attribute__ ((weak, alias("__analogSetWidth")));
|
||||
extern void analogSetCycles(uint8_t cycles) __attribute__ ((weak, alias("__analogSetCycles")));
|
||||
extern void analogSetSamples(uint8_t samples) __attribute__ ((weak, alias("__analogSetSamples")));
|
||||
extern void analogSetClockDiv(uint8_t clockDiv) __attribute__ ((weak, alias("__analogSetClockDiv")));
|
||||
extern void analogSetAttenuation(adc_attenuation_t attenuation) __attribute__ ((weak, alias("__analogSetAttenuation")));
|
||||
extern void analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation) __attribute__ ((weak, alias("__analogSetPinAttenuation")));
|
||||
extern int hallRead() __attribute__ ((weak, alias("__hallRead")));
|
||||
|
||||
extern bool adcAttachPin(uint8_t pin) __attribute__ ((weak, alias("__adcAttachPin")));
|
||||
extern bool adcStart(uint8_t pin) __attribute__ ((weak, alias("__adcStart")));
|
||||
extern bool adcBusy(uint8_t pin) __attribute__ ((weak, alias("__adcBusy")));
|
||||
extern uint16_t adcEnd(uint8_t pin) __attribute__ ((weak, alias("__adcEnd")));
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
extern void analogSetVRefPin(uint8_t pin) __attribute__ ((weak, alias("__analogSetVRefPin")));
|
||||
extern void analogSetWidth(uint8_t bits) __attribute__ ((weak, alias("__analogSetWidth")));
|
||||
extern int hallRead() __attribute__ ((weak, alias("__hallRead")));
|
||||
#endif
|
||||
|
||||
|
@ -38,6 +38,11 @@ typedef enum {
|
||||
* */
|
||||
uint16_t analogRead(uint8_t pin);
|
||||
|
||||
/*
|
||||
* Get MilliVolts value for pin
|
||||
* */
|
||||
uint32_t analogReadMilliVolts(uint8_t pin);
|
||||
|
||||
/*
|
||||
* Set the resolution of analogRead return values. Default is 12 bits (range from 0 to 4096).
|
||||
* If between 9 and 12, it will equal the set hardware resolution, else value will be shifted.
|
||||
@ -47,31 +52,6 @@ uint16_t analogRead(uint8_t pin);
|
||||
*/
|
||||
void analogReadResolution(uint8_t bits);
|
||||
|
||||
/*
|
||||
* Sets the sample bits and read resolution
|
||||
* Default is 12bit (0 - 4095)
|
||||
* Range is 9 - 12
|
||||
* */
|
||||
void analogSetWidth(uint8_t bits);
|
||||
|
||||
/*
|
||||
* Set number of cycles per sample
|
||||
* Default is 8 and seems to do well
|
||||
* Range is 1 - 255
|
||||
* */
|
||||
void analogSetCycles(uint8_t cycles);
|
||||
|
||||
/*
|
||||
* Set number of samples in the range.
|
||||
* Default is 1
|
||||
* Range is 1 - 255
|
||||
* This setting splits the range into
|
||||
* "samples" pieces, which could look
|
||||
* like the sensitivity has been multiplied
|
||||
* that many times
|
||||
* */
|
||||
void analogSetSamples(uint8_t samples);
|
||||
|
||||
/*
|
||||
* Set the divider for the ADC clock.
|
||||
* Default is 1
|
||||
@ -91,40 +71,30 @@ void analogSetAttenuation(adc_attenuation_t attenuation);
|
||||
* */
|
||||
void analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation);
|
||||
|
||||
/*
|
||||
* Get value for HALL sensor (without LNA)
|
||||
* connected to pins 36(SVP) and 39(SVN)
|
||||
* */
|
||||
int hallRead();
|
||||
|
||||
/*
|
||||
* Non-Blocking API (almost)
|
||||
*
|
||||
* Note: ADC conversion can run only for single pin at a time.
|
||||
* That means that if you want to run ADC on two pins on the same bus,
|
||||
* you need to run them one after another. Probably the best use would be
|
||||
* to start conversion on both buses in parallel.
|
||||
* */
|
||||
|
||||
/*
|
||||
* Attach pin to ADC (will also clear any other analog mode that could be on)
|
||||
* */
|
||||
bool adcAttachPin(uint8_t pin);
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
/*
|
||||
* Start ADC conversion on attached pin's bus
|
||||
* Sets the sample bits and read resolution
|
||||
* Default is 12bit (0 - 4095)
|
||||
* Range is 9 - 12
|
||||
* */
|
||||
bool adcStart(uint8_t pin);
|
||||
void analogSetWidth(uint8_t bits);
|
||||
|
||||
/*
|
||||
* Check if conversion on the pin's ADC bus is currently running
|
||||
* Set pin to use for ADC calibration if the esp is not already calibrated (25, 26 or 27)
|
||||
* */
|
||||
bool adcBusy(uint8_t pin);
|
||||
void analogSetVRefPin(uint8_t pin);
|
||||
|
||||
/*
|
||||
* Get the result of the conversion (will wait if it have not finished)
|
||||
* Get value for HALL sensor (without LNA)
|
||||
* connected to pins 36(SVP) and 39(SVN)
|
||||
* */
|
||||
uint16_t adcEnd(uint8_t pin);
|
||||
int hallRead();
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -65,6 +65,14 @@ bool btStop(){
|
||||
while(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED);
|
||||
}
|
||||
if(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED){
|
||||
if (esp_bt_controller_deinit()) {
|
||||
log_e("BT deint failed");
|
||||
return false;
|
||||
}
|
||||
vTaskDelay(1);
|
||||
if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_IDLE) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
log_e("BT Stop failed");
|
||||
|
245
cores/esp32/esp32-hal-cpu.c
Normal file
245
cores/esp32/esp32-hal-cpu.c
Normal file
@ -0,0 +1,245 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/xtensa_timer.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_log.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/apb_ctrl_reg.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "esp32-hal.h"
|
||||
#include "esp32-hal-cpu.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/rtc.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/rtc.h"
|
||||
#endif
|
||||
|
||||
typedef struct apb_change_cb_s {
|
||||
struct apb_change_cb_s * prev;
|
||||
struct apb_change_cb_s * next;
|
||||
void * arg;
|
||||
apb_change_cb_t cb;
|
||||
} apb_change_t;
|
||||
|
||||
|
||||
static apb_change_t * apb_change_callbacks = NULL;
|
||||
static xSemaphoreHandle apb_change_lock = NULL;
|
||||
|
||||
static void initApbChangeCallback(){
|
||||
static volatile bool initialized = false;
|
||||
if(!initialized){
|
||||
initialized = true;
|
||||
apb_change_lock = xSemaphoreCreateMutex();
|
||||
if(!apb_change_lock){
|
||||
initialized = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void triggerApbChangeCallback(apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){
|
||||
initApbChangeCallback();
|
||||
xSemaphoreTake(apb_change_lock, portMAX_DELAY);
|
||||
apb_change_t * r = apb_change_callbacks;
|
||||
if( r != NULL ){
|
||||
if(ev_type == APB_BEFORE_CHANGE )
|
||||
while(r != NULL){
|
||||
r->cb(r->arg, ev_type, old_apb, new_apb);
|
||||
r=r->next;
|
||||
}
|
||||
else { // run backwards through chain
|
||||
while(r->next != NULL) r = r->next; // find first added
|
||||
while( r != NULL){
|
||||
r->cb(r->arg, ev_type, old_apb, new_apb);
|
||||
r=r->prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
xSemaphoreGive(apb_change_lock);
|
||||
}
|
||||
|
||||
bool addApbChangeCallback(void * arg, apb_change_cb_t cb){
|
||||
initApbChangeCallback();
|
||||
apb_change_t * c = (apb_change_t*)malloc(sizeof(apb_change_t));
|
||||
if(!c){
|
||||
log_e("Callback Object Malloc Failed");
|
||||
return false;
|
||||
}
|
||||
c->next = NULL;
|
||||
c->prev = NULL;
|
||||
c->arg = arg;
|
||||
c->cb = cb;
|
||||
xSemaphoreTake(apb_change_lock, portMAX_DELAY);
|
||||
if(apb_change_callbacks == NULL){
|
||||
apb_change_callbacks = c;
|
||||
} else {
|
||||
apb_change_t * r = apb_change_callbacks;
|
||||
// look for duplicate callbacks
|
||||
while( (r != NULL ) && !((r->cb == cb) && ( r->arg == arg))) r = r->next;
|
||||
if (r) {
|
||||
log_e("duplicate func=%08X arg=%08X",c->cb,c->arg);
|
||||
free(c);
|
||||
xSemaphoreGive(apb_change_lock);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
c->next = apb_change_callbacks;
|
||||
apb_change_callbacks-> prev = c;
|
||||
apb_change_callbacks = c;
|
||||
}
|
||||
}
|
||||
xSemaphoreGive(apb_change_lock);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool removeApbChangeCallback(void * arg, apb_change_cb_t cb){
|
||||
initApbChangeCallback();
|
||||
xSemaphoreTake(apb_change_lock, portMAX_DELAY);
|
||||
apb_change_t * r = apb_change_callbacks;
|
||||
// look for matching callback
|
||||
while( (r != NULL ) && !((r->cb == cb) && ( r->arg == arg))) r = r->next;
|
||||
if ( r == NULL ) {
|
||||
log_e("not found func=%08X arg=%08X",cb,arg);
|
||||
xSemaphoreGive(apb_change_lock);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
// patch links
|
||||
if(r->prev) r->prev->next = r->next;
|
||||
else { // this is first link
|
||||
apb_change_callbacks = r->next;
|
||||
}
|
||||
if(r->next) r->next->prev = r->prev;
|
||||
free(r);
|
||||
}
|
||||
xSemaphoreGive(apb_change_lock);
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t calculateApb(rtc_cpu_freq_config_t * conf){
|
||||
if(conf->freq_mhz >= 80){
|
||||
return 80 * MHZ;
|
||||
}
|
||||
return (conf->source_freq_mhz * MHZ) / conf->div;
|
||||
}
|
||||
|
||||
void esp_timer_impl_update_apb_freq(uint32_t apb_ticks_per_us); //private in IDF
|
||||
|
||||
bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz){
|
||||
rtc_cpu_freq_config_t conf, cconf;
|
||||
uint32_t capb, apb;
|
||||
//Get XTAL Frequency and calculate min CPU MHz
|
||||
rtc_xtal_freq_t xtal = rtc_clk_xtal_freq_get();
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
if(xtal > RTC_XTAL_FREQ_AUTO){
|
||||
if(xtal < RTC_XTAL_FREQ_40M) {
|
||||
if(cpu_freq_mhz <= xtal && cpu_freq_mhz != xtal && cpu_freq_mhz != (xtal/2)){
|
||||
log_e("Bad frequency: %u MHz! Options are: 240, 160, 80, %u and %u MHz", cpu_freq_mhz, xtal, xtal/2);
|
||||
return false;
|
||||
}
|
||||
} else if(cpu_freq_mhz <= xtal && cpu_freq_mhz != xtal && cpu_freq_mhz != (xtal/2) && cpu_freq_mhz != (xtal/4)){
|
||||
log_e("Bad frequency: %u MHz! Options are: 240, 160, 80, %u, %u and %u MHz", cpu_freq_mhz, xtal, xtal/2, xtal/4);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(cpu_freq_mhz > xtal && cpu_freq_mhz != 240 && cpu_freq_mhz != 160 && cpu_freq_mhz != 80){
|
||||
if(xtal >= RTC_XTAL_FREQ_40M){
|
||||
log_e("Bad frequency: %u MHz! Options are: 240, 160, 80, %u, %u and %u MHz", cpu_freq_mhz, xtal, xtal/2, xtal/4);
|
||||
} else {
|
||||
log_e("Bad frequency: %u MHz! Options are: 240, 160, 80, %u and %u MHz", cpu_freq_mhz, xtal, xtal/2);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
//check if cpu supports the frequency
|
||||
if(cpu_freq_mhz == 240){
|
||||
//Check if ESP32 is rated for a CPU frequency of 160MHz only
|
||||
if (REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_CPU_FREQ_RATED) &&
|
||||
REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_CPU_FREQ_LOW)) {
|
||||
log_e("Can not switch to 240 MHz! Chip CPU frequency rated for 160MHz.");
|
||||
cpu_freq_mhz = 160;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//Get current CPU clock configuration
|
||||
rtc_clk_cpu_freq_get_config(&cconf);
|
||||
//return if frequency has not changed
|
||||
if(cconf.freq_mhz == cpu_freq_mhz){
|
||||
return true;
|
||||
}
|
||||
//Get configuration for the new CPU frequency
|
||||
if(!rtc_clk_cpu_freq_mhz_to_config(cpu_freq_mhz, &conf)){
|
||||
log_e("CPU clock could not be set to %u MHz", cpu_freq_mhz);
|
||||
return false;
|
||||
}
|
||||
//Current APB
|
||||
capb = calculateApb(&cconf);
|
||||
//New APB
|
||||
apb = calculateApb(&conf);
|
||||
log_d("%s: %u / %u = %u Mhz, APB: %u Hz", (conf.source == RTC_CPU_FREQ_SRC_PLL)?"PLL":((conf.source == RTC_CPU_FREQ_SRC_APLL)?"APLL":((conf.source == RTC_CPU_FREQ_SRC_XTAL)?"XTAL":"8M")), conf.source_freq_mhz, conf.div, conf.freq_mhz, apb);
|
||||
//Call peripheral functions before the APB change
|
||||
if(apb_change_callbacks){
|
||||
triggerApbChangeCallback(APB_BEFORE_CHANGE, capb, apb);
|
||||
}
|
||||
//Make the frequency change
|
||||
rtc_clk_cpu_freq_set_config_fast(&conf);
|
||||
if(capb != apb){
|
||||
//Update REF_TICK (uncomment if REF_TICK is different than 1MHz)
|
||||
//if(conf.freq_mhz < 80){
|
||||
// ESP_REG(APB_CTRL_XTAL_TICK_CONF_REG) = conf.freq_mhz / (REF_CLK_FREQ / MHZ) - 1;
|
||||
// }
|
||||
//Update APB Freq REG
|
||||
rtc_clk_apb_freq_update(apb);
|
||||
//Update esp_timer divisor
|
||||
esp_timer_impl_update_apb_freq(apb / MHZ);
|
||||
}
|
||||
//Update FreeRTOS Tick Divisor
|
||||
uint32_t fcpu = (conf.freq_mhz >= 80)?(conf.freq_mhz * MHZ):(apb);
|
||||
_xt_tick_divisor = fcpu / XT_TICK_PER_SEC;
|
||||
//Call peripheral functions after the APB change
|
||||
if(apb_change_callbacks){
|
||||
triggerApbChangeCallback(APB_AFTER_CHANGE, capb, apb);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t getCpuFrequencyMhz(){
|
||||
rtc_cpu_freq_config_t conf;
|
||||
rtc_clk_cpu_freq_get_config(&conf);
|
||||
return conf.freq_mhz;
|
||||
}
|
||||
|
||||
uint32_t getXtalFrequencyMhz(){
|
||||
return rtc_clk_xtal_freq_get();
|
||||
}
|
||||
|
||||
uint32_t getApbFrequency(){
|
||||
rtc_cpu_freq_config_t conf;
|
||||
rtc_clk_cpu_freq_get_config(&conf);
|
||||
return calculateApb(&conf);
|
||||
}
|
48
cores/esp32/esp32-hal-cpu.h
Normal file
48
cores/esp32/esp32-hal-cpu.h
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef _ESP32_HAL_CPU_H_
|
||||
#define _ESP32_HAL_CPU_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef enum { APB_BEFORE_CHANGE, APB_AFTER_CHANGE } apb_change_ev_t;
|
||||
|
||||
typedef void (* apb_change_cb_t)(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb);
|
||||
|
||||
bool addApbChangeCallback(void * arg, apb_change_cb_t cb);
|
||||
bool removeApbChangeCallback(void * arg, apb_change_cb_t cb);
|
||||
|
||||
//function takes the following frequencies as valid values:
|
||||
// 240, 160, 80 <<< For all XTAL types
|
||||
// 40, 20, 10 <<< For 40MHz XTAL
|
||||
// 26, 13 <<< For 26MHz XTAL
|
||||
// 24, 12 <<< For 24MHz XTAL
|
||||
bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz);
|
||||
|
||||
uint32_t getCpuFrequencyMhz(); // In MHz
|
||||
uint32_t getXtalFrequencyMhz(); // In MHz
|
||||
uint32_t getApbFrequency(); // In Hz
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ESP32_HAL_CPU_H_ */
|
@ -12,43 +12,45 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "esp32-hal-dac.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp32-hal.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_intr.h"
|
||||
#include "soc/rtc_io_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/rtc_io_periph.h"
|
||||
#include "soc/sens_reg.h"
|
||||
#include "soc/sens_struct.h"
|
||||
#include "driver/dac.h"
|
||||
|
||||
void IRAM_ATTR __dacWrite(uint8_t pin, uint8_t value)
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define DAC1 25
|
||||
#define DAC2 26
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define DAC1 17
|
||||
#define DAC2 18
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
|
||||
void ARDUINO_ISR_ATTR __dacWrite(uint8_t pin, uint8_t value)
|
||||
{
|
||||
if(pin < 25 || pin > 26){
|
||||
if(pin < DAC1 || pin > DAC2){
|
||||
return;//not dac pin
|
||||
}
|
||||
pinMode(pin, ANALOG);
|
||||
uint8_t channel = pin - 25;
|
||||
|
||||
|
||||
//Disable Tone
|
||||
uint8_t channel = pin - DAC1;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_DAC_CTRL1_REG, SENS_SW_TONE_EN);
|
||||
|
||||
if (channel) {
|
||||
//Disable Channel Tone
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_CW_EN2_M);
|
||||
//Set the Dac value
|
||||
SET_PERI_REG_BITS(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_DAC, value, RTC_IO_PDAC2_DAC_S); //dac_output
|
||||
//Channel output enable
|
||||
SET_PERI_REG_MASK(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_XPD_DAC | RTC_IO_PDAC2_DAC_XPD_FORCE);
|
||||
} else {
|
||||
//Disable Channel Tone
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_DAC_CTRL2_REG, SENS_DAC_CW_EN1_M);
|
||||
//Set the Dac value
|
||||
SET_PERI_REG_BITS(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_DAC, value, RTC_IO_PDAC1_DAC_S); //dac_output
|
||||
//Channel output enable
|
||||
SET_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_XPD_DAC | RTC_IO_PDAC1_DAC_XPD_FORCE);
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
SENS.sar_dac_ctrl1.dac_clkgate_en = 1;
|
||||
#endif
|
||||
RTCIO.pad_dac[channel].dac_xpd_force = 1;
|
||||
RTCIO.pad_dac[channel].xpd_dac = 1;
|
||||
if (channel == 0) {
|
||||
SENS.sar_dac_ctrl2.dac_cw_en1 = 0;
|
||||
} else if (channel == 1) {
|
||||
SENS.sar_dac_ctrl2.dac_cw_en2 = 0;
|
||||
}
|
||||
RTCIO.pad_dac[channel].dac = value;
|
||||
}
|
||||
|
||||
extern void dacWrite(uint8_t pin, uint8_t value) __attribute__ ((weak, alias("__dacWrite")));
|
||||
|
@ -13,20 +13,45 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include "esp32-hal-gpio.h"
|
||||
#include "pins_arduino.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_intr.h"
|
||||
#include "rom/gpio.h"
|
||||
#include "soc/gpio_reg.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/gpio_struct.h"
|
||||
#include "soc/rtc_io_reg.h"
|
||||
|
||||
const int8_t esp32_adc2gpio[20] = {36, 37, 38, 39, 32, 33, 34, 35, -1, -1, 4, 0, 2, 15, 13, 12, 14, 27, 25, 26};
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#include "esp32/rom/gpio.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#define GPIO_FUNC 2
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/ets_sys.h"
|
||||
#include "esp32s2/rom/gpio.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#define GPIO_FUNC 1
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/gpio.h"
|
||||
#include "esp_intr.h"
|
||||
#endif
|
||||
|
||||
const DRAM_ATTR esp32_gpioMux_t esp32_gpioMux[GPIO_PIN_COUNT]={
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
const int8_t esp32_adc2gpio[20] = {36, 37, 38, 39, 32, 33, 34, 35, -1, -1, 4, 0, 2, 15, 13, 12, 14, 27, 25, 26};
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
const int8_t esp32_adc2gpio[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
|
||||
#endif
|
||||
|
||||
const DRAM_ATTR esp32_gpioMux_t esp32_gpioMux[SOC_GPIO_PIN_COUNT]={
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
{0x44, 11, 11, 1},
|
||||
{0x88, -1, -1, -1},
|
||||
{0x40, 12, 12, 2},
|
||||
@ -59,67 +84,124 @@ const DRAM_ATTR esp32_gpioMux_t esp32_gpioMux[GPIO_PIN_COUNT]={
|
||||
{0, -1, -1, -1},
|
||||
{0, -1, -1, -1},
|
||||
{0, -1, -1, -1},
|
||||
{0x1c, 9, 4, 9},
|
||||
{0x20, 8, 5, 8},
|
||||
{0x1c, 9, 4, 8},
|
||||
{0x20, 8, 5, 9},
|
||||
{0x14, 4, 6, -1},
|
||||
{0x18, 5, 7, -1},
|
||||
{0x04, 0, 0, -1},
|
||||
{0x08, 1, 1, -1},
|
||||
{0x0c, 2, 2, -1},
|
||||
{0x10, 3, 3, -1}
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
{0x04, 0, -1, -1},
|
||||
{0x08, 1, 0, 1},
|
||||
{0x0c, 2, 1, 2},
|
||||
{0x10, 3, 2, 3},
|
||||
{0x14, 4, 3, 4},
|
||||
{0x18, 5, 4, 5},
|
||||
{0x1c, 6, 5, 6},
|
||||
{0x20, 7, 6, 7},
|
||||
{0x24, 8, 7, 8},
|
||||
{0x28, 9, 8, 9},//FSPI_HD
|
||||
{0x2c, 10, 9, 10},//FSPI_CS0 / FSPI_D4
|
||||
{0x30, 11, 10, 11},//FSPI_D / FSPI_D5
|
||||
{0x34, 12, 11, 12},//FSPI_CLK / FSPI_D6
|
||||
{0x38, 13, 12, 13},//FSPI_Q / FSPI_D7
|
||||
{0x3c, 14, 13, 14},//FSPI_WP / FSPI_DQS
|
||||
{0x40, 15, 14, -1},//32K+ / RTS0
|
||||
{0x44, 16, 15, -1},//32K- / CTS0
|
||||
{0x48, 17, 16, -1},//DAC1 / TXD1
|
||||
{0x4c, 18, 17, -1},//DAC2 / RXD1
|
||||
{0x50, 19, 18, -1},//USB D- / RTS1
|
||||
{0x54, 20, 19, -1},//USB D+ / CTS1
|
||||
{0x58, 21, -1, -1},//SDA?
|
||||
{ 0, -1, -1, -1},//UNAVAILABLE
|
||||
{ 0, -1, -1, -1},//UNAVAILABLE
|
||||
{ 0, -1, -1, -1},//UNAVAILABLE
|
||||
{ 0, -1, -1, -1},//UNAVAILABLE
|
||||
{0x6c, -1, -1, -1},//RESERVED SPI_CS1
|
||||
{0x70, -1, -1, -1},//RESERVED SPI_HD
|
||||
{0x74, -1, -1, -1},//RESERVED SPI_WP
|
||||
{0x78, -1, -1, -1},//RESERVED SPI_CS0
|
||||
{0x7c, -1, -1, -1},//RESERVED SPI_CLK
|
||||
{0x80, -1, -1, -1},//RESERVED SPI_Q
|
||||
{0x84, -1, -1, -1},//RESERVED SPI_D
|
||||
{0x88, -1, -1, -1},//FSPI_HD
|
||||
{0x8c, -1, -1, -1},//FSPI_CS0
|
||||
{0x90, -1, -1, -1},//FSPI_D
|
||||
{0x94, -1, -1, -1},//FSPI_CLK
|
||||
{0x98, -1, -1, -1},//FSPI_Q
|
||||
{0x9c, -1, -1, -1},//FSPI_WP
|
||||
{0xa0, -1, -1, -1},//MTCK
|
||||
{0xa4, -1, -1, -1},//MTDO
|
||||
{0xa8, -1, -1, -1},//MTDI
|
||||
{0xac, -1, -1, -1},//MTMS
|
||||
{0xb0, -1, -1, -1},//TXD0
|
||||
{0xb4, -1, -1, -1},//RXD0
|
||||
{0xb8, -1, -1, -1},//SCL?
|
||||
{0xbc, -1, -1, -1},//INPUT ONLY
|
||||
{0, -1, -1, -1}
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef void (*voidFuncPtr)(void);
|
||||
static voidFuncPtr __pinInterruptHandlers[GPIO_PIN_COUNT] = {0,};
|
||||
typedef void (*voidFuncPtrArg)(void*);
|
||||
typedef struct {
|
||||
voidFuncPtr fn;
|
||||
void* arg;
|
||||
bool functional;
|
||||
} InterruptHandle_t;
|
||||
static InterruptHandle_t __pinInterruptHandlers[SOC_GPIO_PIN_COUNT] = {0,};
|
||||
|
||||
#include "driver/rtc_io.h"
|
||||
|
||||
extern void IRAM_ATTR __pinMode(uint8_t pin, uint8_t mode)
|
||||
extern void ARDUINO_ISR_ATTR __pinMode(uint8_t pin, uint8_t mode)
|
||||
{
|
||||
|
||||
if(!digitalPinIsValid(pin)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t rtc_reg = rtc_gpio_desc[pin].reg;
|
||||
int8_t rtc_io = esp32_gpioMux[pin].rtc;
|
||||
uint32_t rtc_reg = (rtc_io != -1)?rtc_io_desc[rtc_io].reg:0;
|
||||
if(mode == ANALOG) {
|
||||
if(!rtc_reg) {
|
||||
return;//not rtc pin
|
||||
}
|
||||
//lock rtc
|
||||
uint32_t reg_val = ESP_REG(rtc_reg);
|
||||
if(reg_val & rtc_gpio_desc[pin].mux){
|
||||
return;//already in adc mode
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
SENS.sar_io_mux_conf.iomux_clk_gate_en = 1;
|
||||
#endif
|
||||
SET_PERI_REG_MASK(rtc_io_desc[rtc_io].reg, (rtc_io_desc[rtc_io].mux));
|
||||
SET_PERI_REG_BITS(rtc_io_desc[rtc_io].reg, RTC_IO_TOUCH_PAD1_FUN_SEL_V, 0, rtc_io_desc[rtc_io].func);
|
||||
|
||||
RTCIO.pin[rtc_io].pad_driver = 0;//OD = 1
|
||||
RTCIO.enable_w1tc.w1tc = (1U << rtc_io);
|
||||
CLEAR_PERI_REG_MASK(rtc_io_desc[rtc_io].reg, rtc_io_desc[rtc_io].ie);
|
||||
|
||||
if (rtc_io_desc[rtc_io].pullup) {
|
||||
CLEAR_PERI_REG_MASK(rtc_io_desc[rtc_io].reg, rtc_io_desc[rtc_io].pullup);
|
||||
}
|
||||
reg_val &= ~(
|
||||
(RTC_IO_TOUCH_PAD1_FUN_SEL_V << rtc_gpio_desc[pin].func)
|
||||
|rtc_gpio_desc[pin].ie
|
||||
|rtc_gpio_desc[pin].pullup
|
||||
|rtc_gpio_desc[pin].pulldown);
|
||||
ESP_REG(RTC_GPIO_ENABLE_W1TC_REG) = (1 << (rtc_gpio_desc[pin].rtc_num + RTC_GPIO_ENABLE_W1TC_S));
|
||||
ESP_REG(rtc_reg) = reg_val | rtc_gpio_desc[pin].mux;
|
||||
//unlock rtc
|
||||
ESP_REG(DR_REG_IO_MUX_BASE + esp32_gpioMux[pin].reg) = ((uint32_t)2 << MCU_SEL_S) | ((uint32_t)2 << FUN_DRV_S) | FUN_IE;
|
||||
if (rtc_io_desc[rtc_io].pulldown) {
|
||||
CLEAR_PERI_REG_MASK(rtc_io_desc[rtc_io].reg, rtc_io_desc[rtc_io].pulldown);
|
||||
}
|
||||
ESP_REG(DR_REG_IO_MUX_BASE + esp32_gpioMux[pin].reg) = ((uint32_t)GPIO_FUNC << MCU_SEL_S) | ((uint32_t)2 << FUN_DRV_S) | FUN_IE;
|
||||
return;
|
||||
}
|
||||
|
||||
//RTC pins PULL settings
|
||||
if(rtc_reg) {
|
||||
//lock rtc
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux);
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[rtc_io].mux);
|
||||
if(mode & PULLUP) {
|
||||
ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_gpio_desc[pin].pullup) & ~(rtc_gpio_desc[pin].pulldown);
|
||||
ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_io_desc[rtc_io].pullup) & ~(rtc_io_desc[rtc_io].pulldown);
|
||||
} else if(mode & PULLDOWN) {
|
||||
ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_gpio_desc[pin].pulldown) & ~(rtc_gpio_desc[pin].pullup);
|
||||
ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_io_desc[rtc_io].pulldown) & ~(rtc_io_desc[rtc_io].pullup);
|
||||
} else {
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown);
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[rtc_io].pullup | rtc_io_desc[rtc_io].pulldown);
|
||||
}
|
||||
//unlock rtc
|
||||
}
|
||||
|
||||
uint32_t pinFunction = 0, pinControl = 0;
|
||||
|
||||
//lock gpio
|
||||
if(mode & INPUT) {
|
||||
if(pin < 32) {
|
||||
GPIO.enable_w1tc = ((uint32_t)1 << pin);
|
||||
@ -127,9 +209,8 @@ extern void IRAM_ATTR __pinMode(uint8_t pin, uint8_t mode)
|
||||
GPIO.enable1_w1tc.val = ((uint32_t)1 << (pin - 32));
|
||||
}
|
||||
} else if(mode & OUTPUT) {
|
||||
if(pin > 33){
|
||||
//unlock gpio
|
||||
return;//pins above 33 can be only inputs
|
||||
if(pin >= NUM_OUPUT_PINS){
|
||||
return;
|
||||
} else if(pin < 32) {
|
||||
GPIO.enable_w1ts = ((uint32_t)1 << pin);
|
||||
} else {
|
||||
@ -147,9 +228,17 @@ extern void IRAM_ATTR __pinMode(uint8_t pin, uint8_t mode)
|
||||
pinFunction |= FUN_IE;//input enable but required for output as well?
|
||||
|
||||
if(mode & (INPUT | OUTPUT)) {
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
pinFunction |= ((uint32_t)2 << MCU_SEL_S);
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
pinFunction |= ((uint32_t)1 << MCU_SEL_S);
|
||||
#endif
|
||||
} else if(mode == SPECIAL) {
|
||||
pinFunction |= ((uint32_t)(((pin)==1||(pin)==3)?0:1) << MCU_SEL_S);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
pinFunction |= ((uint32_t)(((pin)==RX||(pin)==TX)?0:1) << MCU_SEL_S);
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
pinFunction |= ((uint32_t)(((pin)==RX||(pin)==TX)?0:2) << MCU_SEL_S);
|
||||
#endif
|
||||
} else {
|
||||
pinFunction |= ((uint32_t)(mode >> 5) << MCU_SEL_S);
|
||||
}
|
||||
@ -161,31 +250,30 @@ extern void IRAM_ATTR __pinMode(uint8_t pin, uint8_t mode)
|
||||
}
|
||||
|
||||
GPIO.pin[pin].val = pinControl;
|
||||
//unlock gpio
|
||||
}
|
||||
|
||||
extern void IRAM_ATTR __digitalWrite(uint8_t pin, uint8_t val)
|
||||
extern void ARDUINO_ISR_ATTR __digitalWrite(uint8_t pin, uint8_t val)
|
||||
{
|
||||
if(val) {
|
||||
if(pin < 32) {
|
||||
GPIO.out_w1ts = ((uint32_t)1 << pin);
|
||||
} else if(pin < 34) {
|
||||
} else if(pin < NUM_OUPUT_PINS) {
|
||||
GPIO.out1_w1ts.val = ((uint32_t)1 << (pin - 32));
|
||||
}
|
||||
} else {
|
||||
if(pin < 32) {
|
||||
GPIO.out_w1tc = ((uint32_t)1 << pin);
|
||||
} else if(pin < 34) {
|
||||
} else if(pin < NUM_OUPUT_PINS) {
|
||||
GPIO.out1_w1tc.val = ((uint32_t)1 << (pin - 32));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern int IRAM_ATTR __digitalRead(uint8_t pin)
|
||||
extern int ARDUINO_ISR_ATTR __digitalRead(uint8_t pin)
|
||||
{
|
||||
if(pin < 32) {
|
||||
return (GPIO.in >> pin) & 0x1;
|
||||
} else if(pin < 40) {
|
||||
} else if(pin < GPIO_PIN_COUNT) {
|
||||
return (GPIO.in1.val >> (pin - 32)) & 0x1;
|
||||
}
|
||||
return 0;
|
||||
@ -193,7 +281,7 @@ extern int IRAM_ATTR __digitalRead(uint8_t pin)
|
||||
|
||||
static intr_handle_t gpio_intr_handle = NULL;
|
||||
|
||||
static void IRAM_ATTR __onPinInterrupt(void *arg)
|
||||
static void ARDUINO_ISR_ATTR __onPinInterrupt()
|
||||
{
|
||||
uint32_t gpio_intr_status_l=0;
|
||||
uint32_t gpio_intr_status_h=0;
|
||||
@ -207,8 +295,12 @@ static void IRAM_ATTR __onPinInterrupt(void *arg)
|
||||
if(gpio_intr_status_l) {
|
||||
do {
|
||||
if(gpio_intr_status_l & ((uint32_t)1 << pin)) {
|
||||
if(__pinInterruptHandlers[pin]) {
|
||||
__pinInterruptHandlers[pin]();
|
||||
if(__pinInterruptHandlers[pin].fn) {
|
||||
if(__pinInterruptHandlers[pin].arg){
|
||||
((voidFuncPtrArg)__pinInterruptHandlers[pin].fn)(__pinInterruptHandlers[pin].arg);
|
||||
} else {
|
||||
__pinInterruptHandlers[pin].fn();
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(++pin<32);
|
||||
@ -217,37 +309,72 @@ static void IRAM_ATTR __onPinInterrupt(void *arg)
|
||||
pin=32;
|
||||
do {
|
||||
if(gpio_intr_status_h & ((uint32_t)1 << (pin - 32))) {
|
||||
if(__pinInterruptHandlers[pin]) {
|
||||
__pinInterruptHandlers[pin]();
|
||||
if(__pinInterruptHandlers[pin].fn) {
|
||||
if(__pinInterruptHandlers[pin].arg){
|
||||
((voidFuncPtrArg)__pinInterruptHandlers[pin].fn)(__pinInterruptHandlers[pin].arg);
|
||||
} else {
|
||||
__pinInterruptHandlers[pin].fn();
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(++pin<GPIO_PIN_COUNT);
|
||||
}
|
||||
}
|
||||
|
||||
extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int intr_type)
|
||||
extern void cleanupFunctional(void* arg);
|
||||
|
||||
extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type, bool functional)
|
||||
{
|
||||
static bool interrupt_initialized = false;
|
||||
|
||||
if(!interrupt_initialized) {
|
||||
interrupt_initialized = true;
|
||||
esp_intr_alloc(ETS_GPIO_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, __onPinInterrupt, NULL, &gpio_intr_handle);
|
||||
esp_intr_alloc(ETS_GPIO_INTR_SOURCE, (int)ARDUINO_ISR_FLAG, __onPinInterrupt, NULL, &gpio_intr_handle);
|
||||
}
|
||||
__pinInterruptHandlers[pin] = userFunc;
|
||||
|
||||
// if new attach without detach remove old info
|
||||
if (__pinInterruptHandlers[pin].functional && __pinInterruptHandlers[pin].arg)
|
||||
{
|
||||
cleanupFunctional(__pinInterruptHandlers[pin].arg);
|
||||
}
|
||||
__pinInterruptHandlers[pin].fn = (voidFuncPtr)userFunc;
|
||||
__pinInterruptHandlers[pin].arg = arg;
|
||||
__pinInterruptHandlers[pin].functional = functional;
|
||||
|
||||
esp_intr_disable(gpio_intr_handle);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
if(esp_intr_get_cpu(gpio_intr_handle)) { //APP_CPU
|
||||
#endif
|
||||
GPIO.pin[pin].int_ena = 1;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
} else { //PRO_CPU
|
||||
GPIO.pin[pin].int_ena = 4;
|
||||
}
|
||||
#endif
|
||||
GPIO.pin[pin].int_type = intr_type;
|
||||
esp_intr_enable(gpio_intr_handle);
|
||||
}
|
||||
|
||||
extern void __attachInterruptArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type)
|
||||
{
|
||||
__attachInterruptFunctionalArg(pin, userFunc, arg, intr_type, false);
|
||||
}
|
||||
|
||||
extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int intr_type) {
|
||||
__attachInterruptFunctionalArg(pin, (voidFuncPtrArg)userFunc, NULL, intr_type, false);
|
||||
}
|
||||
|
||||
extern void __detachInterrupt(uint8_t pin)
|
||||
{
|
||||
esp_intr_disable(gpio_intr_handle);
|
||||
__pinInterruptHandlers[pin] = NULL;
|
||||
if (__pinInterruptHandlers[pin].functional && __pinInterruptHandlers[pin].arg)
|
||||
{
|
||||
cleanupFunctional(__pinInterruptHandlers[pin].arg);
|
||||
}
|
||||
__pinInterruptHandlers[pin].fn = NULL;
|
||||
__pinInterruptHandlers[pin].arg = NULL;
|
||||
__pinInterruptHandlers[pin].functional = false;
|
||||
|
||||
GPIO.pin[pin].int_ena = 0;
|
||||
GPIO.pin[pin].int_type = 0;
|
||||
esp_intr_enable(gpio_intr_handle);
|
||||
@ -258,5 +385,6 @@ extern void pinMode(uint8_t pin, uint8_t mode) __attribute__ ((weak, alias("__pi
|
||||
extern void digitalWrite(uint8_t pin, uint8_t val) __attribute__ ((weak, alias("__digitalWrite")));
|
||||
extern int digitalRead(uint8_t pin) __attribute__ ((weak, alias("__digitalRead")));
|
||||
extern void attachInterrupt(uint8_t pin, voidFuncPtr handler, int mode) __attribute__ ((weak, alias("__attachInterrupt")));
|
||||
extern void attachInterruptArg(uint8_t pin, voidFuncPtrArg handler, void * arg, int mode) __attribute__ ((weak, alias("__attachInterruptArg")));
|
||||
extern void detachInterrupt(uint8_t pin) __attribute__ ((weak, alias("__detachInterrupt")));
|
||||
|
||||
|
@ -25,6 +25,17 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include "esp32-hal.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#if (CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3)
|
||||
#define NUM_OUPUT_PINS 45
|
||||
#define PIN_DAC1 17
|
||||
#define PIN_DAC2 18
|
||||
#else
|
||||
#define NUM_OUPUT_PINS 34
|
||||
#define PIN_DAC1 25
|
||||
#define PIN_DAC2 26
|
||||
#endif
|
||||
|
||||
#define LOW 0x0
|
||||
#define HIGH 0x1
|
||||
@ -64,21 +75,22 @@ typedef struct {
|
||||
int8_t touch; /*!< Touch Channel number (-1 if not Touch pin) */
|
||||
} esp32_gpioMux_t;
|
||||
|
||||
extern const esp32_gpioMux_t esp32_gpioMux[40];
|
||||
extern const esp32_gpioMux_t esp32_gpioMux[SOC_GPIO_PIN_COUNT];
|
||||
extern const int8_t esp32_adc2gpio[20];
|
||||
|
||||
#define digitalPinIsValid(pin) ((pin) < 40 && esp32_gpioMux[(pin)].reg)
|
||||
#define digitalPinCanOutput(pin) ((pin) < 34 && esp32_gpioMux[(pin)].reg)
|
||||
#define digitalPinToRtcPin(pin) (((pin) < 40)?esp32_gpioMux[(pin)].rtc:-1)
|
||||
#define digitalPinToAnalogChannel(pin) (((pin) < 40)?esp32_gpioMux[(pin)].adc:-1)
|
||||
#define digitalPinToTouchChannel(pin) (((pin) < 40)?esp32_gpioMux[(pin)].touch:-1)
|
||||
#define digitalPinToDacChannel(pin) (((pin) == 25)?0:((pin) == 26)?1:-1)
|
||||
#define digitalPinIsValid(pin) ((pin) < SOC_GPIO_PIN_COUNT && esp32_gpioMux[(pin)].reg)
|
||||
#define digitalPinCanOutput(pin) ((pin) < NUM_OUPUT_PINS && esp32_gpioMux[(pin)].reg)
|
||||
#define digitalPinToRtcPin(pin) (((pin) < SOC_GPIO_PIN_COUNT)?esp32_gpioMux[(pin)].rtc:-1)
|
||||
#define digitalPinToAnalogChannel(pin) (((pin) < SOC_GPIO_PIN_COUNT)?esp32_gpioMux[(pin)].adc:-1)
|
||||
#define digitalPinToTouchChannel(pin) (((pin) < SOC_GPIO_PIN_COUNT)?esp32_gpioMux[(pin)].touch:-1)
|
||||
#define digitalPinToDacChannel(pin) (((pin) == PIN_DAC1)?0:((pin) == PIN_DAC2)?1:-1)
|
||||
|
||||
void pinMode(uint8_t pin, uint8_t mode);
|
||||
void digitalWrite(uint8_t pin, uint8_t val);
|
||||
int digitalRead(uint8_t pin);
|
||||
|
||||
void attachInterrupt(uint8_t pin, void (*)(void), int mode);
|
||||
void attachInterruptArg(uint8_t pin, void (*)(void*), void * arg, int mode);
|
||||
void detachInterrupt(uint8_t pin);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -48,6 +48,7 @@ i2c_err_t i2cRead(i2c_t * i2c, uint16_t address, uint8_t* buff, uint16_t size, b
|
||||
i2c_err_t i2cFlush(i2c_t *i2c);
|
||||
i2c_err_t i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed);
|
||||
uint32_t i2cGetFrequency(i2c_t * i2c);
|
||||
uint32_t i2cGetStatus(i2c_t * i2c); // Status register of peripheral
|
||||
|
||||
//Functions below should be used only if well understood
|
||||
//Might be deprecated and removed in future
|
||||
@ -62,8 +63,17 @@ i2c_err_t i2cAddQueueWrite(i2c_t *i2c, uint16_t i2cDeviceAddr, uint8_t *dataPtr,
|
||||
i2c_err_t i2cAddQueueRead(i2c_t *i2c, uint16_t i2cDeviceAddr, uint8_t *dataPtr, uint16_t dataLen, bool SendStop, EventGroupHandle_t event);
|
||||
|
||||
//stickbreaker debug support
|
||||
void i2cDumpInts(uint8_t num);
|
||||
void i2cDumpI2c(i2c_t *i2c);
|
||||
uint32_t i2cDebug(i2c_t *, uint32_t setBits, uint32_t resetBits);
|
||||
// Debug actions have 3 currently defined locus
|
||||
// 0xXX------ : at entry of ProcQueue
|
||||
// 0x--XX---- : at exit of ProcQueue
|
||||
// 0x------XX : at entry of Flush
|
||||
//
|
||||
// bit 0 causes DumpI2c to execute
|
||||
// bit 1 causes DumpInts to execute
|
||||
// bit 2 causes DumpCmdqueue to execute
|
||||
// bit 3 causes DumpStatus to execute
|
||||
// bit 4 causes DumpFifo to execute
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -16,19 +16,34 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp32-hal-matrix.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/ledc_reg.h"
|
||||
#include "soc/ledc_struct.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#define LAST_CHAN (15)
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/ets_sys.h"
|
||||
#define LAST_CHAN (7)
|
||||
#define LEDC_DIV_NUM_HSTIMER0_V LEDC_CLK_DIV_LSTIMER0_V
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/ets_sys.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_DISABLE_HAL_LOCKS
|
||||
#define LEDC_MUTEX_LOCK()
|
||||
#define LEDC_MUTEX_UNLOCK()
|
||||
#else
|
||||
#define LEDC_MUTEX_LOCK() do {} while (xSemaphoreTake(_ledc_sys_lock, portMAX_DELAY) != pdPASS)
|
||||
#define LEDC_MUTEX_UNLOCK() xSemaphoreGive(_ledc_sys_lock)
|
||||
xSemaphoreHandle _ledc_sys_lock;
|
||||
xSemaphoreHandle _ledc_sys_lock = NULL;
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -53,16 +68,54 @@ xSemaphoreHandle _ledc_sys_lock;
|
||||
#define LEDC_CHAN(g,c) LEDC.channel_group[(g)].channel[(c)]
|
||||
#define LEDC_TIMER(g,t) LEDC.timer_group[(g)].timer[(t)]
|
||||
|
||||
static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){
|
||||
if(ev_type == APB_AFTER_CHANGE && old_apb != new_apb){
|
||||
uint16_t iarg = *(uint16_t*)arg;
|
||||
uint8_t chan = 0;
|
||||
old_apb /= 1000000;
|
||||
new_apb /= 1000000;
|
||||
while(iarg){ // run though all active channels, adjusting timing configurations
|
||||
if(iarg & 1) {// this channel is active
|
||||
uint8_t group=(chan/8), timer=((chan/2)%4);
|
||||
if(LEDC_TIMER(group, timer).conf.tick_sel){
|
||||
LEDC_MUTEX_LOCK();
|
||||
uint32_t old_div = LEDC_TIMER(group, timer).conf.clock_divider;
|
||||
uint32_t div_num = (new_apb * old_div) / old_apb;
|
||||
if(div_num > LEDC_DIV_NUM_HSTIMER0_V){
|
||||
div_num = ((REF_CLK_FREQ /1000000) * old_div) / old_apb;
|
||||
if(div_num > LEDC_DIV_NUM_HSTIMER0_V) {
|
||||
div_num = LEDC_DIV_NUM_HSTIMER0_V;//lowest clock possible
|
||||
}
|
||||
LEDC_TIMER(group, timer).conf.tick_sel = 0;
|
||||
} else if(div_num < 256) {
|
||||
div_num = 256;//highest clock possible
|
||||
}
|
||||
LEDC_TIMER(group, timer).conf.clock_divider = div_num;
|
||||
LEDC_MUTEX_UNLOCK();
|
||||
}
|
||||
else {
|
||||
log_d("using REF_CLK chan=%d",chan);
|
||||
}
|
||||
}
|
||||
iarg = iarg >> 1;
|
||||
chan++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//uint32_t frequency = (80MHz or 1MHz)/((div_num / 256.0)*(1 << bit_num));
|
||||
static void _ledcSetupTimer(uint8_t chan, uint32_t div_num, uint8_t bit_num, bool apb_clk)
|
||||
{
|
||||
uint8_t group=(chan/8), timer=((chan/2)%4);
|
||||
static bool tHasStarted = false;
|
||||
static uint16_t _activeChannels = 0;
|
||||
if(!tHasStarted) {
|
||||
tHasStarted = true;
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_LEDC_CLK_EN);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_LEDC_RST);
|
||||
LEDC.conf.apb_clk_sel = 1;//LS use apb clock
|
||||
addApbChangeCallback((void*)&_activeChannels, _on_apb_change);
|
||||
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
_ledc_sys_lock = xSemaphoreCreateMutex();
|
||||
#endif
|
||||
@ -71,20 +124,25 @@ static void _ledcSetupTimer(uint8_t chan, uint32_t div_num, uint8_t bit_num, boo
|
||||
LEDC_TIMER(group, timer).conf.clock_divider = div_num;//18 bit (10.8) This register is used to configure parameter for divider in timer the least significant eight bits represent the decimal part.
|
||||
LEDC_TIMER(group, timer).conf.duty_resolution = bit_num;//5 bit This register controls the range of the counter in timer. the counter range is [0 2**bit_num] the max bit width for counter is 20.
|
||||
LEDC_TIMER(group, timer).conf.tick_sel = apb_clk;//apb clock
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
if(group) {
|
||||
#endif
|
||||
LEDC_TIMER(group, timer).conf.low_speed_update = 1;//This bit is only useful for low speed timer channels, reserved for high speed timers
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
}
|
||||
#endif
|
||||
LEDC_TIMER(group, timer).conf.pause = 0;
|
||||
LEDC_TIMER(group, timer).conf.rst = 1;//This bit is used to reset timer the counter will be 0 after reset.
|
||||
LEDC_TIMER(group, timer).conf.rst = 0;
|
||||
LEDC_MUTEX_UNLOCK();
|
||||
_activeChannels |= (1 << chan); // mark as active for APB callback
|
||||
}
|
||||
|
||||
//max div_num 0x3FFFF (262143)
|
||||
//max bit_num 0x1F (31)
|
||||
static double _ledcSetupTimerFreq(uint8_t chan, double freq, uint8_t bit_num)
|
||||
{
|
||||
uint64_t clk_freq = APB_CLK_FREQ;
|
||||
uint64_t clk_freq = getApbFrequency();
|
||||
clk_freq <<= 8;//div_num is 8 bit decimal
|
||||
uint32_t div_num = (clk_freq >> bit_num) / freq;
|
||||
bool apb_clk = true;
|
||||
@ -117,7 +175,7 @@ static double _ledcTimerRead(uint8_t chan)
|
||||
LEDC_MUTEX_UNLOCK();
|
||||
uint64_t clk_freq = 1000000;
|
||||
if(apb_clk) {
|
||||
clk_freq *= 80;
|
||||
clk_freq = getApbFrequency();
|
||||
}
|
||||
clk_freq <<= 8;//div_num is 8 bit decimal
|
||||
return (clk_freq >> bit_num) / (double)div_num;
|
||||
@ -137,17 +195,21 @@ static void _ledcSetupChannel(uint8_t chan, uint8_t idle_level)
|
||||
LEDC_CHAN(group, channel).duty.duty = 0;
|
||||
LEDC_CHAN(group, channel).conf0.sig_out_en = 0;//This is the output enable control bit for channel
|
||||
LEDC_CHAN(group, channel).conf1.duty_start = 0;//When duty_num duty_cycle and duty_scale has been configured. these register won't take effect until set duty_start. this bit is automatically cleared by hardware.
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
if(group) {
|
||||
LEDC_CHAN(group, channel).conf0.val &= ~BIT(4);
|
||||
#endif
|
||||
LEDC_CHAN(group, channel).conf0.low_speed_update = 1;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
} else {
|
||||
LEDC_CHAN(group, channel).conf0.clk_en = 0;
|
||||
}
|
||||
#endif
|
||||
LEDC_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
double ledcSetup(uint8_t chan, double freq, uint8_t bit_num)
|
||||
{
|
||||
if(chan > 15) {
|
||||
if(chan > LAST_CHAN) {
|
||||
return 0;
|
||||
}
|
||||
double res_freq = _ledcSetupTimerFreq(chan, freq, bit_num);
|
||||
@ -157,7 +219,7 @@ double ledcSetup(uint8_t chan, double freq, uint8_t bit_num)
|
||||
|
||||
void ledcWrite(uint8_t chan, uint32_t duty)
|
||||
{
|
||||
if(chan > 15) {
|
||||
if(chan > LAST_CHAN) {
|
||||
return;
|
||||
}
|
||||
uint8_t group=(chan/8), channel=(chan%8);
|
||||
@ -166,26 +228,34 @@ void ledcWrite(uint8_t chan, uint32_t duty)
|
||||
if(duty) {
|
||||
LEDC_CHAN(group, channel).conf0.sig_out_en = 1;//This is the output enable control bit for channel
|
||||
LEDC_CHAN(group, channel).conf1.duty_start = 1;//When duty_num duty_cycle and duty_scale has been configured. these register won't take effect until set duty_start. this bit is automatically cleared by hardware.
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
if(group) {
|
||||
LEDC_CHAN(group, channel).conf0.val |= BIT(4);
|
||||
#endif
|
||||
LEDC_CHAN(group, channel).conf0.low_speed_update = 1;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
} else {
|
||||
LEDC_CHAN(group, channel).conf0.clk_en = 1;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
LEDC_CHAN(group, channel).conf0.sig_out_en = 0;//This is the output enable control bit for channel
|
||||
LEDC_CHAN(group, channel).conf1.duty_start = 0;//When duty_num duty_cycle and duty_scale has been configured. these register won't take effect until set duty_start. this bit is automatically cleared by hardware.
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
if(group) {
|
||||
LEDC_CHAN(group, channel).conf0.val &= ~BIT(4);
|
||||
#endif
|
||||
LEDC_CHAN(group, channel).conf0.low_speed_update = 1;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
} else {
|
||||
LEDC_CHAN(group, channel).conf0.clk_en = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
LEDC_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
uint32_t ledcRead(uint8_t chan)
|
||||
{
|
||||
if(chan > 15) {
|
||||
if(chan > LAST_CHAN) {
|
||||
return 0;
|
||||
}
|
||||
return LEDC.channel_group[chan/8].channel[chan%8].duty.duty >> 4;
|
||||
@ -201,7 +271,7 @@ double ledcReadFreq(uint8_t chan)
|
||||
|
||||
double ledcWriteTone(uint8_t chan, double freq)
|
||||
{
|
||||
if(chan > 15) {
|
||||
if(chan > LAST_CHAN) {
|
||||
return 0;
|
||||
}
|
||||
if(!freq) {
|
||||
@ -228,11 +298,15 @@ double ledcWriteNote(uint8_t chan, note_t note, uint8_t octave){
|
||||
|
||||
void ledcAttachPin(uint8_t pin, uint8_t chan)
|
||||
{
|
||||
if(chan > 15) {
|
||||
if(chan > LAST_CHAN) {
|
||||
return;
|
||||
}
|
||||
pinMode(pin, OUTPUT);
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
pinMatrixOutAttach(pin, LEDC_LS_SIG_OUT0_IDX + chan, false, false);
|
||||
#else
|
||||
pinMatrixOutAttach(pin, ((chan/8)?LEDC_LS_SIG_OUT0_IDX:LEDC_HS_SIG_OUT0_IDX) + (chan%8), false, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ledcDetachPin(uint8_t pin)
|
||||
|
@ -20,6 +20,7 @@ extern "C"
|
||||
#endif
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_timer.h"
|
||||
|
||||
#define ARDUHAL_LOG_LEVEL_NONE (0)
|
||||
#define ARDUHAL_LOG_LEVEL_ERROR (1)
|
||||
@ -75,42 +76,54 @@ const char * pathToFileName(const char * path);
|
||||
int log_printf(const char *fmt, ...);
|
||||
|
||||
#define ARDUHAL_SHORT_LOG_FORMAT(letter, format) ARDUHAL_LOG_COLOR_ ## letter format ARDUHAL_LOG_RESET_COLOR "\r\n"
|
||||
#define ARDUHAL_LOG_FORMAT(letter, format) ARDUHAL_LOG_COLOR_ ## letter "[" #letter "][%s:%u] %s(): " format ARDUHAL_LOG_RESET_COLOR "\r\n", pathToFileName(__FILE__), __LINE__, __FUNCTION__
|
||||
#define ARDUHAL_LOG_FORMAT(letter, format) ARDUHAL_LOG_COLOR_ ## letter "[%6u][" #letter "][%s:%u] %s(): " format ARDUHAL_LOG_RESET_COLOR "\r\n", (unsigned long) (esp_timer_get_time() / 1000ULL), pathToFileName(__FILE__), __LINE__, __FUNCTION__
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
|
||||
#define log_v(format, ...) log_printf(ARDUHAL_LOG_FORMAT(V, format), ##__VA_ARGS__)
|
||||
#define isr_log_v(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(V, format), ##__VA_ARGS__)
|
||||
#else
|
||||
#define log_v(format, ...)
|
||||
#define isr_log_v(format, ...)
|
||||
#endif
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
|
||||
#define log_d(format, ...) log_printf(ARDUHAL_LOG_FORMAT(D, format), ##__VA_ARGS__)
|
||||
#define isr_log_d(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(D, format), ##__VA_ARGS__)
|
||||
#else
|
||||
#define log_d(format, ...)
|
||||
#define isr_log_d(format, ...)
|
||||
#endif
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
#define log_i(format, ...) log_printf(ARDUHAL_LOG_FORMAT(I, format), ##__VA_ARGS__)
|
||||
#define isr_log_i(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(I, format), ##__VA_ARGS__)
|
||||
#else
|
||||
#define log_i(format, ...)
|
||||
#define isr_log_i(format, ...)
|
||||
#endif
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_WARN
|
||||
#define log_w(format, ...) log_printf(ARDUHAL_LOG_FORMAT(W, format), ##__VA_ARGS__)
|
||||
#define isr_log_w(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(W, format), ##__VA_ARGS__)
|
||||
#else
|
||||
#define log_w(format, ...)
|
||||
#define isr_log_w(format, ...)
|
||||
#endif
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
|
||||
#define log_e(format, ...) log_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__)
|
||||
#define isr_log_e(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__)
|
||||
#else
|
||||
#define log_e(format, ...)
|
||||
#define isr_log_e(format, ...)
|
||||
#endif
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_NONE
|
||||
#define log_n(format, ...) log_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__)
|
||||
#define isr_log_n(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__)
|
||||
#else
|
||||
#define log_n(format, ...)
|
||||
#define isr_log_n(format, ...)
|
||||
#endif
|
||||
|
||||
#include "esp_log.h"
|
||||
@ -121,12 +134,22 @@ int log_printf(const char *fmt, ...);
|
||||
#undef ESP_LOGI
|
||||
#undef ESP_LOGD
|
||||
#undef ESP_LOGV
|
||||
#undef ESP_EARLY_LOGE
|
||||
#undef ESP_EARLY_LOGW
|
||||
#undef ESP_EARLY_LOGI
|
||||
#undef ESP_EARLY_LOGD
|
||||
#undef ESP_EARLY_LOGV
|
||||
|
||||
#define ESP_LOGE(tag, ...) log_e(__VA_ARGS__)
|
||||
#define ESP_LOGW(tag, ...) log_w(__VA_ARGS__)
|
||||
#define ESP_LOGI(tag, ...) log_i(__VA_ARGS__)
|
||||
#define ESP_LOGD(tag, ...) log_d(__VA_ARGS__)
|
||||
#define ESP_LOGV(tag, ...) log_v(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGE(tag, ...) isr_log_e(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGW(tag, ...) isr_log_w(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGI(tag, ...) isr_log_i(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGD(tag, ...) isr_log_d(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGV(tag, ...) isr_log_v(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -14,33 +14,45 @@
|
||||
|
||||
#include "esp32-hal-matrix.h"
|
||||
#include "esp_attr.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/gpio.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/gpio.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/gpio.h"
|
||||
#endif
|
||||
|
||||
#define MATRIX_DETACH_OUT_SIG 0x100
|
||||
#define MATRIX_DETACH_IN_LOW_PIN 0x30
|
||||
#define MATRIX_DETACH_IN_LOW_HIGH 0x38
|
||||
|
||||
void IRAM_ATTR pinMatrixOutAttach(uint8_t pin, uint8_t function, bool invertOut, bool invertEnable)
|
||||
void ARDUINO_ISR_ATTR pinMatrixOutAttach(uint8_t pin, uint8_t function, bool invertOut, bool invertEnable)
|
||||
{
|
||||
gpio_matrix_out(pin, function, invertOut, invertEnable);
|
||||
}
|
||||
|
||||
void IRAM_ATTR pinMatrixOutDetach(uint8_t pin, bool invertOut, bool invertEnable)
|
||||
void ARDUINO_ISR_ATTR pinMatrixOutDetach(uint8_t pin, bool invertOut, bool invertEnable)
|
||||
{
|
||||
gpio_matrix_out(pin, MATRIX_DETACH_OUT_SIG, invertOut, invertEnable);
|
||||
}
|
||||
|
||||
void IRAM_ATTR pinMatrixInAttach(uint8_t pin, uint8_t signal, bool inverted)
|
||||
void ARDUINO_ISR_ATTR pinMatrixInAttach(uint8_t pin, uint8_t signal, bool inverted)
|
||||
{
|
||||
gpio_matrix_in(pin, signal, inverted);
|
||||
}
|
||||
|
||||
void IRAM_ATTR pinMatrixInDetach(uint8_t signal, bool high, bool inverted)
|
||||
void ARDUINO_ISR_ATTR pinMatrixInDetach(uint8_t signal, bool high, bool inverted)
|
||||
{
|
||||
gpio_matrix_in(high?MATRIX_DETACH_IN_LOW_HIGH:MATRIX_DETACH_IN_LOW_PIN, signal, inverted);
|
||||
}
|
||||
/*
|
||||
void IRAM_ATTR intrMatrixAttach(uint32_t source, uint32_t inum){
|
||||
void ARDUINO_ISR_ATTR intrMatrixAttach(uint32_t source, uint32_t inum){
|
||||
intr_matrix_set(PRO_CPU_NUM, source, inum);
|
||||
}
|
||||
*/
|
||||
|
@ -12,7 +12,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "esp32-hal.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
@ -22,8 +21,31 @@
|
||||
#include "esp_partition.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
#ifdef CONFIG_APP_ROLLBACK_ENABLE
|
||||
#include "esp_ota_ops.h"
|
||||
#endif //CONFIG_APP_ROLLBACK_ENABLE
|
||||
#ifdef CONFIG_BT_ENABLED
|
||||
#include "esp_bt.h"
|
||||
#endif //CONFIG_BT_ENABLED
|
||||
#include <sys/time.h>
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/apb_ctrl_reg.h"
|
||||
#include "esp_task_wdt.h"
|
||||
#include "esp32-hal.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/rtc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/rtc.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/rtc.h"
|
||||
#endif
|
||||
|
||||
//Undocumented!!! Get chip temperature in Farenheit
|
||||
//Source: https://github.com/pcbreflux/espressif/blob/master/esp32/arduino/sketchbook/ESP32_int_temp_sensor/ESP32_int_temp_sensor.ino
|
||||
@ -34,19 +56,101 @@ float temperatureRead()
|
||||
return (temprature_sens_read() - 32) / 1.8;
|
||||
}
|
||||
|
||||
void yield()
|
||||
void __yield()
|
||||
{
|
||||
vPortYield();
|
||||
}
|
||||
|
||||
unsigned long IRAM_ATTR micros()
|
||||
{
|
||||
return (unsigned long) esp_timer_get_time();
|
||||
void yield() __attribute__ ((weak, alias("__yield")));
|
||||
|
||||
#if CONFIG_AUTOSTART_ARDUINO
|
||||
|
||||
extern TaskHandle_t loopTaskHandle;
|
||||
extern bool loopTaskWDTEnabled;
|
||||
|
||||
void enableLoopWDT(){
|
||||
if(loopTaskHandle != NULL){
|
||||
if(esp_task_wdt_add(loopTaskHandle) != ESP_OK){
|
||||
log_e("Failed to add loop task to WDT");
|
||||
} else {
|
||||
loopTaskWDTEnabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long IRAM_ATTR millis()
|
||||
void disableLoopWDT(){
|
||||
if(loopTaskHandle != NULL && loopTaskWDTEnabled){
|
||||
loopTaskWDTEnabled = false;
|
||||
if(esp_task_wdt_delete(loopTaskHandle) != ESP_OK){
|
||||
log_e("Failed to remove loop task from WDT");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void feedLoopWDT(){
|
||||
esp_err_t err = esp_task_wdt_reset();
|
||||
if(err != ESP_OK){
|
||||
log_e("Failed to feed WDT! Error: %d", err);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void enableCore0WDT(){
|
||||
TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0);
|
||||
if(idle_0 == NULL || esp_task_wdt_add(idle_0) != ESP_OK){
|
||||
log_e("Failed to add Core 0 IDLE task to WDT");
|
||||
}
|
||||
}
|
||||
|
||||
void disableCore0WDT(){
|
||||
TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0);
|
||||
if(idle_0 == NULL || esp_task_wdt_delete(idle_0) != ESP_OK){
|
||||
log_e("Failed to remove Core 0 IDLE task from WDT");
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
void enableCore1WDT(){
|
||||
TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1);
|
||||
if(idle_1 == NULL || esp_task_wdt_add(idle_1) != ESP_OK){
|
||||
log_e("Failed to add Core 1 IDLE task to WDT");
|
||||
}
|
||||
}
|
||||
|
||||
void disableCore1WDT(){
|
||||
TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1);
|
||||
if(idle_1 == NULL || esp_task_wdt_delete(idle_1) != ESP_OK){
|
||||
log_e("Failed to remove Core 1 IDLE task from WDT");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
BaseType_t xTaskCreateUniversal( TaskFunction_t pxTaskCode,
|
||||
const char * const pcName,
|
||||
const uint32_t usStackDepth,
|
||||
void * const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t * const pxCreatedTask,
|
||||
const BaseType_t xCoreID ){
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
if(xCoreID >= 0 && xCoreID < 2) {
|
||||
return xTaskCreatePinnedToCore(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask, xCoreID);
|
||||
} else {
|
||||
#endif
|
||||
return xTaskCreate(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask);
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned long ARDUINO_ISR_ATTR micros()
|
||||
{
|
||||
return (unsigned long) (esp_timer_get_time() / 1000);
|
||||
return (unsigned long) (esp_timer_get_time());
|
||||
}
|
||||
|
||||
unsigned long ARDUINO_ISR_ATTR millis()
|
||||
{
|
||||
return (unsigned long) (esp_timer_get_time() / 1000ULL);
|
||||
}
|
||||
|
||||
void delay(uint32_t ms)
|
||||
@ -54,7 +158,7 @@ void delay(uint32_t ms)
|
||||
vTaskDelay(ms / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
void IRAM_ATTR delayMicroseconds(uint32_t us)
|
||||
void ARDUINO_ISR_ATTR delayMicroseconds(uint32_t us)
|
||||
{
|
||||
uint32_t m = micros();
|
||||
if(us){
|
||||
@ -76,6 +180,9 @@ void initVariant() {}
|
||||
void init() __attribute__((weak));
|
||||
void init() {}
|
||||
|
||||
bool verifyOta() __attribute__((weak));
|
||||
bool verifyOta() { return true; }
|
||||
|
||||
#ifdef CONFIG_BT_ENABLED
|
||||
//overwritten in esp32-hal-bt.c
|
||||
bool btInUse() __attribute__((weak));
|
||||
@ -84,7 +191,26 @@ bool btInUse(){ return false; }
|
||||
|
||||
void initArduino()
|
||||
{
|
||||
#if CONFIG_SPIRAM_SUPPORT
|
||||
#ifdef CONFIG_APP_ROLLBACK_ENABLE
|
||||
const esp_partition_t *running = esp_ota_get_running_partition();
|
||||
esp_ota_img_states_t ota_state;
|
||||
if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
|
||||
if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
|
||||
if (verifyOta()) {
|
||||
esp_ota_mark_app_valid_cancel_rollback();
|
||||
} else {
|
||||
log_e("OTA verification failed! Start rollback to the previous version ...");
|
||||
esp_ota_mark_app_invalid_rollback_and_reboot();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//init proper ref tick value for PLL (uncomment if REF_TICK is different than 1MHz)
|
||||
//ESP_REG(APB_CTRL_PLL_TICK_CONF_REG) = APB_CLK_FREQ / REF_CLK_FREQ - 1;
|
||||
#ifdef F_CPU
|
||||
setCpuFrequencyMhz(F_CPU/1000000);
|
||||
#endif
|
||||
#if CONFIG_SPIRAM_SUPPORT || CONFIG_SPIRAM
|
||||
psramInit();
|
||||
#endif
|
||||
esp_log_level_set("*", CONFIG_LOG_DEFAULT_LEVEL);
|
||||
@ -113,7 +239,7 @@ void initArduino()
|
||||
}
|
||||
|
||||
//used by hal log
|
||||
const char * IRAM_ATTR pathToFileName(const char * path)
|
||||
const char * ARDUINO_ISR_ATTR pathToFileName(const char * path)
|
||||
{
|
||||
size_t i = 0;
|
||||
size_t pos = 0;
|
||||
|
@ -1,12 +1,37 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "esp32-hal.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_SPIRAM_SUPPORT
|
||||
#include "esp_spiram.h"
|
||||
#if CONFIG_SPIRAM_SUPPORT || CONFIG_SPIRAM
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/spiram.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/spiram.h"
|
||||
#include "esp32s2/rom/cache.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "esp_spiram.h"
|
||||
#endif
|
||||
|
||||
static volatile bool spiramDetected = false;
|
||||
static volatile bool spiramFailed = false;
|
||||
|
||||
@ -18,21 +43,30 @@ bool psramInit(){
|
||||
if (spiramFailed) {
|
||||
return false;
|
||||
}
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG);
|
||||
uint32_t pkg_ver = chip_ver & 0x7;
|
||||
if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 || pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2 || pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) {
|
||||
if (pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 || pkg_ver == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2) {
|
||||
spiramFailed = true;
|
||||
log_w("PSRAM not supported!");
|
||||
return false;
|
||||
}
|
||||
esp_spiram_init_cache();
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
extern void esp_config_data_cache_mode(void);
|
||||
esp_config_data_cache_mode();
|
||||
Cache_Enable_DCache(0);
|
||||
#endif
|
||||
if (esp_spiram_init() != ESP_OK) {
|
||||
spiramFailed = true;
|
||||
log_w("PSRAM init failed!");
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
pinMatrixOutDetach(16, false, false);
|
||||
pinMatrixOutDetach(17, false, false);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
esp_spiram_init_cache();
|
||||
if (!esp_spiram_test()) {
|
||||
spiramFailed = true;
|
||||
log_e("PSRAM test failed!");
|
||||
@ -43,31 +77,34 @@ bool psramInit(){
|
||||
log_e("PSRAM could not be added to the heap!");
|
||||
return false;
|
||||
}
|
||||
#if CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL && !CONFIG_ARDUINO_ISR_IRAM
|
||||
heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL);
|
||||
#endif
|
||||
#endif
|
||||
spiramDetected = true;
|
||||
log_d("PSRAM enabled");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IRAM_ATTR psramFound(){
|
||||
bool ARDUINO_ISR_ATTR psramFound(){
|
||||
return spiramDetected;
|
||||
}
|
||||
|
||||
void IRAM_ATTR *ps_malloc(size_t size){
|
||||
void ARDUINO_ISR_ATTR *ps_malloc(size_t size){
|
||||
if(!spiramDetected){
|
||||
return NULL;
|
||||
}
|
||||
return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
}
|
||||
|
||||
void IRAM_ATTR *ps_calloc(size_t n, size_t size){
|
||||
void ARDUINO_ISR_ATTR *ps_calloc(size_t n, size_t size){
|
||||
if(!spiramDetected){
|
||||
return NULL;
|
||||
}
|
||||
return heap_caps_calloc(n, size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
}
|
||||
|
||||
void IRAM_ATTR *ps_realloc(void *ptr, size_t size){
|
||||
void ARDUINO_ISR_ATTR *ps_realloc(void *ptr, size_t size){
|
||||
if(!spiramDetected){
|
||||
return NULL;
|
||||
}
|
||||
@ -80,19 +117,19 @@ bool psramInit(){
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IRAM_ATTR psramFound(){
|
||||
bool ARDUINO_ISR_ATTR psramFound(){
|
||||
return false;
|
||||
}
|
||||
|
||||
void IRAM_ATTR *ps_malloc(size_t size){
|
||||
void ARDUINO_ISR_ATTR *ps_malloc(size_t size){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void IRAM_ATTR *ps_calloc(size_t n, size_t size){
|
||||
void ARDUINO_ISR_ATTR *ps_calloc(size_t n, size_t size){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void IRAM_ATTR *ps_realloc(void *ptr, size_t size){
|
||||
void ARDUINO_ISR_ATTR *ps_realloc(void *ptr, size_t size){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,21 @@
|
||||
#ifndef _ESP32_HAL_PSRAM_H_
|
||||
#define _ESP32_HAL_PSRAM_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifndef BOARD_HAS_PSRAM
|
||||
#ifdef CONFIG_SPIRAM_SUPPORT
|
||||
#undef CONFIG_SPIRAM_SUPPORT
|
||||
#endif
|
||||
#ifdef CONFIG_SPIRAM
|
||||
#undef CONFIG_SPIRAM
|
||||
#endif
|
||||
#endif
|
||||
|
||||
bool psramInit();
|
||||
bool psramFound();
|
||||
|
||||
@ -22,4 +37,8 @@ void *ps_malloc(size_t size);
|
||||
void *ps_calloc(size_t n, size_t size);
|
||||
void *ps_realloc(void *ptr, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ESP32_HAL_PSRAM_H_ */
|
||||
|
847
cores/esp32/esp32-hal-rmt.c
Normal file
847
cores/esp32/esp32-hal-rmt.c
Normal file
@ -0,0 +1,847 @@
|
||||
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#include "esp32-hal.h"
|
||||
#include "esp8266-compat.h"
|
||||
#include "soc/gpio_reg.h"
|
||||
#include "soc/rmt_struct.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
|
||||
/**
|
||||
* Internal macros
|
||||
*/
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#define MAX_CHANNELS 8
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define MAX_CHANNELS 4
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#define MAX_DATA_PER_CHANNEL 64
|
||||
#define MAX_DATA_PER_ITTERATION 62
|
||||
#define _ABS(a) (a>0?a:-a)
|
||||
#define _LIMIT(a,b) (a>b?b:a)
|
||||
#define __INT_TX_END (1)
|
||||
#define __INT_RX_END (2)
|
||||
#define __INT_ERROR (4)
|
||||
#define __INT_THR_EVNT (1<<24)
|
||||
|
||||
#define _INT_TX_END(channel) (__INT_TX_END<<(channel*3))
|
||||
#define _INT_RX_END(channel) (__INT_RX_END<<(channel*3))
|
||||
#define _INT_ERROR(channel) (__INT_ERROR<<(channel*3))
|
||||
#define _INT_THR_EVNT(channel) ((__INT_THR_EVNT)<<(channel))
|
||||
|
||||
#if CONFIG_DISABLE_HAL_LOCKS
|
||||
# define RMT_MUTEX_LOCK(channel)
|
||||
# define RMT_MUTEX_UNLOCK(channel)
|
||||
#else
|
||||
# define RMT_MUTEX_LOCK(channel) do {} while (xSemaphoreTake(g_rmt_objlocks[channel], portMAX_DELAY) != pdPASS)
|
||||
# define RMT_MUTEX_UNLOCK(channel) xSemaphoreGive(g_rmt_objlocks[channel])
|
||||
#endif /* CONFIG_DISABLE_HAL_LOCKS */
|
||||
|
||||
#define _RMT_INTERNAL_DEBUG
|
||||
#ifdef _RMT_INTERNAL_DEBUG
|
||||
# define DEBUG_INTERRUPT_START(pin) digitalWrite(pin, 1);
|
||||
# define DEBUG_INTERRUPT_END(pin) digitalWrite(pin, 0);
|
||||
#else
|
||||
# define DEBUG_INTERRUPT_START(pin)
|
||||
# define DEBUG_INTERRUPT_END(pin)
|
||||
#endif /* _RMT_INTERNAL_DEBUG */
|
||||
|
||||
/**
|
||||
* Typedefs for internal stuctures, enums
|
||||
*/
|
||||
typedef enum {
|
||||
E_NO_INTR = 0,
|
||||
E_TX_INTR = 1,
|
||||
E_TXTHR_INTR = 2,
|
||||
E_RX_INTR = 4,
|
||||
} intr_mode_t;
|
||||
|
||||
typedef enum {
|
||||
E_INACTIVE = 0,
|
||||
E_FIRST_HALF = 1,
|
||||
E_LAST_DATA = 2,
|
||||
E_END_TRANS = 4,
|
||||
E_SET_CONTI = 8,
|
||||
} transaction_state_t;
|
||||
|
||||
struct rmt_obj_s
|
||||
{
|
||||
bool allocated;
|
||||
EventGroupHandle_t events;
|
||||
int pin;
|
||||
int channel;
|
||||
bool tx_not_rx;
|
||||
int buffers;
|
||||
int data_size;
|
||||
uint32_t* data_ptr;
|
||||
intr_mode_t intr_mode;
|
||||
transaction_state_t tx_state;
|
||||
rmt_rx_data_cb_t cb;
|
||||
bool data_alloc;
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal variables for channel descriptors
|
||||
*/
|
||||
static xSemaphoreHandle g_rmt_objlocks[MAX_CHANNELS] = {
|
||||
NULL, NULL, NULL, NULL,
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
NULL, NULL, NULL, NULL
|
||||
#endif
|
||||
};
|
||||
|
||||
static rmt_obj_t g_rmt_objects[MAX_CHANNELS] = {
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false},
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false},
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false},
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false},
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false},
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false},
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false},
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false},
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal variables for driver data
|
||||
*/
|
||||
static intr_handle_t intr_handle;
|
||||
|
||||
static bool periph_enabled = false;
|
||||
|
||||
static xSemaphoreHandle g_rmt_block_lock = NULL;
|
||||
|
||||
/**
|
||||
* Internal method (private) declarations
|
||||
*/
|
||||
static void _initPin(int pin, int channel, bool tx_not_rx);
|
||||
|
||||
static bool _rmtSendOnce(rmt_obj_t* rmt, rmt_data_t* data, size_t size, bool continuous);
|
||||
|
||||
static void ARDUINO_ISR_ATTR _rmt_isr(void* arg);
|
||||
|
||||
static rmt_obj_t* _rmtAllocate(int pin, int from, int size);
|
||||
|
||||
static void _initPin(int pin, int channel, bool tx_not_rx);
|
||||
|
||||
static int ARDUINO_ISR_ATTR _rmt_get_mem_len(uint8_t channel);
|
||||
|
||||
static void ARDUINO_ISR_ATTR _rmt_tx_mem_first(uint8_t ch);
|
||||
|
||||
static void ARDUINO_ISR_ATTR _rmt_tx_mem_second(uint8_t ch);
|
||||
|
||||
|
||||
/**
|
||||
* Public method definitions
|
||||
*/
|
||||
bool rmtSetCarrier(rmt_obj_t* rmt, bool carrier_en, bool carrier_level, uint32_t low, uint32_t high)
|
||||
{
|
||||
if (!rmt || low > 0xFFFF || high > 0xFFFF) {
|
||||
return false;
|
||||
}
|
||||
size_t channel = rmt->channel;
|
||||
|
||||
RMT_MUTEX_LOCK(channel);
|
||||
|
||||
RMT.carrier_duty_ch[channel].low = low;
|
||||
RMT.carrier_duty_ch[channel].high = high;
|
||||
RMT.conf_ch[channel].conf0.carrier_en = carrier_en;
|
||||
RMT.conf_ch[channel].conf0.carrier_out_lv = carrier_level;
|
||||
|
||||
RMT_MUTEX_UNLOCK(channel);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool rmtSetFilter(rmt_obj_t* rmt, bool filter_en, uint32_t filter_level)
|
||||
{
|
||||
if (!rmt || filter_level > 0xFF) {
|
||||
return false;
|
||||
}
|
||||
size_t channel = rmt->channel;
|
||||
|
||||
RMT_MUTEX_LOCK(channel);
|
||||
|
||||
RMT.conf_ch[channel].conf1.rx_filter_thres = filter_level;
|
||||
RMT.conf_ch[channel].conf1.rx_filter_en = filter_en;
|
||||
|
||||
RMT_MUTEX_UNLOCK(channel);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool rmtSetRxThreshold(rmt_obj_t* rmt, uint32_t value)
|
||||
{
|
||||
if (!rmt || value > 0xFFFF) {
|
||||
return false;
|
||||
}
|
||||
size_t channel = rmt->channel;
|
||||
|
||||
RMT_MUTEX_LOCK(channel);
|
||||
RMT.conf_ch[channel].conf0.idle_thres = value;
|
||||
RMT_MUTEX_UNLOCK(channel);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool rmtDeinit(rmt_obj_t *rmt)
|
||||
{
|
||||
if (!rmt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// sanity check
|
||||
if (rmt != &(g_rmt_objects[rmt->channel])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t from = rmt->channel;
|
||||
size_t to = rmt->buffers + rmt->channel;
|
||||
size_t i;
|
||||
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
if(g_rmt_objlocks[from] != NULL) {
|
||||
vSemaphoreDelete(g_rmt_objlocks[from]);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (g_rmt_objects[from].data_alloc) {
|
||||
free(g_rmt_objects[from].data_ptr);
|
||||
}
|
||||
|
||||
for (i = from; i < to; i++) {
|
||||
g_rmt_objects[i].allocated = false;
|
||||
}
|
||||
|
||||
g_rmt_objects[from].channel = 0;
|
||||
g_rmt_objects[from].buffers = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rmtLoop(rmt_obj_t* rmt, rmt_data_t* data, size_t size)
|
||||
{
|
||||
if (!rmt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int allocated_size = MAX_DATA_PER_CHANNEL * rmt->buffers;
|
||||
|
||||
if (size > allocated_size) {
|
||||
return false;
|
||||
}
|
||||
return _rmtSendOnce(rmt, data, size, true);
|
||||
}
|
||||
|
||||
bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size)
|
||||
{
|
||||
if (!rmt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int channel = rmt->channel;
|
||||
int allocated_size = MAX_DATA_PER_CHANNEL * rmt->buffers;
|
||||
|
||||
if (size > allocated_size) {
|
||||
|
||||
int half_tx_nr = MAX_DATA_PER_ITTERATION/2;
|
||||
RMT_MUTEX_LOCK(channel);
|
||||
// setup interrupt handler if not yet installed for half and full tx
|
||||
if (!intr_handle) {
|
||||
esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ARDUINO_ISR_FLAG, _rmt_isr, NULL, &intr_handle);
|
||||
}
|
||||
|
||||
rmt->data_size = size - MAX_DATA_PER_ITTERATION;
|
||||
rmt->data_ptr = ((uint32_t*)data) + MAX_DATA_PER_ITTERATION;
|
||||
rmt->intr_mode = E_TX_INTR | E_TXTHR_INTR;
|
||||
rmt->tx_state = E_SET_CONTI | E_FIRST_HALF;
|
||||
|
||||
// init the tx limit for interruption
|
||||
RMT.tx_lim_ch[channel].limit = half_tx_nr+2;
|
||||
// reset memory pointer
|
||||
RMT.conf_ch[channel].conf1.apb_mem_rst = 1;
|
||||
RMT.conf_ch[channel].conf1.apb_mem_rst = 0;
|
||||
RMT.conf_ch[channel].conf1.mem_rd_rst = 1;
|
||||
RMT.conf_ch[channel].conf1.mem_rd_rst = 0;
|
||||
RMT.conf_ch[channel].conf1.mem_wr_rst = 1;
|
||||
RMT.conf_ch[channel].conf1.mem_wr_rst = 0;
|
||||
|
||||
// set the tx end mark
|
||||
RMTMEM.chan[channel].data32[MAX_DATA_PER_ITTERATION].val = 0;
|
||||
|
||||
// clear and enable both Tx completed and half tx event
|
||||
RMT.int_clr.val = _INT_TX_END(channel);
|
||||
RMT.int_clr.val = _INT_THR_EVNT(channel);
|
||||
RMT.int_clr.val = _INT_ERROR(channel);
|
||||
|
||||
RMT.int_ena.val |= _INT_TX_END(channel);
|
||||
RMT.int_ena.val |= _INT_THR_EVNT(channel);
|
||||
RMT.int_ena.val |= _INT_ERROR(channel);
|
||||
|
||||
RMT_MUTEX_UNLOCK(channel);
|
||||
|
||||
// start the transation
|
||||
return _rmtSendOnce(rmt, data, MAX_DATA_PER_ITTERATION, false);
|
||||
} else {
|
||||
// use one-go mode if data fits one buffer
|
||||
return _rmtSendOnce(rmt, data, size, false);
|
||||
}
|
||||
}
|
||||
|
||||
bool rmtReadData(rmt_obj_t* rmt, uint32_t* data, size_t size)
|
||||
{
|
||||
if (!rmt) {
|
||||
return false;
|
||||
}
|
||||
int channel = rmt->channel;
|
||||
|
||||
if (g_rmt_objects[channel].buffers < size/MAX_DATA_PER_CHANNEL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t i;
|
||||
volatile uint32_t* rmt_mem_ptr = &(RMTMEM.chan[channel].data32[0].val);
|
||||
for (i=0; i<size; i++) {
|
||||
data[i] = *rmt_mem_ptr++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rmtBeginReceive(rmt_obj_t* rmt)
|
||||
{
|
||||
if (!rmt) {
|
||||
return false;
|
||||
}
|
||||
int channel = rmt->channel;
|
||||
|
||||
RMT.int_clr.val = _INT_ERROR(channel);
|
||||
RMT.int_ena.val |= _INT_ERROR(channel);
|
||||
|
||||
RMT.conf_ch[channel].conf1.mem_owner = 1;
|
||||
RMT.conf_ch[channel].conf1.mem_wr_rst = 1;
|
||||
RMT.conf_ch[channel].conf1.rx_en = 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rmtReceiveCompleted(rmt_obj_t* rmt)
|
||||
{
|
||||
if (!rmt) {
|
||||
return false;
|
||||
}
|
||||
int channel = rmt->channel;
|
||||
|
||||
if (RMT.int_raw.val&_INT_RX_END(channel)) {
|
||||
// RX end flag
|
||||
RMT.int_clr.val = _INT_RX_END(channel);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb)
|
||||
{
|
||||
if (!rmt && !cb) {
|
||||
return false;
|
||||
}
|
||||
int channel = rmt->channel;
|
||||
|
||||
RMT_MUTEX_LOCK(channel);
|
||||
rmt->intr_mode = E_RX_INTR;
|
||||
rmt->tx_state = E_FIRST_HALF;
|
||||
rmt->cb = cb;
|
||||
// allocate internally two buffers which would alternate
|
||||
if (!rmt->data_alloc) {
|
||||
rmt->data_ptr = (uint32_t*)malloc(2*MAX_DATA_PER_CHANNEL*(rmt->buffers)*sizeof(uint32_t));
|
||||
rmt->data_size = MAX_DATA_PER_CHANNEL*rmt->buffers;
|
||||
rmt->data_alloc = true;
|
||||
}
|
||||
|
||||
RMT.conf_ch[channel].conf1.mem_owner = 1;
|
||||
|
||||
RMT.int_clr.val = _INT_RX_END(channel);
|
||||
RMT.int_clr.val = _INT_ERROR(channel);
|
||||
|
||||
RMT.int_ena.val |= _INT_RX_END(channel);
|
||||
RMT.int_ena.val |= _INT_ERROR(channel);
|
||||
|
||||
RMT.conf_ch[channel].conf1.mem_wr_rst = 1;
|
||||
|
||||
RMT.conf_ch[channel].conf1.rx_en = 1;
|
||||
RMT_MUTEX_UNLOCK(channel);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rmtReadAsync(rmt_obj_t* rmt, rmt_data_t* data, size_t size, void* eventFlag, bool waitForData, uint32_t timeout)
|
||||
{
|
||||
if (!rmt) {
|
||||
return false;
|
||||
}
|
||||
int channel = rmt->channel;
|
||||
|
||||
if (g_rmt_objects[channel].buffers < size/MAX_DATA_PER_CHANNEL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (eventFlag) {
|
||||
xEventGroupClearBits(eventFlag, RMT_FLAGS_ALL);
|
||||
rmt->events = eventFlag;
|
||||
}
|
||||
|
||||
if (data && size>0) {
|
||||
rmt->data_ptr = (uint32_t*)data;
|
||||
rmt->data_size = size;
|
||||
}
|
||||
|
||||
RMT_MUTEX_LOCK(channel);
|
||||
rmt->intr_mode = E_RX_INTR;
|
||||
|
||||
RMT.conf_ch[channel].conf1.mem_owner = 1;
|
||||
|
||||
RMT.int_clr.val = _INT_RX_END(channel);
|
||||
RMT.int_clr.val = _INT_ERROR(channel);
|
||||
|
||||
RMT.int_ena.val |= _INT_RX_END(channel);
|
||||
RMT.int_ena.val |= _INT_ERROR(channel);
|
||||
|
||||
RMT.conf_ch[channel].conf1.mem_wr_rst = 1;
|
||||
|
||||
RMT.conf_ch[channel].conf1.rx_en = 1;
|
||||
RMT_MUTEX_UNLOCK(channel);
|
||||
|
||||
// wait for data if requested so
|
||||
if (waitForData && eventFlag) {
|
||||
uint32_t flags = xEventGroupWaitBits(eventFlag, RMT_FLAGS_ALL,
|
||||
pdTRUE /* clear on exit */, pdFALSE /* wait for all bits */, timeout);
|
||||
if (flags & RMT_FLAG_ERROR) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float rmtSetTick(rmt_obj_t* rmt, float tick)
|
||||
{
|
||||
if (!rmt) {
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
divider field span from 1 (smallest), 2, 3, ... , 0xFF, 0x00 (highest)
|
||||
* rmt tick from 1/80M -> 12.5ns (1x) div_cnt = 0x01
|
||||
3.2 us (256x) div_cnt = 0x00
|
||||
* rmt tick for 1 MHz -> 1us (1x) div_cnt = 0x01
|
||||
256us (256x) div_cnt = 0x00
|
||||
*/
|
||||
int apb_div = _LIMIT(tick/12.5, 256);
|
||||
int ref_div = _LIMIT(tick/1000, 256);
|
||||
|
||||
float apb_tick = 12.5 * apb_div;
|
||||
float ref_tick = 1000.0 * ref_div;
|
||||
|
||||
size_t channel = rmt->channel;
|
||||
|
||||
if (_ABS(apb_tick - tick) < _ABS(ref_tick - tick)) {
|
||||
RMT.conf_ch[channel].conf0.div_cnt = apb_div & 0xFF;
|
||||
RMT.conf_ch[channel].conf1.ref_always_on = 1;
|
||||
return apb_tick;
|
||||
} else {
|
||||
RMT.conf_ch[channel].conf0.div_cnt = ref_div & 0xFF;
|
||||
RMT.conf_ch[channel].conf1.ref_always_on = 0;
|
||||
return ref_tick;
|
||||
}
|
||||
}
|
||||
|
||||
rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize)
|
||||
{
|
||||
int buffers = memsize;
|
||||
rmt_obj_t* rmt;
|
||||
size_t i;
|
||||
size_t j;
|
||||
|
||||
// create common block mutex for protecting allocs from multiple threads
|
||||
if (!g_rmt_block_lock) {
|
||||
g_rmt_block_lock = xSemaphoreCreateMutex();
|
||||
}
|
||||
// lock
|
||||
while (xSemaphoreTake(g_rmt_block_lock, portMAX_DELAY) != pdPASS) {}
|
||||
|
||||
for (i=0; i<MAX_CHANNELS; i++) {
|
||||
for (j=0; j<buffers && i+j < MAX_CHANNELS; j++) {
|
||||
// if the space is ocupied break and continue on other channel
|
||||
if (g_rmt_objects[i+j].allocated) {
|
||||
i += j; // continue searching from latter channel
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j == buffers) {
|
||||
// found a space in channel descriptors
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == MAX_CHANNELS || i+j > MAX_CHANNELS || j != buffers) {
|
||||
xSemaphoreGive(g_rmt_block_lock);
|
||||
return NULL;
|
||||
}
|
||||
rmt = _rmtAllocate(pin, i, buffers);
|
||||
|
||||
xSemaphoreGive(g_rmt_block_lock);
|
||||
|
||||
size_t channel = i;
|
||||
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
if(g_rmt_objlocks[channel] == NULL) {
|
||||
g_rmt_objlocks[channel] = xSemaphoreCreateMutex();
|
||||
if(g_rmt_objlocks[channel] == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
RMT_MUTEX_LOCK(channel);
|
||||
|
||||
rmt->pin = pin;
|
||||
rmt->tx_not_rx = tx_not_rx;
|
||||
rmt->buffers =buffers;
|
||||
rmt->channel = channel;
|
||||
_initPin(pin, channel, tx_not_rx);
|
||||
|
||||
// Initialize the registers in default mode:
|
||||
// - no carrier, filter
|
||||
// - timebase tick of 1us
|
||||
// - idle threshold set to 0x8000 (max pulse width + 1)
|
||||
RMT.conf_ch[channel].conf0.div_cnt = 1;
|
||||
RMT.conf_ch[channel].conf0.mem_size = buffers;
|
||||
RMT.conf_ch[channel].conf0.carrier_en = 0;
|
||||
RMT.conf_ch[channel].conf0.carrier_out_lv = 0;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
RMT.conf_ch[channel].conf0.mem_pd = 0;
|
||||
#endif
|
||||
RMT.conf_ch[channel].conf0.idle_thres = 0x80;
|
||||
RMT.conf_ch[channel].conf1.rx_en = 0;
|
||||
RMT.conf_ch[channel].conf1.tx_conti_mode = 0;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
RMT.conf_ch[channel].conf1.ref_cnt_rst = 0;
|
||||
#else
|
||||
RMT.conf_ch[channel].conf1.chk_rx_carrier_en = 0;
|
||||
#endif
|
||||
RMT.conf_ch[channel].conf1.rx_filter_en = 0;
|
||||
RMT.conf_ch[channel].conf1.rx_filter_thres = 0;
|
||||
RMT.conf_ch[channel].conf1.idle_out_lv = 0; // signal level for idle
|
||||
RMT.conf_ch[channel].conf1.idle_out_en = 1; // enable idle
|
||||
RMT.conf_ch[channel].conf1.ref_always_on = 0; // base clock
|
||||
RMT.apb_conf.fifo_mask = 1;
|
||||
|
||||
if (tx_not_rx) {
|
||||
// RMT.conf_ch[channel].conf1.rx_en = 0;
|
||||
RMT.conf_ch[channel].conf1.mem_owner = 0;
|
||||
RMT.conf_ch[channel].conf1.mem_rd_rst = 1;
|
||||
} else {
|
||||
// RMT.conf_ch[channel].conf1.rx_en = 1;
|
||||
RMT.conf_ch[channel].conf1.mem_owner = 1;
|
||||
RMT.conf_ch[channel].conf1.mem_wr_rst = 1;
|
||||
}
|
||||
|
||||
// install interrupt if at least one channel is active
|
||||
if (!intr_handle) {
|
||||
esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ARDUINO_ISR_FLAG, _rmt_isr, NULL, &intr_handle);
|
||||
}
|
||||
RMT_MUTEX_UNLOCK(channel);
|
||||
|
||||
return rmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private methods definitions
|
||||
*/
|
||||
bool _rmtSendOnce(rmt_obj_t* rmt, rmt_data_t* data, size_t size, bool continuous)
|
||||
{
|
||||
if (!rmt) {
|
||||
return false;
|
||||
}
|
||||
int channel = rmt->channel;
|
||||
RMT.apb_conf.fifo_mask = 1;
|
||||
if (data && size>0) {
|
||||
size_t i;
|
||||
volatile uint32_t* rmt_mem_ptr = &(RMTMEM.chan[channel].data32[0].val);
|
||||
for (i = 0; i < size; i++) {
|
||||
*rmt_mem_ptr++ = data[i].val;
|
||||
}
|
||||
// tx end mark
|
||||
RMTMEM.chan[channel].data32[size].val = 0;
|
||||
}
|
||||
|
||||
RMT_MUTEX_LOCK(channel);
|
||||
RMT.conf_ch[channel].conf1.tx_conti_mode = continuous;
|
||||
RMT.conf_ch[channel].conf1.mem_rd_rst = 1;
|
||||
RMT.conf_ch[channel].conf1.tx_start = 1;
|
||||
RMT_MUTEX_UNLOCK(channel);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static rmt_obj_t* _rmtAllocate(int pin, int from, int size)
|
||||
{
|
||||
size_t i;
|
||||
// setup how many buffers shall we use
|
||||
g_rmt_objects[from].buffers = size;
|
||||
|
||||
for (i=0; i<size; i++) {
|
||||
// mark the block of channels as used
|
||||
g_rmt_objects[i+from].allocated = true;
|
||||
}
|
||||
return &(g_rmt_objects[from]);
|
||||
}
|
||||
|
||||
|
||||
static void _initPin(int pin, int channel, bool tx_not_rx)
|
||||
{
|
||||
if (!periph_enabled) {
|
||||
periph_enabled = true;
|
||||
periph_module_enable( PERIPH_RMT_MODULE );
|
||||
}
|
||||
if (tx_not_rx) {
|
||||
pinMode(pin, OUTPUT);
|
||||
pinMatrixOutAttach(pin, RMT_SIG_OUT0_IDX + channel, 0, 0);
|
||||
} else {
|
||||
pinMode(pin, INPUT);
|
||||
pinMatrixInAttach(pin, RMT_SIG_IN0_IDX + channel, 0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ARDUINO_ISR_ATTR _rmt_isr(void* arg)
|
||||
{
|
||||
int intr_val = RMT.int_st.val;
|
||||
size_t ch;
|
||||
for (ch = 0; ch < MAX_CHANNELS; ch++) {
|
||||
|
||||
if (intr_val & _INT_RX_END(ch)) {
|
||||
// clear the flag
|
||||
RMT.int_clr.val = _INT_RX_END(ch);
|
||||
RMT.int_ena.val &= ~_INT_RX_END(ch);
|
||||
|
||||
if ((g_rmt_objects[ch].intr_mode) & E_RX_INTR) {
|
||||
if (g_rmt_objects[ch].events) {
|
||||
xEventGroupSetBits(g_rmt_objects[ch].events, RMT_FLAG_RX_DONE);
|
||||
}
|
||||
if (g_rmt_objects[ch].data_ptr && g_rmt_objects[ch].data_size > 0) {
|
||||
size_t i;
|
||||
uint32_t * data = g_rmt_objects[ch].data_ptr;
|
||||
// in case of callback, provide switching between memories
|
||||
if (g_rmt_objects[ch].cb) {
|
||||
if (g_rmt_objects[ch].tx_state & E_FIRST_HALF) {
|
||||
g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF;
|
||||
} else {
|
||||
g_rmt_objects[ch].tx_state |= E_FIRST_HALF;
|
||||
data += MAX_DATA_PER_CHANNEL*(g_rmt_objects[ch].buffers);
|
||||
}
|
||||
}
|
||||
uint32_t *data_received = data;
|
||||
for (i = 0; i < g_rmt_objects[ch].data_size; i++ ) {
|
||||
*data++ = RMTMEM.chan[ch].data32[i].val;
|
||||
}
|
||||
if (g_rmt_objects[ch].cb) {
|
||||
// actually received data ptr
|
||||
(g_rmt_objects[ch].cb)(data_received, _rmt_get_mem_len(ch));
|
||||
|
||||
// restart the reception
|
||||
RMT.conf_ch[ch].conf1.mem_owner = 1;
|
||||
RMT.conf_ch[ch].conf1.mem_wr_rst = 1;
|
||||
RMT.conf_ch[ch].conf1.rx_en = 1;
|
||||
RMT.int_ena.val |= _INT_RX_END(ch);
|
||||
} else {
|
||||
// if not callback provide, expect only one Rx
|
||||
g_rmt_objects[ch].intr_mode &= ~E_RX_INTR;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Report error and disable Rx interrupt
|
||||
log_e("Unexpected Rx interrupt!\n"); // TODO: eplace messages with log_X
|
||||
RMT.int_ena.val &= ~_INT_RX_END(ch);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (intr_val & _INT_ERROR(ch)) {
|
||||
// clear the flag
|
||||
RMT.int_clr.val = _INT_ERROR(ch);
|
||||
RMT.int_ena.val &= ~_INT_ERROR(ch);
|
||||
// report error
|
||||
log_e("RMT Error %d!\n", ch);
|
||||
if (g_rmt_objects[ch].events) {
|
||||
xEventGroupSetBits(g_rmt_objects[ch].events, RMT_FLAG_ERROR);
|
||||
}
|
||||
// reset memory
|
||||
RMT.conf_ch[ch].conf1.mem_rd_rst = 1;
|
||||
RMT.conf_ch[ch].conf1.mem_rd_rst = 0;
|
||||
RMT.conf_ch[ch].conf1.mem_wr_rst = 1;
|
||||
RMT.conf_ch[ch].conf1.mem_wr_rst = 0;
|
||||
}
|
||||
|
||||
if (intr_val & _INT_TX_END(ch)) {
|
||||
|
||||
RMT.int_clr.val = _INT_TX_END(ch);
|
||||
_rmt_tx_mem_second(ch);
|
||||
}
|
||||
|
||||
if (intr_val & _INT_THR_EVNT(ch)) {
|
||||
// clear the flag
|
||||
RMT.int_clr.val = _INT_THR_EVNT(ch);
|
||||
|
||||
// initial setup of continuous mode
|
||||
if (g_rmt_objects[ch].tx_state & E_SET_CONTI) {
|
||||
RMT.conf_ch[ch].conf1.tx_conti_mode = 1;
|
||||
g_rmt_objects[ch].intr_mode &= ~E_SET_CONTI;
|
||||
}
|
||||
_rmt_tx_mem_first(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ARDUINO_ISR_ATTR _rmt_tx_mem_second(uint8_t ch)
|
||||
{
|
||||
DEBUG_INTERRUPT_START(4)
|
||||
uint32_t* data = g_rmt_objects[ch].data_ptr;
|
||||
int half_tx_nr = MAX_DATA_PER_ITTERATION/2;
|
||||
int i;
|
||||
|
||||
RMT.tx_lim_ch[ch].limit = half_tx_nr+2;
|
||||
RMT.int_clr.val = _INT_THR_EVNT(ch);
|
||||
RMT.int_ena.val |= _INT_THR_EVNT(ch);
|
||||
|
||||
g_rmt_objects[ch].tx_state |= E_FIRST_HALF;
|
||||
|
||||
if (data) {
|
||||
int remaining_size = g_rmt_objects[ch].data_size;
|
||||
// will the remaining data occupy the entire halfbuffer
|
||||
if (remaining_size > half_tx_nr) {
|
||||
for (i = 0; i < half_tx_nr; i++) {
|
||||
RMTMEM.chan[ch].data32[half_tx_nr+i].val = data[i];
|
||||
}
|
||||
g_rmt_objects[ch].data_size -= half_tx_nr;
|
||||
g_rmt_objects[ch].data_ptr += half_tx_nr;
|
||||
} else {
|
||||
for (i = 0; i < half_tx_nr; i++) {
|
||||
if (i < remaining_size) {
|
||||
RMTMEM.chan[ch].data32[half_tx_nr+i].val = data[i];
|
||||
} else {
|
||||
RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0x000F000F;
|
||||
}
|
||||
}
|
||||
g_rmt_objects[ch].data_ptr = NULL;
|
||||
|
||||
}
|
||||
} else if ((!(g_rmt_objects[ch].tx_state & E_LAST_DATA)) &&
|
||||
(!(g_rmt_objects[ch].tx_state & E_END_TRANS))) {
|
||||
for (i = 0; i < half_tx_nr; i++) {
|
||||
RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0x000F000F;
|
||||
}
|
||||
RMTMEM.chan[ch].data32[half_tx_nr+i].val = 0;
|
||||
g_rmt_objects[ch].tx_state |= E_LAST_DATA;
|
||||
RMT.conf_ch[ch].conf1.tx_conti_mode = 0;
|
||||
} else {
|
||||
log_d("RMT Tx finished %d!\n", ch);
|
||||
RMT.conf_ch[ch].conf1.tx_conti_mode = 0;
|
||||
RMT.int_ena.val &= ~_INT_TX_END(ch);
|
||||
RMT.int_ena.val &= ~_INT_THR_EVNT(ch);
|
||||
g_rmt_objects[ch].intr_mode = E_NO_INTR;
|
||||
g_rmt_objects[ch].tx_state = E_INACTIVE;
|
||||
}
|
||||
DEBUG_INTERRUPT_END(4);
|
||||
}
|
||||
|
||||
static void ARDUINO_ISR_ATTR _rmt_tx_mem_first(uint8_t ch)
|
||||
{
|
||||
DEBUG_INTERRUPT_START(2);
|
||||
uint32_t* data = g_rmt_objects[ch].data_ptr;
|
||||
int half_tx_nr = MAX_DATA_PER_ITTERATION/2;
|
||||
int i;
|
||||
RMT.int_ena.val &= ~_INT_THR_EVNT(ch);
|
||||
RMT.tx_lim_ch[ch].limit = 0;
|
||||
|
||||
if (data) {
|
||||
int remaining_size = g_rmt_objects[ch].data_size;
|
||||
|
||||
// will the remaining data occupy the entire halfbuffer
|
||||
if (remaining_size > half_tx_nr) {
|
||||
RMTMEM.chan[ch].data32[0].val = data[0] - 1;
|
||||
for (i = 1; i < half_tx_nr; i++) {
|
||||
RMTMEM.chan[ch].data32[i].val = data[i];
|
||||
}
|
||||
g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF;
|
||||
// turn off the treshold interrupt
|
||||
RMT.int_ena.val &= ~_INT_THR_EVNT(ch);
|
||||
RMT.tx_lim_ch[ch].limit = 0;
|
||||
g_rmt_objects[ch].data_size -= half_tx_nr;
|
||||
g_rmt_objects[ch].data_ptr += half_tx_nr;
|
||||
} else {
|
||||
RMTMEM.chan[ch].data32[0].val = data[0] - 1;
|
||||
for (i = 1; i < half_tx_nr; i++) {
|
||||
if (i < remaining_size) {
|
||||
RMTMEM.chan[ch].data32[i].val = data[i];
|
||||
} else {
|
||||
RMTMEM.chan[ch].data32[i].val = 0x000F000F;
|
||||
}
|
||||
}
|
||||
|
||||
g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF;
|
||||
g_rmt_objects[ch].data_ptr = NULL;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < half_tx_nr; i++) {
|
||||
RMTMEM.chan[ch].data32[i].val = 0x000F000F;
|
||||
}
|
||||
RMTMEM.chan[ch].data32[i].val = 0;
|
||||
|
||||
g_rmt_objects[ch].tx_state &= ~E_FIRST_HALF;
|
||||
RMT.tx_lim_ch[ch].limit = 0;
|
||||
g_rmt_objects[ch].tx_state |= E_LAST_DATA;
|
||||
RMT.conf_ch[ch].conf1.tx_conti_mode = 0;
|
||||
}
|
||||
DEBUG_INTERRUPT_END(2);
|
||||
}
|
||||
|
||||
static int ARDUINO_ISR_ATTR _rmt_get_mem_len(uint8_t channel)
|
||||
{
|
||||
int block_num = RMT.conf_ch[channel].conf0.mem_size;
|
||||
int item_block_len = block_num * 64;
|
||||
volatile rmt_item32_t* data = RMTMEM.chan[channel].data32;
|
||||
int idx;
|
||||
for(idx = 0; idx < item_block_len; idx++) {
|
||||
if(data[idx].duration0 == 0) {
|
||||
return idx;
|
||||
} else if(data[idx].duration1 == 0) {
|
||||
return idx + 1;
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
}
|
147
cores/esp32/esp32-hal-rmt.h
Normal file
147
cores/esp32/esp32-hal-rmt.h
Normal file
@ -0,0 +1,147 @@
|
||||
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef MAIN_ESP32_HAL_RMT_H_
|
||||
#define MAIN_ESP32_HAL_RMT_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// notification flags
|
||||
#define RMT_FLAG_TX_DONE (1)
|
||||
#define RMT_FLAG_RX_DONE (2)
|
||||
#define RMT_FLAG_ERROR (4)
|
||||
#define RMT_FLAGS_ALL (RMT_FLAG_TX_DONE | RMT_FLAG_RX_DONE | RMT_FLAG_ERROR)
|
||||
|
||||
struct rmt_obj_s;
|
||||
|
||||
typedef enum {
|
||||
RMT_MEM_64 = 1,
|
||||
RMT_MEM_128 = 2,
|
||||
RMT_MEM_192 = 3,
|
||||
RMT_MEM_256 = 4,
|
||||
RMT_MEM_320 = 5,
|
||||
RMT_MEM_384 = 6,
|
||||
RMT_MEM_448 = 7,
|
||||
RMT_MEM_512 = 8,
|
||||
} rmt_reserve_memsize_t;
|
||||
|
||||
typedef struct rmt_obj_s rmt_obj_t;
|
||||
|
||||
typedef void (*rmt_rx_data_cb_t)(uint32_t *data, size_t len);
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint32_t duration0 :15;
|
||||
uint32_t level0 :1;
|
||||
uint32_t duration1 :15;
|
||||
uint32_t level1 :1;
|
||||
};
|
||||
uint32_t val;
|
||||
};
|
||||
} rmt_data_t;
|
||||
|
||||
/**
|
||||
* Initialize the object
|
||||
*
|
||||
*/
|
||||
rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize);
|
||||
|
||||
/**
|
||||
* Sets the clock/divider of timebase the nearest tick to the supplied value in nanoseconds
|
||||
* return the real actual tick value in ns
|
||||
*/
|
||||
float rmtSetTick(rmt_obj_t* rmt, float tick);
|
||||
|
||||
/**
|
||||
* Sending data in one-go mode or continual mode
|
||||
* (more data being send while updating buffers in interrupts)
|
||||
*
|
||||
*/
|
||||
bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size);
|
||||
|
||||
/**
|
||||
* Loop data up to the reserved memsize continuously
|
||||
*
|
||||
*/
|
||||
bool rmtLoop(rmt_obj_t* rmt, rmt_data_t* data, size_t size);
|
||||
|
||||
/**
|
||||
* Initiates async receive, event flag indicates data received
|
||||
*
|
||||
*/
|
||||
bool rmtReadAsync(rmt_obj_t* rmt, rmt_data_t* data, size_t size, void* eventFlag, bool waitForData, uint32_t timeout);
|
||||
|
||||
/**
|
||||
* Initiates async receive with automatic buffering
|
||||
* and callback with data from ISR
|
||||
*
|
||||
*/
|
||||
bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb);
|
||||
|
||||
|
||||
/* Additional interface */
|
||||
|
||||
/**
|
||||
* Start reception
|
||||
*
|
||||
*/
|
||||
bool rmtBeginReceive(rmt_obj_t* rmt);
|
||||
|
||||
/**
|
||||
* Checks if reception completes
|
||||
*
|
||||
*/
|
||||
bool rmtReceiveCompleted(rmt_obj_t* rmt);
|
||||
|
||||
/**
|
||||
* Reads the data for particular channel
|
||||
*
|
||||
*/
|
||||
bool rmtReadData(rmt_obj_t* rmt, uint32_t* data, size_t size);
|
||||
|
||||
/**
|
||||
* Setting threshold for Rx completed
|
||||
*/
|
||||
bool rmtSetRxThreshold(rmt_obj_t* rmt, uint32_t value);
|
||||
|
||||
/**
|
||||
* Setting carrier
|
||||
*/
|
||||
bool rmtSetCarrier(rmt_obj_t* rmt, bool carrier_en, bool carrier_level, uint32_t low, uint32_t high);
|
||||
|
||||
/**
|
||||
* Setting input filter
|
||||
*/
|
||||
bool rmtSetFilter(rmt_obj_t* rmt, bool filter_en, uint32_t filter_level);
|
||||
|
||||
/**
|
||||
* Deinitialize the driver
|
||||
*/
|
||||
bool rmtDeinit(rmt_obj_t *rmt);
|
||||
|
||||
// TODO:
|
||||
// * uninstall interrupt when all channels are deinit
|
||||
// * send only-conti mode with circular-buffer
|
||||
// * put sanity checks to some macro or inlines
|
||||
// * doxy comments
|
||||
// * error reporting
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MAIN_ESP32_HAL_RMT_H_ */
|
@ -16,11 +16,23 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp32-hal-matrix.h"
|
||||
#include "soc/gpio_sd_reg.h"
|
||||
#include "soc/gpio_sd_struct.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/ets_sys.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/ets_sys.h"
|
||||
#endif
|
||||
|
||||
|
||||
#if CONFIG_DISABLE_HAL_LOCKS
|
||||
#define SD_MUTEX_LOCK()
|
||||
@ -31,6 +43,26 @@
|
||||
xSemaphoreHandle _sd_sys_lock;
|
||||
#endif
|
||||
|
||||
static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){
|
||||
if(old_apb == new_apb){
|
||||
return;
|
||||
}
|
||||
uint32_t iarg = (uint32_t)arg;
|
||||
uint8_t channel = iarg;
|
||||
if(ev_type == APB_BEFORE_CHANGE){
|
||||
SIGMADELTA.cg.clk_en = 0;
|
||||
} else {
|
||||
old_apb /= 1000000;
|
||||
new_apb /= 1000000;
|
||||
SD_MUTEX_LOCK();
|
||||
uint32_t old_prescale = SIGMADELTA.channel[channel].prescale + 1;
|
||||
SIGMADELTA.channel[channel].prescale = ((new_apb * old_prescale) / old_apb) - 1;
|
||||
SIGMADELTA.cg.clk_en = 0;
|
||||
SIGMADELTA.cg.clk_en = 1;
|
||||
SD_MUTEX_UNLOCK();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t sigmaDeltaSetup(uint8_t channel, uint32_t freq) //chan 0-7 freq 1220-312500
|
||||
{
|
||||
if(channel > 7) {
|
||||
@ -43,16 +75,22 @@ uint32_t sigmaDeltaSetup(uint8_t channel, uint32_t freq) //chan 0-7 freq 1220-31
|
||||
_sd_sys_lock = xSemaphoreCreateMutex();
|
||||
}
|
||||
#endif
|
||||
uint32_t prescale = (10000000/(freq*32)) - 1;
|
||||
uint32_t apb_freq = getApbFrequency();
|
||||
uint32_t prescale = (apb_freq/(freq*256)) - 1;
|
||||
if(prescale > 0xFF) {
|
||||
prescale = 0xFF;
|
||||
}
|
||||
SD_MUTEX_LOCK();
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32
|
||||
SIGMADELTA.misc.function_clk_en = 1;
|
||||
#endif
|
||||
SIGMADELTA.channel[channel].prescale = prescale;
|
||||
SIGMADELTA.cg.clk_en = 0;
|
||||
SIGMADELTA.cg.clk_en = 1;
|
||||
SD_MUTEX_UNLOCK();
|
||||
return 10000000/((prescale + 1) * 32);
|
||||
uint32_t iarg = channel;
|
||||
addApbChangeCallback((void*)iarg, _on_apb_change);
|
||||
return apb_freq/((prescale + 1) * 256);
|
||||
}
|
||||
|
||||
void sigmaDeltaWrite(uint8_t channel, uint8_t duty) //chan 0-7 duty 8 bit
|
||||
|
@ -17,15 +17,59 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_intr.h"
|
||||
#include "rom/gpio.h"
|
||||
#include "soc/spi_reg.h"
|
||||
#include "soc/spi_struct.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/rtc.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#include "esp32/rom/gpio.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/ets_sys.h"
|
||||
#include "esp32s2/rom/gpio.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/gpio.h"
|
||||
#include "esp_intr.h"
|
||||
#endif
|
||||
|
||||
struct spi_struct_t {
|
||||
spi_dev_t * dev;
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
xSemaphoreHandle lock;
|
||||
#endif
|
||||
uint8_t num;
|
||||
};
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
// ESP32S2
|
||||
#define SPI_COUNT (3)
|
||||
|
||||
#define SPI_CLK_IDX(p) ((p==0)?SPICLK_OUT_MUX_IDX:((p==1)?FSPICLK_OUT_MUX_IDX:((p==2)?SPI3_CLK_OUT_MUX_IDX:0)))
|
||||
#define SPI_MISO_IDX(p) ((p==0)?SPIQ_OUT_IDX:((p==1)?FSPIQ_OUT_IDX:((p==2)?SPI3_Q_OUT_IDX:0)))
|
||||
#define SPI_MOSI_IDX(p) ((p==0)?SPID_IN_IDX:((p==1)?FSPID_IN_IDX:((p==2)?SPI3_D_IN_IDX:0)))
|
||||
|
||||
#define SPI_SPI_SS_IDX(n) ((n==0)?SPICS0_OUT_IDX:((n==1)?SPICS1_OUT_IDX:0))
|
||||
#define SPI_HSPI_SS_IDX(n) ((n==0)?SPI3_CS0_OUT_IDX:((n==1)?SPI3_CS1_OUT_IDX:((n==2)?SPI3_CS2_OUT_IDX:SPI3_CS0_OUT_IDX)))
|
||||
#define SPI_FSPI_SS_IDX(n) ((n==0)?FSPICS0_OUT_IDX:((n==1)?FSPICS1_OUT_IDX:((n==2)?FSPICS2_OUT_IDX:VSPICS0_OUT_IDX)))
|
||||
#define SPI_SS_IDX(p, n) ((p==0)?SPI_SPI_SS_IDX(n):((p==1)?SPI_SPI_SS_IDX(n):((p==2)?SPI_HSPI_SS_IDX(n):0)))
|
||||
|
||||
#define SPI_INTR_SOURCE(u) ((u==0)?ETS_SPI1_INTR_SOURCE:((u==1)?ETS_SPI2_INTR_SOURCE:((u==2)?ETS_SPI3_INTR_SOURCE:0)))
|
||||
|
||||
#else
|
||||
// ESP32
|
||||
#define SPI_COUNT (4)
|
||||
|
||||
#define SPI_CLK_IDX(p) ((p==0)?SPICLK_OUT_IDX:((p==1)?SPICLK_OUT_IDX:((p==2)?HSPICLK_OUT_IDX:((p==3)?VSPICLK_OUT_IDX:0))))
|
||||
#define SPI_MISO_IDX(p) ((p==0)?SPIQ_OUT_IDX:((p==1)?SPIQ_OUT_IDX:((p==2)?HSPIQ_OUT_IDX:((p==3)?VSPIQ_OUT_IDX:0))))
|
||||
@ -36,36 +80,41 @@
|
||||
#define SPI_VSPI_SS_IDX(n) ((n==0)?VSPICS0_OUT_IDX:((n==1)?VSPICS1_OUT_IDX:((n==2)?VSPICS2_OUT_IDX:VSPICS0_OUT_IDX)))
|
||||
#define SPI_SS_IDX(p, n) ((p==0)?SPI_SPI_SS_IDX(n):((p==1)?SPI_SPI_SS_IDX(n):((p==2)?SPI_HSPI_SS_IDX(n):((p==3)?SPI_VSPI_SS_IDX(n):0))))
|
||||
|
||||
#define SPI_INUM(u) (2)
|
||||
#define SPI_INTR_SOURCE(u) ((u==0)?ETS_SPI0_INTR_SOURCE:((u==1)?ETS_SPI1_INTR_SOURCE:((u==2)?ETS_SPI2_INTR_SOURCE:((p==3)?ETS_SPI3_INTR_SOURCE:0))))
|
||||
|
||||
struct spi_struct_t {
|
||||
spi_dev_t * dev;
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
xSemaphoreHandle lock;
|
||||
#endif
|
||||
uint8_t num;
|
||||
};
|
||||
|
||||
#if CONFIG_DISABLE_HAL_LOCKS
|
||||
#define SPI_MUTEX_LOCK()
|
||||
#define SPI_MUTEX_UNLOCK()
|
||||
|
||||
static spi_t _spi_bus_array[4] = {
|
||||
static spi_t _spi_bus_array[] = {
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
{(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 0},
|
||||
{(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 1},
|
||||
{(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 2}
|
||||
#else
|
||||
{(volatile spi_dev_t *)(DR_REG_SPI0_BASE), 0},
|
||||
{(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 1},
|
||||
{(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 2},
|
||||
{(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 3}
|
||||
#endif
|
||||
};
|
||||
#else
|
||||
#define SPI_MUTEX_LOCK() do {} while (xSemaphoreTake(spi->lock, portMAX_DELAY) != pdPASS)
|
||||
#define SPI_MUTEX_UNLOCK() xSemaphoreGive(spi->lock)
|
||||
|
||||
static spi_t _spi_bus_array[4] = {
|
||||
static spi_t _spi_bus_array[] = {
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
{(volatile spi_dev_t *)(DR_REG_SPI1_BASE), NULL, 0},
|
||||
{(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 1},
|
||||
{(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 2}
|
||||
#else
|
||||
{(volatile spi_dev_t *)(DR_REG_SPI0_BASE), NULL, 0},
|
||||
{(volatile spi_dev_t *)(DR_REG_SPI1_BASE), NULL, 1},
|
||||
{(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 2},
|
||||
{(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 3}
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -75,6 +124,14 @@ void spiAttachSCK(spi_t * spi, int8_t sck)
|
||||
return;
|
||||
}
|
||||
if(sck < 0) {
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
if(spi->num == FSPI) {
|
||||
sck = 36;
|
||||
} else {
|
||||
log_e("HSPI Does not have default pins on ESP32S2!");
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if(spi->num == HSPI) {
|
||||
sck = 14;
|
||||
} else if(spi->num == VSPI) {
|
||||
@ -82,6 +139,7 @@ void spiAttachSCK(spi_t * spi, int8_t sck)
|
||||
} else {
|
||||
sck = 6;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
pinMode(sck, OUTPUT);
|
||||
pinMatrixOutAttach(sck, SPI_CLK_IDX(spi->num), false, false);
|
||||
@ -93,6 +151,14 @@ void spiAttachMISO(spi_t * spi, int8_t miso)
|
||||
return;
|
||||
}
|
||||
if(miso < 0) {
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
if(spi->num == FSPI) {
|
||||
miso = 37;
|
||||
} else {
|
||||
log_e("HSPI Does not have default pins on ESP32S2!");
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if(spi->num == HSPI) {
|
||||
miso = 12;
|
||||
} else if(spi->num == VSPI) {
|
||||
@ -100,6 +166,7 @@ void spiAttachMISO(spi_t * spi, int8_t miso)
|
||||
} else {
|
||||
miso = 7;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
SPI_MUTEX_LOCK();
|
||||
pinMode(miso, INPUT);
|
||||
@ -113,6 +180,14 @@ void spiAttachMOSI(spi_t * spi, int8_t mosi)
|
||||
return;
|
||||
}
|
||||
if(mosi < 0) {
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
if(spi->num == FSPI) {
|
||||
mosi = 35;
|
||||
} else {
|
||||
log_e("HSPI Does not have default pins on ESP32S2!");
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if(spi->num == HSPI) {
|
||||
mosi = 13;
|
||||
} else if(spi->num == VSPI) {
|
||||
@ -120,6 +195,7 @@ void spiAttachMOSI(spi_t * spi, int8_t mosi)
|
||||
} else {
|
||||
mosi = 8;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
pinMode(mosi, OUTPUT);
|
||||
pinMatrixOutAttach(mosi, SPI_MOSI_IDX(spi->num), false, false);
|
||||
@ -131,6 +207,14 @@ void spiDetachSCK(spi_t * spi, int8_t sck)
|
||||
return;
|
||||
}
|
||||
if(sck < 0) {
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
if(spi->num == FSPI) {
|
||||
sck = 36;
|
||||
} else {
|
||||
log_e("HSPI Does not have default pins on ESP32S2!");
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if(spi->num == HSPI) {
|
||||
sck = 14;
|
||||
} else if(spi->num == VSPI) {
|
||||
@ -138,6 +222,7 @@ void spiDetachSCK(spi_t * spi, int8_t sck)
|
||||
} else {
|
||||
sck = 6;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
pinMatrixOutDetach(sck, false, false);
|
||||
pinMode(sck, INPUT);
|
||||
@ -149,6 +234,14 @@ void spiDetachMISO(spi_t * spi, int8_t miso)
|
||||
return;
|
||||
}
|
||||
if(miso < 0) {
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
if(spi->num == FSPI) {
|
||||
miso = 37;
|
||||
} else {
|
||||
log_e("HSPI Does not have default pins on ESP32S2!");
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if(spi->num == HSPI) {
|
||||
miso = 12;
|
||||
} else if(spi->num == VSPI) {
|
||||
@ -156,6 +249,7 @@ void spiDetachMISO(spi_t * spi, int8_t miso)
|
||||
} else {
|
||||
miso = 7;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
pinMatrixInDetach(SPI_MISO_IDX(spi->num), false, false);
|
||||
pinMode(miso, INPUT);
|
||||
@ -167,6 +261,14 @@ void spiDetachMOSI(spi_t * spi, int8_t mosi)
|
||||
return;
|
||||
}
|
||||
if(mosi < 0) {
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
if(spi->num == FSPI) {
|
||||
mosi = 35;
|
||||
} else {
|
||||
log_e("HSPI Does not have default pins on ESP32S2!");
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if(spi->num == HSPI) {
|
||||
mosi = 13;
|
||||
} else if(spi->num == VSPI) {
|
||||
@ -174,6 +276,7 @@ void spiDetachMOSI(spi_t * spi, int8_t mosi)
|
||||
} else {
|
||||
mosi = 8;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
pinMatrixOutDetach(mosi, false, false);
|
||||
pinMode(mosi, INPUT);
|
||||
@ -189,6 +292,14 @@ void spiAttachSS(spi_t * spi, uint8_t cs_num, int8_t ss)
|
||||
}
|
||||
if(ss < 0) {
|
||||
cs_num = 0;
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
if(spi->num == FSPI) {
|
||||
ss = 34;
|
||||
} else {
|
||||
log_e("HSPI Does not have default pins on ESP32S2!");
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if(spi->num == HSPI) {
|
||||
ss = 15;
|
||||
} else if(spi->num == VSPI) {
|
||||
@ -196,6 +307,7 @@ void spiAttachSS(spi_t * spi, uint8_t cs_num, int8_t ss)
|
||||
} else {
|
||||
ss = 11;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
pinMode(ss, OUTPUT);
|
||||
pinMatrixOutAttach(ss, SPI_SS_IDX(spi->num, cs_num), false, false);
|
||||
@ -208,6 +320,14 @@ void spiDetachSS(spi_t * spi, int8_t ss)
|
||||
return;
|
||||
}
|
||||
if(ss < 0) {
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
if(spi->num == FSPI) {
|
||||
ss = 34;
|
||||
} else {
|
||||
log_e("HSPI Does not have default pins on ESP32S2!");
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if(spi->num == HSPI) {
|
||||
ss = 15;
|
||||
} else if(spi->num == VSPI) {
|
||||
@ -215,6 +335,7 @@ void spiDetachSS(spi_t * spi, int8_t ss)
|
||||
} else {
|
||||
ss = 11;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
pinMatrixOutDetach(ss, false, false);
|
||||
pinMode(ss, INPUT);
|
||||
@ -226,7 +347,11 @@ void spiEnableSSPins(spi_t * spi, uint8_t cs_mask)
|
||||
return;
|
||||
}
|
||||
SPI_MUTEX_LOCK();
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
spi->dev->misc.val &= ~(cs_mask & SPI_CS_MASK_ALL);
|
||||
#else
|
||||
spi->dev->pin.val &= ~(cs_mask & SPI_CS_MASK_ALL);
|
||||
#endif
|
||||
SPI_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
@ -236,7 +361,11 @@ void spiDisableSSPins(spi_t * spi, uint8_t cs_mask)
|
||||
return;
|
||||
}
|
||||
SPI_MUTEX_LOCK();
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
spi->dev->misc.val |= (cs_mask & SPI_CS_MASK_ALL);
|
||||
#else
|
||||
spi->dev->pin.val |= (cs_mask & SPI_CS_MASK_ALL);
|
||||
#endif
|
||||
SPI_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
@ -268,7 +397,11 @@ void spiSSSet(spi_t * spi)
|
||||
return;
|
||||
}
|
||||
SPI_MUTEX_LOCK();
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
spi->dev->misc.cs_keep_active = 1;
|
||||
#else
|
||||
spi->dev->pin.cs_keep_active = 1;
|
||||
#endif
|
||||
SPI_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
@ -278,7 +411,11 @@ void spiSSClear(spi_t * spi)
|
||||
return;
|
||||
}
|
||||
SPI_MUTEX_LOCK();
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
spi->dev->misc.cs_keep_active = 0;
|
||||
#else
|
||||
spi->dev->pin.cs_keep_active = 0;
|
||||
#endif
|
||||
SPI_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
@ -305,7 +442,11 @@ uint8_t spiGetDataMode(spi_t * spi)
|
||||
if(!spi) {
|
||||
return 0;
|
||||
}
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
bool idleEdge = spi->dev->misc.ck_idle_edge;
|
||||
#else
|
||||
bool idleEdge = spi->dev->pin.ck_idle_edge;
|
||||
#endif
|
||||
bool outEdge = spi->dev->user.ck_out_edge;
|
||||
if(idleEdge) {
|
||||
if(outEdge) {
|
||||
@ -327,20 +468,36 @@ void spiSetDataMode(spi_t * spi, uint8_t dataMode)
|
||||
SPI_MUTEX_LOCK();
|
||||
switch (dataMode) {
|
||||
case SPI_MODE1:
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
spi->dev->misc.ck_idle_edge = 0;
|
||||
#else
|
||||
spi->dev->pin.ck_idle_edge = 0;
|
||||
#endif
|
||||
spi->dev->user.ck_out_edge = 1;
|
||||
break;
|
||||
case SPI_MODE2:
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
spi->dev->misc.ck_idle_edge = 1;
|
||||
#else
|
||||
spi->dev->pin.ck_idle_edge = 1;
|
||||
#endif
|
||||
spi->dev->user.ck_out_edge = 1;
|
||||
break;
|
||||
case SPI_MODE3:
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
spi->dev->misc.ck_idle_edge = 1;
|
||||
#else
|
||||
spi->dev->pin.ck_idle_edge = 1;
|
||||
#endif
|
||||
spi->dev->user.ck_out_edge = 0;
|
||||
break;
|
||||
case SPI_MODE0:
|
||||
default:
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
spi->dev->misc.ck_idle_edge = 0;
|
||||
#else
|
||||
spi->dev->pin.ck_idle_edge = 0;
|
||||
#endif
|
||||
spi->dev->user.ck_out_edge = 0;
|
||||
break;
|
||||
}
|
||||
@ -371,27 +528,51 @@ void spiSetBitOrder(spi_t * spi, uint8_t bitOrder)
|
||||
SPI_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
void spiStopBus(spi_t * spi)
|
||||
static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb)
|
||||
{
|
||||
if(!spi) {
|
||||
return;
|
||||
}
|
||||
spi_t * spi = (spi_t *)arg;
|
||||
if(ev_type == APB_BEFORE_CHANGE){
|
||||
SPI_MUTEX_LOCK();
|
||||
while(spi->dev->cmd.usr);
|
||||
} else {
|
||||
spi->dev->clock.val = spiFrequencyToClockDiv(old_apb / ((spi->dev->clock.clkdiv_pre + 1) * (spi->dev->clock.clkcnt_n + 1)));
|
||||
SPI_MUTEX_UNLOCK();
|
||||
}
|
||||
}
|
||||
|
||||
static void spiInitBus(spi_t * spi)
|
||||
{
|
||||
spi->dev->slave.trans_done = 0;
|
||||
spi->dev->slave.slave_mode = 0;
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
spi->dev->misc.val = 0;
|
||||
#else
|
||||
spi->dev->pin.val = 0;
|
||||
#endif
|
||||
spi->dev->user.val = 0;
|
||||
spi->dev->user1.val = 0;
|
||||
spi->dev->ctrl.val = 0;
|
||||
spi->dev->ctrl1.val = 0;
|
||||
spi->dev->ctrl2.val = 0;
|
||||
spi->dev->clock.val = 0;
|
||||
}
|
||||
|
||||
void spiStopBus(spi_t * spi)
|
||||
{
|
||||
if(!spi) {
|
||||
return;
|
||||
}
|
||||
|
||||
removeApbChangeCallback(spi, _on_apb_change);
|
||||
|
||||
SPI_MUTEX_LOCK();
|
||||
spiInitBus(spi);
|
||||
SPI_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_t bitOrder)
|
||||
{
|
||||
if(spi_num > 3){
|
||||
if(spi_num >= SPI_COUNT){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -406,23 +587,32 @@ spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_
|
||||
}
|
||||
#endif
|
||||
|
||||
if(spi_num == HSPI) {
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST);
|
||||
} else if(spi_num == VSPI) {
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_2);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_2);
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
if(spi_num == FSPI) {
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI2_CLK_EN);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI2_RST);
|
||||
} else if(spi_num == HSPI) {
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI3_CLK_EN);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI3_RST);
|
||||
} else {
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_1);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_1);
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI01_CLK_EN);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI01_RST);
|
||||
}
|
||||
|
||||
spiStopBus(spi);
|
||||
spiSetDataMode(spi, dataMode);
|
||||
spiSetBitOrder(spi, bitOrder);
|
||||
spiSetClockDiv(spi, clockDiv);
|
||||
#else
|
||||
if(spi_num == HSPI) {
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI2_CLK_EN);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI2_RST);
|
||||
} else if(spi_num == VSPI) {
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI3_CLK_EN);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI3_RST);
|
||||
} else {
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI01_CLK_EN);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI01_RST);
|
||||
}
|
||||
#endif
|
||||
|
||||
SPI_MUTEX_LOCK();
|
||||
spiInitBus(spi);
|
||||
spi->dev->user.usr_mosi = 1;
|
||||
spi->dev->user.usr_miso = 1;
|
||||
spi->dev->user.doutdin = 1;
|
||||
@ -433,6 +623,11 @@ spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_
|
||||
}
|
||||
SPI_MUTEX_UNLOCK();
|
||||
|
||||
spiSetDataMode(spi, dataMode);
|
||||
spiSetBitOrder(spi, bitOrder);
|
||||
spiSetClockDiv(spi, clockDiv);
|
||||
|
||||
addApbChangeCallback(spi, _on_apb_change);
|
||||
return spi;
|
||||
}
|
||||
|
||||
@ -444,7 +639,12 @@ void spiWaitReady(spi_t * spi)
|
||||
while(spi->dev->cmd.usr);
|
||||
}
|
||||
|
||||
void spiWrite(spi_t * spi, uint32_t *data, uint8_t len)
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
#define usr_mosi_dbitlen usr_mosi_bit_len
|
||||
#define usr_miso_dbitlen usr_miso_bit_len
|
||||
#endif
|
||||
|
||||
void spiWrite(spi_t * spi, const uint32_t *data, uint8_t len)
|
||||
{
|
||||
if(!spi) {
|
||||
return;
|
||||
@ -517,17 +717,7 @@ uint8_t spiTransferByte(spi_t * spi, uint8_t data)
|
||||
return data;
|
||||
}
|
||||
|
||||
uint32_t __spiTranslate24(uint32_t data)
|
||||
{
|
||||
union {
|
||||
uint32_t l;
|
||||
uint8_t b[4];
|
||||
} out;
|
||||
out.l = data;
|
||||
return out.b[2] | (out.b[1] << 8) | (out.b[0] << 16);
|
||||
}
|
||||
|
||||
uint32_t __spiTranslate32(uint32_t data)
|
||||
static uint32_t __spiTranslate32(uint32_t data)
|
||||
{
|
||||
union {
|
||||
uint32_t l;
|
||||
@ -615,7 +805,7 @@ uint32_t spiTransferLong(spi_t * spi, uint32_t data)
|
||||
return data;
|
||||
}
|
||||
|
||||
void __spiTransferBytes(spi_t * spi, uint8_t * data, uint8_t * out, uint32_t bytes)
|
||||
static void __spiTransferBytes(spi_t * spi, const uint8_t * data, uint8_t * out, uint32_t bytes)
|
||||
{
|
||||
if(!spi) {
|
||||
return;
|
||||
@ -656,7 +846,7 @@ void __spiTransferBytes(spi_t * spi, uint8_t * data, uint8_t * out, uint32_t byt
|
||||
}
|
||||
}
|
||||
|
||||
void spiTransferBytes(spi_t * spi, uint8_t * data, uint8_t * out, uint32_t size)
|
||||
void spiTransferBytes(spi_t * spi, const uint8_t * data, uint8_t * out, uint32_t size)
|
||||
{
|
||||
if(!spi) {
|
||||
return;
|
||||
@ -708,20 +898,36 @@ void spiTransaction(spi_t * spi, uint32_t clockDiv, uint8_t dataMode, uint8_t bi
|
||||
spi->dev->clock.val = clockDiv;
|
||||
switch (dataMode) {
|
||||
case SPI_MODE1:
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
spi->dev->misc.ck_idle_edge = 0;
|
||||
#else
|
||||
spi->dev->pin.ck_idle_edge = 0;
|
||||
#endif
|
||||
spi->dev->user.ck_out_edge = 1;
|
||||
break;
|
||||
case SPI_MODE2:
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
spi->dev->misc.ck_idle_edge = 1;
|
||||
#else
|
||||
spi->dev->pin.ck_idle_edge = 1;
|
||||
#endif
|
||||
spi->dev->user.ck_out_edge = 1;
|
||||
break;
|
||||
case SPI_MODE3:
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
spi->dev->misc.ck_idle_edge = 1;
|
||||
#else
|
||||
spi->dev->pin.ck_idle_edge = 1;
|
||||
#endif
|
||||
spi->dev->user.ck_out_edge = 0;
|
||||
break;
|
||||
case SPI_MODE0:
|
||||
default:
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
spi->dev->misc.ck_idle_edge = 0;
|
||||
#else
|
||||
spi->dev->pin.ck_idle_edge = 0;
|
||||
#endif
|
||||
spi->dev->user.ck_out_edge = 0;
|
||||
break;
|
||||
}
|
||||
@ -750,7 +956,7 @@ void spiEndTransaction(spi_t * spi)
|
||||
SPI_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
void spiWriteByteNL(spi_t * spi, uint8_t data)
|
||||
void ARDUINO_ISR_ATTR spiWriteByteNL(spi_t * spi, uint8_t data)
|
||||
{
|
||||
if(!spi) {
|
||||
return;
|
||||
@ -776,7 +982,7 @@ uint8_t spiTransferByteNL(spi_t * spi, uint8_t data)
|
||||
return data;
|
||||
}
|
||||
|
||||
void spiWriteShortNL(spi_t * spi, uint16_t data)
|
||||
void ARDUINO_ISR_ATTR spiWriteShortNL(spi_t * spi, uint16_t data)
|
||||
{
|
||||
if(!spi) {
|
||||
return;
|
||||
@ -811,7 +1017,7 @@ uint16_t spiTransferShortNL(spi_t * spi, uint16_t data)
|
||||
return data;
|
||||
}
|
||||
|
||||
void spiWriteLongNL(spi_t * spi, uint32_t data)
|
||||
void ARDUINO_ISR_ATTR spiWriteLongNL(spi_t * spi, uint32_t data)
|
||||
{
|
||||
if(!spi) {
|
||||
return;
|
||||
@ -846,7 +1052,7 @@ uint32_t spiTransferLongNL(spi_t * spi, uint32_t data)
|
||||
return data;
|
||||
}
|
||||
|
||||
void spiWriteNL(spi_t * spi, const void * data_in, size_t len){
|
||||
void spiWriteNL(spi_t * spi, const void * data_in, uint32_t len){
|
||||
size_t longs = len >> 2;
|
||||
if(len & 3){
|
||||
longs++;
|
||||
@ -872,7 +1078,7 @@ void spiWriteNL(spi_t * spi, const void * data_in, size_t len){
|
||||
}
|
||||
}
|
||||
|
||||
void spiTransferBytesNL(spi_t * spi, const void * data_in, uint8_t * data_out, size_t len){
|
||||
void spiTransferBytesNL(spi_t * spi, const void * data_in, uint8_t * data_out, uint32_t len){
|
||||
if(!spi) {
|
||||
return;
|
||||
}
|
||||
@ -959,7 +1165,7 @@ void spiTransferBitsNL(spi_t * spi, uint32_t data, uint32_t * out, uint8_t bits)
|
||||
}
|
||||
}
|
||||
|
||||
void spiWritePixelsNL(spi_t * spi, const void * data_in, size_t len){
|
||||
void ARDUINO_ISR_ATTR spiWritePixelsNL(spi_t * spi, const void * data_in, uint32_t len){
|
||||
size_t longs = len >> 2;
|
||||
if(len & 3){
|
||||
longs++;
|
||||
@ -1007,35 +1213,37 @@ void spiWritePixelsNL(spi_t * spi, const void * data_in, size_t len){
|
||||
* */
|
||||
|
||||
typedef union {
|
||||
uint32_t regValue;
|
||||
uint32_t value;
|
||||
struct {
|
||||
unsigned regL :6;
|
||||
unsigned regH :6;
|
||||
unsigned regN :6;
|
||||
unsigned regPre :13;
|
||||
unsigned regEQU :1;
|
||||
uint32_t clkcnt_l: 6; /*it must be equal to spi_clkcnt_N.*/
|
||||
uint32_t clkcnt_h: 6; /*it must be floor((spi_clkcnt_N+1)/2-1).*/
|
||||
uint32_t clkcnt_n: 6; /*it is the divider of spi_clk. So spi_clk frequency is system/(spi_clkdiv_pre+1)/(spi_clkcnt_N+1)*/
|
||||
uint32_t clkdiv_pre: 13; /*it is pre-divider of spi_clk.*/
|
||||
uint32_t clk_equ_sysclk: 1; /*1: spi_clk is eqaul to system 0: spi_clk is divided from system clock.*/
|
||||
};
|
||||
} spiClk_t;
|
||||
|
||||
#define ClkRegToFreq(reg) (CPU_CLK_FREQ / (((reg)->regPre + 1) * ((reg)->regN + 1)))
|
||||
#define ClkRegToFreq(reg) (apb_freq / (((reg)->clkdiv_pre + 1) * ((reg)->clkcnt_n + 1)))
|
||||
|
||||
uint32_t spiClockDivToFrequency(uint32_t clockDiv)
|
||||
{
|
||||
uint32_t apb_freq = getApbFrequency();
|
||||
spiClk_t reg = { clockDiv };
|
||||
return ClkRegToFreq(®);
|
||||
}
|
||||
|
||||
uint32_t spiFrequencyToClockDiv(uint32_t freq)
|
||||
{
|
||||
uint32_t apb_freq = getApbFrequency();
|
||||
|
||||
if(freq >= CPU_CLK_FREQ) {
|
||||
if(freq >= apb_freq) {
|
||||
return SPI_CLK_EQU_SYSCLK;
|
||||
}
|
||||
|
||||
const spiClk_t minFreqReg = { 0x7FFFF000 };
|
||||
uint32_t minFreq = ClkRegToFreq((spiClk_t*) &minFreqReg);
|
||||
if(freq < minFreq) {
|
||||
return minFreqReg.regValue;
|
||||
return minFreqReg.value;
|
||||
}
|
||||
|
||||
uint8_t calN = 1;
|
||||
@ -1048,18 +1256,18 @@ uint32_t spiFrequencyToClockDiv(uint32_t freq)
|
||||
int32_t calPre;
|
||||
int8_t calPreVari = -2;
|
||||
|
||||
reg.regN = calN;
|
||||
reg.clkcnt_n = calN;
|
||||
|
||||
while(calPreVari++ <= 1) {
|
||||
calPre = (((CPU_CLK_FREQ / (reg.regN + 1)) / freq) - 1) + calPreVari;
|
||||
calPre = (((apb_freq / (reg.clkcnt_n + 1)) / freq) - 1) + calPreVari;
|
||||
if(calPre > 0x1FFF) {
|
||||
reg.regPre = 0x1FFF;
|
||||
reg.clkdiv_pre = 0x1FFF;
|
||||
} else if(calPre <= 0) {
|
||||
reg.regPre = 0;
|
||||
reg.clkdiv_pre = 0;
|
||||
} else {
|
||||
reg.regPre = calPre;
|
||||
reg.clkdiv_pre = calPre;
|
||||
}
|
||||
reg.regL = ((reg.regN + 1) / 2);
|
||||
reg.clkcnt_l = ((reg.clkcnt_n + 1) / 2);
|
||||
calFreq = ClkRegToFreq(®);
|
||||
if(calFreq == (int32_t) freq) {
|
||||
memcpy(&bestReg, ®, sizeof(bestReg));
|
||||
@ -1076,6 +1284,6 @@ uint32_t spiFrequencyToClockDiv(uint32_t freq)
|
||||
}
|
||||
calN++;
|
||||
}
|
||||
return bestReg.regValue;
|
||||
return bestReg.value;
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
@ -26,7 +27,9 @@ extern "C" {
|
||||
|
||||
#define FSPI 1 //SPI bus attached to the flash (can use the same data lines but different SS)
|
||||
#define HSPI 2 //SPI bus normally mapped to pins 12 - 15, but can be matrixed to any pins
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define VSPI 3 //SPI bus normally attached to pins 5, 18, 19 and 23, but can be matrixed to any pins
|
||||
#endif
|
||||
|
||||
// This defines are not representing the real Divider of the ESP32
|
||||
// the Defines match to an AVR Arduino on 16MHz for better compatibility
|
||||
@ -96,7 +99,7 @@ void spiSetClockDiv(spi_t * spi, uint32_t clockDiv);
|
||||
void spiSetDataMode(spi_t * spi, uint8_t dataMode);
|
||||
void spiSetBitOrder(spi_t * spi, uint8_t bitOrder);
|
||||
|
||||
void spiWrite(spi_t * spi, uint32_t *data, uint8_t len);
|
||||
void spiWrite(spi_t * spi, const uint32_t *data, uint8_t len);
|
||||
void spiWriteByte(spi_t * spi, uint8_t data);
|
||||
void spiWriteWord(spi_t * spi, uint16_t data);
|
||||
void spiWriteLong(spi_t * spi, uint32_t data);
|
||||
@ -105,7 +108,7 @@ void spiTransfer(spi_t * spi, uint32_t *out, uint8_t len);
|
||||
uint8_t spiTransferByte(spi_t * spi, uint8_t data);
|
||||
uint16_t spiTransferWord(spi_t * spi, uint16_t data);
|
||||
uint32_t spiTransferLong(spi_t * spi, uint32_t data);
|
||||
void spiTransferBytes(spi_t * spi, uint8_t * data, uint8_t * out, uint32_t size);
|
||||
void spiTransferBytes(spi_t * spi, const uint8_t * data, uint8_t * out, uint32_t size);
|
||||
void spiTransferBits(spi_t * spi, uint32_t data, uint32_t * out, uint8_t bits);
|
||||
|
||||
/*
|
||||
@ -115,11 +118,11 @@ void spiTransaction(spi_t * spi, uint32_t clockDiv, uint8_t dataMode, uint8_t bi
|
||||
void spiSimpleTransaction(spi_t * spi);
|
||||
void spiEndTransaction(spi_t * spi);
|
||||
|
||||
void spiWriteNL(spi_t * spi, const void * data, uint32_t len);
|
||||
void spiWriteNL(spi_t * spi, const void * data_in, uint32_t len);
|
||||
void spiWriteByteNL(spi_t * spi, uint8_t data);
|
||||
void spiWriteShortNL(spi_t * spi, uint16_t data);
|
||||
void spiWriteLongNL(spi_t * spi, uint32_t data);
|
||||
void spiWritePixelsNL(spi_t * spi, const void * data, uint32_t len);
|
||||
void spiWritePixelsNL(spi_t * spi, const void * data_in, uint32_t len);
|
||||
|
||||
#define spiTransferNL(spi, data, len) spiTransferBytesNL(spi, data, data, len)
|
||||
uint8_t spiTransferByteNL(spi_t * spi, uint8_t data);
|
||||
|
@ -13,13 +13,15 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include "esp32-hal.h"
|
||||
#include "apps/sntp/sntp.h"
|
||||
#include "lwip/apps/sntp.h"
|
||||
//#include "tcpip_adapter.h"
|
||||
#include "esp_netif.h"
|
||||
|
||||
static void setTimeZone(long offset, int daylight)
|
||||
{
|
||||
char cst[16] = {0};
|
||||
char cdt[16] = "DST";
|
||||
char tz[32] = {0};
|
||||
char cst[17] = {0};
|
||||
char cdt[17] = "DST";
|
||||
char tz[33] = {0};
|
||||
|
||||
if(offset % 3600){
|
||||
sprintf(cst, "UTC%ld:%02u:%02u", offset / 3600, abs((offset % 3600) / 60), abs(offset % 60));
|
||||
@ -45,6 +47,8 @@ static void setTimeZone(long offset, int daylight)
|
||||
* */
|
||||
void configTime(long gmtOffset_sec, int daylightOffset_sec, const char* server1, const char* server2, const char* server3)
|
||||
{
|
||||
//tcpip_adapter_init(); // Should not hurt anything if already inited
|
||||
esp_netif_init();
|
||||
if(sntp_enabled()){
|
||||
sntp_stop();
|
||||
}
|
||||
@ -62,6 +66,8 @@ void configTime(long gmtOffset_sec, int daylightOffset_sec, const char* server1,
|
||||
* */
|
||||
void configTzTime(const char* tz, const char* server1, const char* server2, const char* server3)
|
||||
{
|
||||
//tcpip_adapter_init(); // Should not hurt anything if already inited
|
||||
esp_netif_init();
|
||||
if(sntp_enabled()){
|
||||
sntp_stop();
|
||||
}
|
||||
@ -76,23 +82,15 @@ void configTzTime(const char* tz, const char* server1, const char* server2, cons
|
||||
|
||||
bool getLocalTime(struct tm * info, uint32_t ms)
|
||||
{
|
||||
uint32_t count = ms / 10;
|
||||
uint32_t start = millis();
|
||||
time_t now;
|
||||
|
||||
while((millis()-start) <= ms) {
|
||||
time(&now);
|
||||
localtime_r(&now, info);
|
||||
|
||||
if(info->tm_year > (2016 - 1900)){
|
||||
return true;
|
||||
}
|
||||
|
||||
while(count--) {
|
||||
delay(10);
|
||||
time(&now);
|
||||
localtime_r(&now, info);
|
||||
if(info->tm_year > (2016 - 1900)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -16,11 +16,27 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "freertos/task.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "soc/timer_group_struct.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "esp_attr.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/ets_sys.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_intr.h"
|
||||
#endif
|
||||
|
||||
#define HWTIMER_LOCK() portENTER_CRITICAL(timer->lock)
|
||||
#define HWTIMER_UNLOCK() portEXIT_CRITICAL(timer->lock)
|
||||
@ -67,11 +83,18 @@ static hw_timer_t hw_timer[4] = {
|
||||
typedef void (*voidFuncPtr)(void);
|
||||
static voidFuncPtr __timerInterruptHandlers[4] = {0,0,0,0};
|
||||
|
||||
void IRAM_ATTR __timerISR(void * arg){
|
||||
void ARDUINO_ISR_ATTR __timerISR(void * arg){
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
uint32_t s0 = TIMERG0.int_st_timers.val;
|
||||
uint32_t s1 = TIMERG1.int_st_timers.val;
|
||||
TIMERG0.int_clr_timers.val = s0;
|
||||
TIMERG1.int_clr_timers.val = s1;
|
||||
#else
|
||||
uint32_t s0 = TIMERG0.int_st.val;
|
||||
uint32_t s1 = TIMERG1.int_st.val;
|
||||
TIMERG0.int_clr.val = s0;
|
||||
TIMERG1.int_clr.val = s1;
|
||||
#endif
|
||||
uint8_t status = (s1 & 3) << 2 | (s0 & 3);
|
||||
uint8_t i = 4;
|
||||
//restart the timers that should autoreload
|
||||
@ -84,7 +107,7 @@ void IRAM_ATTR __timerISR(void * arg){
|
||||
i = 4;
|
||||
//call callbacks
|
||||
while(i--){
|
||||
if(__timerInterruptHandlers[i] && status & (1 << i)){
|
||||
if(__timerInterruptHandlers[i] && (status & (1 << i))){
|
||||
__timerInterruptHandlers[i]();
|
||||
}
|
||||
}
|
||||
@ -165,6 +188,7 @@ void timerStop(hw_timer_t *timer){
|
||||
|
||||
void timerRestart(hw_timer_t *timer){
|
||||
timer->dev->config.enable = 0;
|
||||
timer->dev->reload = 1;
|
||||
timer->dev->config.enable = 1;
|
||||
}
|
||||
|
||||
@ -184,36 +208,67 @@ bool timerAlarmEnabled(hw_timer_t *timer){
|
||||
return timer->dev->config.alarm_en;
|
||||
}
|
||||
|
||||
static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){
|
||||
hw_timer_t * timer = (hw_timer_t *)arg;
|
||||
if(ev_type == APB_BEFORE_CHANGE){
|
||||
timer->dev->config.enable = 0;
|
||||
} else {
|
||||
old_apb /= 1000000;
|
||||
new_apb /= 1000000;
|
||||
timer->dev->config.divider = (new_apb * timer->dev->config.divider) / old_apb;
|
||||
timer->dev->config.enable = 1;
|
||||
}
|
||||
}
|
||||
|
||||
hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){
|
||||
if(num > 3){
|
||||
return NULL;
|
||||
}
|
||||
hw_timer_t * timer = &hw_timer[num];
|
||||
if(timer->group) {
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP1_CLK_EN);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP1_RST);
|
||||
TIMERG1.int_ena.val &= ~BIT(timer->timer);
|
||||
periph_module_enable(PERIPH_TIMG1_MODULE);
|
||||
} else {
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP_CLK_EN);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP_RST);
|
||||
TIMERG0.int_ena.val &= ~BIT(timer->timer);
|
||||
periph_module_enable(PERIPH_TIMG0_MODULE);
|
||||
}
|
||||
timer->dev->config.enable = 0;
|
||||
if(timer->group) {
|
||||
TIMERG1.int_ena.val &= ~BIT(timer->timer);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
TIMERG1.int_clr_timers.val |= BIT(timer->timer);
|
||||
#else
|
||||
TIMERG1.int_clr.val = BIT(timer->timer);
|
||||
#endif
|
||||
} else {
|
||||
TIMERG0.int_ena.val &= ~BIT(timer->timer);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
TIMERG0.int_clr_timers.val |= BIT(timer->timer);
|
||||
#else
|
||||
TIMERG0.int_clr.val = BIT(timer->timer);
|
||||
#endif
|
||||
}
|
||||
#ifdef TIMER_GROUP_SUPPORTS_XTAL_CLOCK
|
||||
timer->dev->config.use_xtal = 0;
|
||||
#endif
|
||||
timerSetDivider(timer, divider);
|
||||
timerSetCountUp(timer, countUp);
|
||||
timerSetAutoReload(timer, false);
|
||||
timerAttachInterrupt(timer, NULL, false);
|
||||
timerWrite(timer, 0);
|
||||
timer->dev->config.enable = 1;
|
||||
addApbChangeCallback(timer, _on_apb_change);
|
||||
return timer;
|
||||
}
|
||||
|
||||
void timerEnd(hw_timer_t *timer){
|
||||
timer->dev->config.enable = 0;
|
||||
timerAttachInterrupt(timer, NULL, false);
|
||||
removeApbChangeCallback(timer, _on_apb_change);
|
||||
}
|
||||
|
||||
void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){
|
||||
// EDGE DOES NOT WORK CURRENTLY
|
||||
edge = false;
|
||||
|
||||
static bool initialized = false;
|
||||
static intr_handle_t intr_handle = NULL;
|
||||
if(intr_handle){
|
||||
@ -225,8 +280,18 @@ void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){
|
||||
timer->dev->config.alarm_en = 0;
|
||||
if(timer->num & 2){
|
||||
TIMERG1.int_ena.val &= ~BIT(timer->timer);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
TIMERG1.int_clr_timers.val |= BIT(timer->timer);
|
||||
#else
|
||||
TIMERG1.int_clr.val = BIT(timer->timer);
|
||||
#endif
|
||||
} else {
|
||||
TIMERG0.int_ena.val &= ~BIT(timer->timer);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
TIMERG0.int_clr_timers.val |= BIT(timer->timer);
|
||||
#else
|
||||
TIMERG0.int_clr.val = BIT(timer->timer);
|
||||
#endif
|
||||
}
|
||||
__timerInterruptHandlers[timer->num] = NULL;
|
||||
} else {
|
||||
@ -249,7 +314,7 @@ void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){
|
||||
}
|
||||
if(!initialized){
|
||||
initialized = true;
|
||||
esp_intr_alloc(intr_source, (int)(ESP_INTR_FLAG_IRAM|ESP_INTR_FLAG_LOWMED|ESP_INTR_FLAG_EDGE), __timerISR, NULL, &intr_handle);
|
||||
esp_intr_alloc(intr_source, (int)(ARDUINO_ISR_FLAG|ESP_INTR_FLAG_LOWMED), __timerISR, NULL, &intr_handle);
|
||||
} else {
|
||||
intr_matrix_set(esp_intr_get_cpu(intr_handle), intr_source, esp_intr_get_intno(intr_handle));
|
||||
}
|
||||
@ -271,23 +336,23 @@ void timerDetachInterrupt(hw_timer_t *timer){
|
||||
uint64_t timerReadMicros(hw_timer_t *timer){
|
||||
uint64_t timer_val = timerRead(timer);
|
||||
uint16_t div = timerGetDivider(timer);
|
||||
return timer_val * div / 80;
|
||||
return timer_val * div / (getApbFrequency() / 1000000);
|
||||
}
|
||||
|
||||
double timerReadSeconds(hw_timer_t *timer){
|
||||
uint64_t timer_val = timerRead(timer);
|
||||
uint16_t div = timerGetDivider(timer);
|
||||
return (double)timer_val * div / 80000000;
|
||||
return (double)timer_val * div / getApbFrequency();
|
||||
}
|
||||
|
||||
uint64_t timerAlarmReadMicros(hw_timer_t *timer){
|
||||
uint64_t timer_val = timerAlarmRead(timer);
|
||||
uint16_t div = timerGetDivider(timer);
|
||||
return timer_val * div / 80;
|
||||
return timer_val * div / (getApbFrequency() / 1000000);
|
||||
}
|
||||
|
||||
double timerAlarmReadSeconds(hw_timer_t *timer){
|
||||
uint64_t timer_val = timerAlarmRead(timer);
|
||||
uint16_t div = timerGetDivider(timer);
|
||||
return (double)timer_val * div / 80000000;
|
||||
return (double)timer_val * div / getApbFrequency();
|
||||
}
|
||||
|
702
cores/esp32/esp32-hal-tinyusb.c
Normal file
702
cores/esp32/esp32-hal-tinyusb.c
Normal file
@ -0,0 +1,702 @@
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#if CONFIG_USB_ENABLED
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "soc/soc.h"
|
||||
#include "soc/efuse_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/usb_struct.h"
|
||||
#include "soc/usb_reg.h"
|
||||
#include "soc/usb_wrap_reg.h"
|
||||
#include "soc/usb_wrap_struct.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#include "soc/timer_group_struct.h"
|
||||
#include "soc/system_reg.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
|
||||
#include "tinyusb.h"
|
||||
#include "esp32-hal.h"
|
||||
|
||||
#include "esp32-hal-tinyusb.h"
|
||||
#include "esp32s2/rom/usb/usb_persist.h"
|
||||
|
||||
typedef char tusb_str_t[127];
|
||||
|
||||
static bool WEBUSB_ENABLED = false;
|
||||
|
||||
static tusb_str_t WEBUSB_URL = "";
|
||||
static tusb_str_t USB_DEVICE_PRODUCT = "";
|
||||
static tusb_str_t USB_DEVICE_MANUFACTURER = "";
|
||||
static tusb_str_t USB_DEVICE_SERIAL = "";
|
||||
|
||||
static uint8_t USB_DEVICE_ATTRIBUTES = 0;
|
||||
static uint16_t USB_DEVICE_POWER = 0;
|
||||
|
||||
/*
|
||||
* Device Descriptor
|
||||
* */
|
||||
static tusb_desc_device_t tinyusb_device_descriptor = {
|
||||
.bLength = sizeof(tusb_desc_device_t),
|
||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||
.bcdUSB = 0,
|
||||
.bDeviceClass = 0,
|
||||
.bDeviceSubClass = 0,
|
||||
.bDeviceProtocol = 0,
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDOINT0_SIZE,
|
||||
|
||||
.idVendor = 0,
|
||||
.idProduct = 0,
|
||||
.bcdDevice = 0,
|
||||
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
/*
|
||||
* String Descriptors
|
||||
* */
|
||||
#define MAX_STRING_DESCRIPTORS 20
|
||||
static uint32_t tinyusb_string_descriptor_len = 4;
|
||||
static char * tinyusb_string_descriptor[MAX_STRING_DESCRIPTORS] = {
|
||||
// array of pointer to string descriptors
|
||||
"\x09\x04", // 0: is supported language is English (0x0409)
|
||||
USB_DEVICE_MANUFACTURER,// 1: Manufacturer
|
||||
USB_DEVICE_PRODUCT, // 2: Product
|
||||
USB_DEVICE_SERIAL, // 3: Serials, should use chip ID
|
||||
};
|
||||
|
||||
|
||||
/* Microsoft OS 2.0 registry property descriptor
|
||||
Per MS requirements https://msdn.microsoft.com/en-us/library/windows/hardware/hh450799(v=vs.85).aspx
|
||||
device should create DeviceInterfaceGUIDs. It can be done by driver and
|
||||
in case of real PnP solution device should expose MS "Microsoft OS 2.0
|
||||
registry property descriptor". Such descriptor can insert any record
|
||||
into Windows registry per device/configuration/interface. In our case it
|
||||
will insert "DeviceInterfaceGUIDs" multistring property.
|
||||
|
||||
GUID is freshly generated and should be OK to use.
|
||||
|
||||
https://developers.google.com/web/fundamentals/native-hardware/build-for-webusb/
|
||||
(Section Microsoft OS compatibility descriptors)
|
||||
*/
|
||||
|
||||
#define MS_OS_20_DESC_LEN 0xB2
|
||||
|
||||
static uint8_t const tinyusb_ms_os_20_descriptor[] =
|
||||
{
|
||||
// Set header: length, type, windows version, total length
|
||||
U16_TO_U8S_LE(0x000A), U16_TO_U8S_LE(MS_OS_20_SET_HEADER_DESCRIPTOR), U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(MS_OS_20_DESC_LEN),
|
||||
|
||||
// Configuration subset header: length, type, configuration index, reserved, configuration total length
|
||||
U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_CONFIGURATION), 0, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A),
|
||||
|
||||
// Function Subset header: length, type, first interface, reserved, subset length
|
||||
U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_FUNCTION), 0, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08),
|
||||
|
||||
// MS OS 2.0 Compatible ID descriptor: length, type, compatible ID, sub compatible ID
|
||||
U16_TO_U8S_LE(0x0014), U16_TO_U8S_LE(MS_OS_20_FEATURE_COMPATBLE_ID), 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sub-compatible
|
||||
|
||||
// MS OS 2.0 Registry property descriptor: length, type
|
||||
U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08-0x08-0x14), U16_TO_U8S_LE(MS_OS_20_FEATURE_REG_PROPERTY),
|
||||
U16_TO_U8S_LE(0x0007), U16_TO_U8S_LE(0x002A), // wPropertyDataType, wPropertyNameLength and PropertyName "DeviceInterfaceGUIDs\0" in UTF-16
|
||||
'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00,
|
||||
'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00, 0x00, 0x00,
|
||||
U16_TO_U8S_LE(0x0050), // wPropertyDataLength
|
||||
//bPropertyData: “{975F44D9-0D08-43FD-8B3E-127CA8AFFF9D}”.
|
||||
'{', 0x00, '9', 0x00, '7', 0x00, '5', 0x00, 'F', 0x00, '4', 0x00, '4', 0x00, 'D', 0x00, '9', 0x00, '-', 0x00,
|
||||
'0', 0x00, 'D', 0x00, '0', 0x00, '8', 0x00, '-', 0x00, '4', 0x00, '3', 0x00, 'F', 0x00, 'D', 0x00, '-', 0x00,
|
||||
'8', 0x00, 'B', 0x00, '3', 0x00, 'E', 0x00, '-', 0x00, '1', 0x00, '2', 0x00, '7', 0x00, 'C', 0x00, 'A', 0x00,
|
||||
'8', 0x00, 'A', 0x00, 'F', 0x00, 'F', 0x00, 'F', 0x00, '9', 0x00, 'D', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
TU_VERIFY_STATIC(sizeof(tinyusb_ms_os_20_descriptor) == MS_OS_20_DESC_LEN, "Incorrect size");
|
||||
|
||||
|
||||
/*
|
||||
* BOS Descriptor (required for webUSB)
|
||||
* */
|
||||
#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN + TUD_BOS_WEBUSB_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN)
|
||||
|
||||
enum {
|
||||
VENDOR_REQUEST_WEBUSB = 1,
|
||||
VENDOR_REQUEST_MICROSOFT = 2
|
||||
};
|
||||
|
||||
static uint8_t const tinyusb_bos_descriptor[] = {
|
||||
// total length, number of device caps
|
||||
TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2),
|
||||
|
||||
// Vendor Code, iLandingPage
|
||||
TUD_BOS_WEBUSB_DESCRIPTOR(VENDOR_REQUEST_WEBUSB, 1),
|
||||
|
||||
// Microsoft OS 2.0 descriptor
|
||||
TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, VENDOR_REQUEST_MICROSOFT)
|
||||
};
|
||||
|
||||
/*
|
||||
* URL Descriptor (required for webUSB)
|
||||
* */
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bScheme;
|
||||
char url[127];
|
||||
} tinyusb_desc_webusb_url_t;
|
||||
|
||||
static tinyusb_desc_webusb_url_t tinyusb_url_descriptor = {
|
||||
.bLength = 3,
|
||||
.bDescriptorType = 3, // WEBUSB URL type
|
||||
.bScheme = 1, // URL Scheme Prefix: 0: "http://", 1: "https://", 255: ""
|
||||
.url = ""
|
||||
};
|
||||
|
||||
/*
|
||||
* Configuration Descriptor
|
||||
* */
|
||||
|
||||
static tinyusb_descriptor_cb_t tinyusb_loaded_interfaces_callbacks[USB_INTERFACE_MAX];
|
||||
static uint32_t tinyusb_loaded_interfaces_mask = 0;
|
||||
static uint8_t tinyusb_loaded_interfaces_num = 0;
|
||||
static uint16_t tinyusb_config_descriptor_len = 0;
|
||||
static uint8_t * tinyusb_config_descriptor = NULL;
|
||||
|
||||
/*
|
||||
* Endpoint Usage Tracking
|
||||
* */
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t in:16;
|
||||
uint32_t out:16;
|
||||
};
|
||||
uint32_t val;
|
||||
} tinyusb_endpoints_usage_t;
|
||||
|
||||
static tinyusb_endpoints_usage_t tinyusb_endpoints;
|
||||
|
||||
|
||||
/*
|
||||
* TinyUSB Callbacks
|
||||
* */
|
||||
|
||||
/**
|
||||
* @brief Invoked when received GET CONFIGURATION DESCRIPTOR.
|
||||
*/
|
||||
uint8_t const *tud_descriptor_configuration_cb(uint8_t index)
|
||||
{
|
||||
//log_d("%u", index);
|
||||
return tinyusb_config_descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Invoked when received GET DEVICE DESCRIPTOR.
|
||||
*/
|
||||
uint8_t const *tud_descriptor_device_cb(void)
|
||||
{
|
||||
//log_d("");
|
||||
return (uint8_t const *)&tinyusb_device_descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Invoked when received GET STRING DESCRIPTOR request.
|
||||
*/
|
||||
uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid)
|
||||
{
|
||||
//log_d("%u (0x%x)", index, langid);
|
||||
static uint16_t _desc_str[127];
|
||||
uint8_t chr_count;
|
||||
|
||||
if (index == 0) {
|
||||
memcpy(&_desc_str[1], tinyusb_string_descriptor[0], 2);
|
||||
chr_count = 1;
|
||||
} else {
|
||||
// Convert ASCII string into UTF-16
|
||||
if (index >= tinyusb_string_descriptor_len) {
|
||||
return NULL;
|
||||
}
|
||||
const char *str = tinyusb_string_descriptor[index];
|
||||
// Cap at max char
|
||||
chr_count = strlen(str);
|
||||
if (chr_count > 126) {
|
||||
chr_count = 126;
|
||||
}
|
||||
for (uint8_t i = 0; i < chr_count; i++) {
|
||||
_desc_str[1 + i] = str[i];
|
||||
}
|
||||
}
|
||||
|
||||
// first byte is len, second byte is string type
|
||||
_desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);
|
||||
|
||||
return _desc_str;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Invoked when received GET BOS DESCRIPTOR request.
|
||||
*/
|
||||
uint8_t const * tud_descriptor_bos_cb(void)
|
||||
{
|
||||
//log_d("");
|
||||
return tinyusb_bos_descriptor;
|
||||
}
|
||||
|
||||
__attribute__ ((weak)) bool tinyusb_vendor_control_request_cb(uint8_t rhport, tusb_control_request_t const * request){ return false; }
|
||||
__attribute__ ((weak)) bool tinyusb_vendor_control_complete_cb(uint8_t rhport, tusb_control_request_t const * request){ return true; }
|
||||
|
||||
/**
|
||||
* @brief Handle WebUSB and Vendor requests.
|
||||
*/
|
||||
bool tud_vendor_control_request_cb(uint8_t rhport, tusb_control_request_t const * request)
|
||||
{
|
||||
if(WEBUSB_ENABLED && (request->bRequest == VENDOR_REQUEST_WEBUSB
|
||||
|| (request->bRequest == VENDOR_REQUEST_MICROSOFT && request->wIndex == 7))){
|
||||
if(request->bRequest == VENDOR_REQUEST_WEBUSB){
|
||||
// match vendor request in BOS descriptor
|
||||
// Get landing page url
|
||||
tinyusb_url_descriptor.bLength = 3 + strlen(WEBUSB_URL);
|
||||
snprintf(tinyusb_url_descriptor.url, 127, "%s", WEBUSB_URL);
|
||||
return tud_control_xfer(rhport, request, (void*) &tinyusb_url_descriptor, tinyusb_url_descriptor.bLength);
|
||||
}
|
||||
// Get Microsoft OS 2.0 compatible descriptor
|
||||
uint16_t total_len;
|
||||
memcpy(&total_len, tinyusb_ms_os_20_descriptor + 8, 2);
|
||||
return tud_control_xfer(rhport, request, (void*) tinyusb_ms_os_20_descriptor, total_len);
|
||||
}
|
||||
return tinyusb_vendor_control_request_cb(rhport, request);
|
||||
}
|
||||
|
||||
bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_request_t const * request)
|
||||
{
|
||||
if(!WEBUSB_ENABLED || !(request->bRequest == VENDOR_REQUEST_WEBUSB
|
||||
|| (request->bRequest == VENDOR_REQUEST_MICROSOFT && request->wIndex == 7))){
|
||||
return tinyusb_vendor_control_complete_cb(rhport, request);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Required Callbacks
|
||||
* */
|
||||
#if CFG_TUD_HID
|
||||
__attribute__ ((weak)) const uint8_t * tud_hid_descriptor_report_cb(void){return NULL;}
|
||||
__attribute__ ((weak)) uint16_t tud_hid_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen){return 0;}
|
||||
__attribute__ ((weak)) void tud_hid_set_report_cb(uint8_t report_id, hid_report_type_t report_type, const uint8_t * buffer, uint16_t bufsize){}
|
||||
#endif
|
||||
#if CFG_TUD_MSC
|
||||
__attribute__ ((weak)) bool tud_msc_test_unit_ready_cb(uint8_t lun){return false;}
|
||||
__attribute__ ((weak)) void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]){}
|
||||
__attribute__ ((weak)) void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size){}
|
||||
__attribute__ ((weak)) int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize){return -1;}
|
||||
__attribute__ ((weak)) int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize){return -1;}
|
||||
__attribute__ ((weak)) int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize){return -1;}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Private API
|
||||
* */
|
||||
static bool usb_persist_enabled = false;
|
||||
static restart_type_t usb_persist_mode = RESTART_NO_PERSIST;
|
||||
|
||||
static bool tinyusb_reserve_in_endpoint(uint8_t endpoint){
|
||||
if(endpoint > 6 || (tinyusb_endpoints.in & BIT(endpoint)) != 0){
|
||||
return false;
|
||||
}
|
||||
tinyusb_endpoints.in |= BIT(endpoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool tinyusb_reserve_out_endpoint(uint8_t endpoint){
|
||||
if(endpoint > 6 || (tinyusb_endpoints.out & BIT(endpoint)) != 0){
|
||||
return false;
|
||||
}
|
||||
tinyusb_endpoints.out |= BIT(endpoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool tinyusb_has_available_fifos(void){
|
||||
uint8_t max_endpoints = 4, active_endpoints = 0;
|
||||
if (tinyusb_loaded_interfaces_mask & BIT(USB_INTERFACE_CDC)) {
|
||||
max_endpoints = 5; //CDC endpoint 0x85 is actually not linked to FIFO and not used
|
||||
}
|
||||
for(uint8_t i=1; i<7; i++){
|
||||
if((tinyusb_endpoints.in & BIT(i)) != 0){
|
||||
active_endpoints++;
|
||||
}
|
||||
}
|
||||
|
||||
return active_endpoints < max_endpoints;
|
||||
}
|
||||
|
||||
static uint16_t tinyusb_load_descriptor(tinyusb_interface_t interface, uint8_t * dst, uint8_t * itf)
|
||||
{
|
||||
if(tinyusb_loaded_interfaces_callbacks[interface]){
|
||||
return tinyusb_loaded_interfaces_callbacks[interface](dst, itf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool tinyusb_load_enabled_interfaces(){
|
||||
tinyusb_config_descriptor_len += TUD_CONFIG_DESC_LEN;
|
||||
tinyusb_config_descriptor = (uint8_t *)malloc(tinyusb_config_descriptor_len);
|
||||
if (tinyusb_config_descriptor == NULL) {
|
||||
log_e("Descriptor Malloc Failed");
|
||||
return false;
|
||||
}
|
||||
uint8_t * dst = tinyusb_config_descriptor + TUD_CONFIG_DESC_LEN;
|
||||
|
||||
for(int i=0; i<USB_INTERFACE_MAX; i++){
|
||||
if (tinyusb_loaded_interfaces_mask & (1U << i)) {
|
||||
uint16_t len = tinyusb_load_descriptor((tinyusb_interface_t)i, dst, &tinyusb_loaded_interfaces_num);
|
||||
if (!len) {
|
||||
log_e("Descriptor Load Failed");
|
||||
return false;
|
||||
} else {
|
||||
if(i == USB_INTERFACE_CDC){
|
||||
if(!tinyusb_reserve_out_endpoint(3) ||!tinyusb_reserve_in_endpoint(4) || !tinyusb_reserve_in_endpoint(5)){
|
||||
log_e("CDC Reserve Endpoints Failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
dst += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB Device");
|
||||
uint8_t descriptor[TUD_CONFIG_DESC_LEN] = {
|
||||
//num configs, interface count, string index, total length, attribute, power in mA
|
||||
TUD_CONFIG_DESCRIPTOR(1, tinyusb_loaded_interfaces_num, str_index, tinyusb_config_descriptor_len, USB_DEVICE_ATTRIBUTES, USB_DEVICE_POWER)
|
||||
};
|
||||
memcpy(tinyusb_config_descriptor, descriptor, TUD_CONFIG_DESC_LEN);
|
||||
if ((tinyusb_loaded_interfaces_mask == (BIT(USB_INTERFACE_CDC) | BIT(USB_INTERFACE_DFU))) || (tinyusb_loaded_interfaces_mask == BIT(USB_INTERFACE_CDC))) {
|
||||
usb_persist_enabled = true;
|
||||
log_d("USB Persist enabled");
|
||||
}
|
||||
log_d("Load Done: if_num: %u, descr_len: %u, if_mask: 0x%x", tinyusb_loaded_interfaces_num, tinyusb_config_descriptor_len, tinyusb_loaded_interfaces_mask);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline char nibble_to_hex_char(uint8_t b)
|
||||
{
|
||||
if (b < 0xa) {
|
||||
return '0' + b;
|
||||
} else {
|
||||
return 'a' + b - 0xa;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_usb_serial_num(void)
|
||||
{
|
||||
/* Get the MAC address */
|
||||
const uint32_t mac0 = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_0_REG, EFUSE_MAC_0);
|
||||
const uint32_t mac1 = REG_GET_FIELD(EFUSE_RD_MAC_SPI_SYS_1_REG, EFUSE_MAC_1);
|
||||
uint8_t mac_bytes[6];
|
||||
memcpy(mac_bytes, &mac0, 4);
|
||||
memcpy(mac_bytes + 4, &mac1, 2);
|
||||
|
||||
/* Convert to UTF16 string */
|
||||
uint8_t* srl = (uint8_t*)USB_DEVICE_SERIAL;
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
uint8_t b = mac_bytes[5 - i]; /* printing from the MSB */
|
||||
if (i) {
|
||||
*srl++ = ':';
|
||||
}
|
||||
*srl++ = nibble_to_hex_char(b >> 4);
|
||||
*srl++ = nibble_to_hex_char(b & 0xf);
|
||||
}
|
||||
*srl++ = '\0';
|
||||
}
|
||||
|
||||
static void tinyusb_apply_device_config(tinyusb_device_config_t *config){
|
||||
if(config->product_name){
|
||||
snprintf(USB_DEVICE_PRODUCT, 126, "%s", config->product_name);
|
||||
}
|
||||
|
||||
if(config->manufacturer_name){
|
||||
snprintf(USB_DEVICE_MANUFACTURER, 126, "%s", config->manufacturer_name);
|
||||
}
|
||||
|
||||
if(config->serial_number && config->serial_number[0]){
|
||||
snprintf(USB_DEVICE_SERIAL, 126, "%s", config->serial_number);
|
||||
} else {
|
||||
set_usb_serial_num();
|
||||
}
|
||||
|
||||
if(config->webusb_url){
|
||||
snprintf(WEBUSB_URL, 126, "%s", config->webusb_url);
|
||||
}
|
||||
|
||||
WEBUSB_ENABLED = config->webusb_enabled;
|
||||
USB_DEVICE_ATTRIBUTES = config->usb_attributes;
|
||||
USB_DEVICE_POWER = config->usb_power_ma;
|
||||
|
||||
tinyusb_device_descriptor.bcdUSB = config->usb_version;
|
||||
tinyusb_device_descriptor.idVendor = config->vid;
|
||||
tinyusb_device_descriptor.idProduct = config->pid;
|
||||
tinyusb_device_descriptor.bcdDevice = config->fw_version;
|
||||
tinyusb_device_descriptor.bDeviceClass = config->usb_class;
|
||||
tinyusb_device_descriptor.bDeviceSubClass = config->usb_subclass;
|
||||
tinyusb_device_descriptor.bDeviceProtocol = config->usb_protocol;
|
||||
}
|
||||
|
||||
static void IRAM_ATTR usb_persist_shutdown_handler(void)
|
||||
{
|
||||
if(usb_persist_mode != RESTART_NO_PERSIST){
|
||||
if (usb_persist_enabled) {
|
||||
REG_SET_BIT(RTC_CNTL_USB_CONF_REG, RTC_CNTL_IO_MUX_RESET_DISABLE);
|
||||
REG_SET_BIT(RTC_CNTL_USB_CONF_REG, RTC_CNTL_USB_RESET_DISABLE);
|
||||
}
|
||||
if (usb_persist_mode == RESTART_BOOTLOADER) {
|
||||
//USB CDC Download
|
||||
if (usb_persist_enabled) {
|
||||
USB_WRAP.date.val = USBDC_PERSIST_ENA;
|
||||
}
|
||||
REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT);
|
||||
periph_module_disable(PERIPH_TIMG1_MODULE);
|
||||
} else if (usb_persist_mode == RESTART_BOOTLOADER_DFU) {
|
||||
//DFU Download
|
||||
USB_WRAP.date.val = USBDC_BOOT_DFU;
|
||||
REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT);
|
||||
periph_module_disable(PERIPH_TIMG0_MODULE);
|
||||
periph_module_disable(PERIPH_TIMG1_MODULE);
|
||||
} else if (usb_persist_enabled) {
|
||||
//USB Persist reboot
|
||||
USB_WRAP.date.val = USBDC_PERSIST_ENA;
|
||||
}
|
||||
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_PROCPU_RST);
|
||||
}
|
||||
}
|
||||
|
||||
// USB Device Driver task
|
||||
// This top level thread processes all usb events and invokes callbacks
|
||||
static void usb_device_task(void *param) {
|
||||
(void)param;
|
||||
while(1) tud_task(); // RTOS forever loop
|
||||
}
|
||||
|
||||
/*
|
||||
* PUBLIC API
|
||||
* */
|
||||
|
||||
esp_err_t tinyusb_enable_interface(tinyusb_interface_t interface, uint16_t descriptor_len, tinyusb_descriptor_cb_t cb)
|
||||
{
|
||||
if((interface >= USB_INTERFACE_MAX) || (tinyusb_loaded_interfaces_mask & (1U << interface))){
|
||||
log_e("Interface %u not enabled", interface);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
tinyusb_loaded_interfaces_mask |= (1U << interface);
|
||||
tinyusb_config_descriptor_len += descriptor_len;
|
||||
tinyusb_loaded_interfaces_callbacks[interface] = cb;
|
||||
log_d("Interface %u enabled", interface);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t tinyusb_init(tinyusb_device_config_t *config) {
|
||||
static bool initialized = false;
|
||||
if(initialized){
|
||||
return ESP_OK;
|
||||
}
|
||||
initialized = true;
|
||||
|
||||
tinyusb_endpoints.val = 0;
|
||||
tinyusb_apply_device_config(config);
|
||||
if (!tinyusb_load_enabled_interfaces()) {
|
||||
initialized = false;
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
bool usb_did_persist = (USB_WRAP.date.val == USBDC_PERSIST_ENA);
|
||||
|
||||
if(usb_did_persist && usb_persist_enabled){
|
||||
// Enable USB/IO_MUX peripheral reset, if coming from persistent reboot
|
||||
REG_CLR_BIT(RTC_CNTL_USB_CONF_REG, RTC_CNTL_IO_MUX_RESET_DISABLE);
|
||||
REG_CLR_BIT(RTC_CNTL_USB_CONF_REG, RTC_CNTL_USB_RESET_DISABLE);
|
||||
} else {
|
||||
// Reset USB module
|
||||
periph_module_reset(PERIPH_USB_MODULE);
|
||||
periph_module_enable(PERIPH_USB_MODULE);
|
||||
}
|
||||
|
||||
if (usb_persist_enabled && esp_register_shutdown_handler(usb_persist_shutdown_handler) != ESP_OK) {
|
||||
initialized = false;
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
tinyusb_config_t tusb_cfg = {
|
||||
.external_phy = false // In the most cases you need to use a `false` value
|
||||
};
|
||||
esp_err_t err = tinyusb_driver_install(&tusb_cfg);
|
||||
if (err != ESP_OK) {
|
||||
initialized = false;
|
||||
return err;
|
||||
}
|
||||
xTaskCreate(usb_device_task, "usbd", 4096, NULL, configMAX_PRIORITIES - 1, NULL);
|
||||
return err;
|
||||
}
|
||||
|
||||
void usb_persist_restart(restart_type_t mode)
|
||||
{
|
||||
if (usb_persist_enabled && mode < RESTART_TYPE_MAX) {
|
||||
usb_persist_mode = mode;
|
||||
esp_restart();
|
||||
} else {
|
||||
log_e("Persistence is not enabled");
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t tinyusb_add_string_descriptor(const char * str){
|
||||
if(str == NULL || tinyusb_string_descriptor_len >= MAX_STRING_DESCRIPTORS){
|
||||
return 0;
|
||||
}
|
||||
uint8_t index = tinyusb_string_descriptor_len;
|
||||
tinyusb_string_descriptor[tinyusb_string_descriptor_len++] = (char*)str;
|
||||
return index;
|
||||
}
|
||||
|
||||
uint8_t tinyusb_get_free_duplex_endpoint(void){
|
||||
if(!tinyusb_has_available_fifos()){
|
||||
log_e("No available IN endpoints");
|
||||
return 0;
|
||||
}
|
||||
for(uint8_t i=1; i<7; i++){
|
||||
if((tinyusb_endpoints.in & BIT(i)) == 0 && (tinyusb_endpoints.out & BIT(i)) == 0){
|
||||
tinyusb_endpoints.in |= BIT(i);
|
||||
tinyusb_endpoints.out |= BIT(i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
log_e("No available duplex endpoints");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t tinyusb_get_free_in_endpoint(void){
|
||||
if(!tinyusb_has_available_fifos()){
|
||||
log_e("No available IN endpoints");
|
||||
return 0;
|
||||
}
|
||||
for(uint8_t i=1; i<7; i++){
|
||||
if((tinyusb_endpoints.in & BIT(i)) == 0 && (tinyusb_endpoints.out & BIT(i)) != 0){
|
||||
tinyusb_endpoints.in |= BIT(i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
for(uint8_t i=1; i<7; i++){
|
||||
if((tinyusb_endpoints.in & BIT(i)) == 0){
|
||||
tinyusb_endpoints.in |= BIT(i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t tinyusb_get_free_out_endpoint(void){
|
||||
for(uint8_t i=1; i<7; i++){
|
||||
if((tinyusb_endpoints.out & BIT(i)) == 0 && (tinyusb_endpoints.in & BIT(i)) != 0){
|
||||
tinyusb_endpoints.out |= BIT(i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
for(uint8_t i=1; i<7; i++){
|
||||
if((tinyusb_endpoints.out & BIT(i)) == 0){
|
||||
tinyusb_endpoints.out |= BIT(i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
void usb_dw_reg_dump(void)
|
||||
{
|
||||
#define USB_PRINT_REG(r) printf("USB0." #r " = 0x%x;\n", USB0.r)
|
||||
#define USB_PRINT_IREG(i, r) printf("USB0.in_ep_reg[%u]." #r " = 0x%x;\n", i, USB0.in_ep_reg[i].r)
|
||||
#define USB_PRINT_OREG(i, r) printf("USB0.out_ep_reg[%u]." #r " = 0x%x;\n", i, USB0.out_ep_reg[i].r)
|
||||
uint8_t i;
|
||||
USB_PRINT_REG(gotgctl);
|
||||
USB_PRINT_REG(gotgint);
|
||||
USB_PRINT_REG(gahbcfg);
|
||||
USB_PRINT_REG(gusbcfg);
|
||||
USB_PRINT_REG(grstctl);
|
||||
USB_PRINT_REG(gintsts);
|
||||
USB_PRINT_REG(gintmsk);
|
||||
USB_PRINT_REG(grxstsr);
|
||||
USB_PRINT_REG(grxstsp);
|
||||
USB_PRINT_REG(grxfsiz);
|
||||
USB_PRINT_REG(gnptxsts);
|
||||
USB_PRINT_REG(gpvndctl);
|
||||
USB_PRINT_REG(ggpio);
|
||||
USB_PRINT_REG(guid);
|
||||
USB_PRINT_REG(gsnpsid);
|
||||
USB_PRINT_REG(ghwcfg1);
|
||||
USB_PRINT_REG(ghwcfg2);
|
||||
USB_PRINT_REG(ghwcfg3);
|
||||
USB_PRINT_REG(ghwcfg4);
|
||||
USB_PRINT_REG(glpmcfg);
|
||||
USB_PRINT_REG(gpwrdn);
|
||||
USB_PRINT_REG(gdfifocfg);
|
||||
USB_PRINT_REG(gadpctl);
|
||||
USB_PRINT_REG(hptxfsiz);
|
||||
USB_PRINT_REG(hcfg);
|
||||
USB_PRINT_REG(hfir);
|
||||
USB_PRINT_REG(hfnum);
|
||||
USB_PRINT_REG(hptxsts);
|
||||
USB_PRINT_REG(haint);
|
||||
USB_PRINT_REG(haintmsk);
|
||||
USB_PRINT_REG(hflbaddr);
|
||||
USB_PRINT_REG(hprt);
|
||||
USB_PRINT_REG(dcfg);
|
||||
USB_PRINT_REG(dctl);
|
||||
USB_PRINT_REG(dsts);
|
||||
USB_PRINT_REG(diepmsk);
|
||||
USB_PRINT_REG(doepmsk);
|
||||
USB_PRINT_REG(daint);
|
||||
USB_PRINT_REG(daintmsk);
|
||||
USB_PRINT_REG(dtknqr1);
|
||||
USB_PRINT_REG(dtknqr2);
|
||||
USB_PRINT_REG(dvbusdis);
|
||||
USB_PRINT_REG(dvbuspulse);
|
||||
USB_PRINT_REG(dtknqr3_dthrctl);
|
||||
USB_PRINT_REG(dtknqr4_fifoemptymsk);
|
||||
USB_PRINT_REG(deachint);
|
||||
USB_PRINT_REG(deachintmsk);
|
||||
USB_PRINT_REG(pcgctrl);
|
||||
USB_PRINT_REG(pcgctrl1);
|
||||
USB_PRINT_REG(gnptxfsiz);
|
||||
for (i = 0; i < 4; i++) {
|
||||
printf("USB0.dieptxf[%u] = 0x%x;\n", i, USB0.dieptxf[i]);
|
||||
}
|
||||
// for (i = 0; i < 16; i++) {
|
||||
// printf("USB0.diepeachintmsk[%u] = 0x%x;\n", i, USB0.diepeachintmsk[i]);
|
||||
// }
|
||||
// for (i = 0; i < 16; i++) {
|
||||
// printf("USB0.doepeachintmsk[%u] = 0x%x;\n", i, USB0.doepeachintmsk[i]);
|
||||
// }
|
||||
for (i = 0; i < 7; i++) {
|
||||
printf("// EP %u:\n", i);
|
||||
USB_PRINT_IREG(i, diepctl);
|
||||
USB_PRINT_IREG(i, diepint);
|
||||
USB_PRINT_IREG(i, dieptsiz);
|
||||
USB_PRINT_IREG(i, diepdma);
|
||||
USB_PRINT_IREG(i, dtxfsts);
|
||||
USB_PRINT_OREG(i, doepctl);
|
||||
USB_PRINT_OREG(i, doepint);
|
||||
USB_PRINT_OREG(i, doeptsiz);
|
||||
USB_PRINT_OREG(i, doepdma);
|
||||
}
|
||||
}
|
||||
*/
|
||||
#endif /* CONFIG_USB_ENABLED */
|
103
cores/esp32/esp32-hal-tinyusb.h
Normal file
103
cores/esp32/esp32-hal-tinyusb.h
Normal file
@ -0,0 +1,103 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#pragma once
|
||||
|
||||
#include "esp32-hal.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
#if CONFIG_USB_ENABLED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "tinyusb.h"
|
||||
|
||||
typedef struct {
|
||||
uint16_t vid;
|
||||
uint16_t pid;
|
||||
const char * product_name;
|
||||
const char * manufacturer_name;
|
||||
const char * serial_number;
|
||||
uint16_t fw_version;
|
||||
|
||||
uint16_t usb_version;
|
||||
uint8_t usb_class;
|
||||
uint8_t usb_subclass;
|
||||
uint8_t usb_protocol;
|
||||
uint8_t usb_attributes;
|
||||
uint16_t usb_power_ma;
|
||||
|
||||
bool webusb_enabled;
|
||||
const char * webusb_url;
|
||||
} tinyusb_device_config_t;
|
||||
|
||||
#define TINYUSB_CONFIG_DEFAULT() { \
|
||||
.vid = USB_ESPRESSIF_VID, \
|
||||
.pid = 0x0002, \
|
||||
.product_name = CONFIG_USB_DESC_PRODUCT_STRING, \
|
||||
.manufacturer_name = CONFIG_USB_DESC_MANUFACTURER_STRING, \
|
||||
.serial_number = CONFIG_USB_DESC_SERIAL_STRING, \
|
||||
.fw_version = CONFIG_USB_DESC_BCDDEVICE, \
|
||||
.usb_version = 0x0200, \
|
||||
.usb_class = TUSB_CLASS_MISC, \
|
||||
.usb_subclass = MISC_SUBCLASS_COMMON, \
|
||||
.usb_protocol = MISC_PROTOCOL_IAD, \
|
||||
.usb_attributes = TUSB_DESC_CONFIG_ATT_SELF_POWERED, \
|
||||
.usb_power_ma = 500, \
|
||||
.webusb_enabled = false, \
|
||||
.webusb_url = "espressif.github.io/arduino-esp32/webusb.html" \
|
||||
}
|
||||
|
||||
esp_err_t tinyusb_init(tinyusb_device_config_t *config);
|
||||
|
||||
/*
|
||||
* USB Persistence API
|
||||
* */
|
||||
typedef enum {
|
||||
RESTART_NO_PERSIST,
|
||||
RESTART_PERSIST,
|
||||
RESTART_BOOTLOADER,
|
||||
RESTART_BOOTLOADER_DFU,
|
||||
RESTART_TYPE_MAX
|
||||
} restart_type_t;
|
||||
|
||||
void usb_persist_restart(restart_type_t mode);
|
||||
|
||||
// The following definitions and functions are to be used only by the drivers
|
||||
typedef enum {
|
||||
USB_INTERFACE_CDC,
|
||||
USB_INTERFACE_DFU,
|
||||
USB_INTERFACE_HID,
|
||||
USB_INTERFACE_VENDOR,
|
||||
USB_INTERFACE_MSC,
|
||||
USB_INTERFACE_MIDI,
|
||||
USB_INTERFACE_CUSTOM,
|
||||
USB_INTERFACE_MAX
|
||||
} tinyusb_interface_t;
|
||||
|
||||
typedef uint16_t (*tinyusb_descriptor_cb_t)(uint8_t * dst, uint8_t * itf);
|
||||
|
||||
esp_err_t tinyusb_enable_interface(tinyusb_interface_t interface, uint16_t descriptor_len, tinyusb_descriptor_cb_t cb);
|
||||
uint8_t tinyusb_add_string_descriptor(const char * str);
|
||||
uint8_t tinyusb_get_free_duplex_endpoint(void);
|
||||
uint8_t tinyusb_get_free_in_endpoint(void);
|
||||
uint8_t tinyusb_get_free_out_endpoint(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_USB_ENABLED */
|
||||
#endif /* CONFIG_IDF_TARGET_ESP32S2 */
|
@ -15,12 +15,29 @@
|
||||
#include "esp32-hal-touch.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_intr.h"
|
||||
#include "soc/rtc_io_reg.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/sens_reg.h"
|
||||
#include "soc/sens_struct.h"
|
||||
#include "driver/touch_sensor.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/ets_sys.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_intr.h"
|
||||
#endif
|
||||
|
||||
static uint16_t __touchSleepCycles = 0x1000;
|
||||
static uint16_t __touchMeasureCycles = 0x1000;
|
||||
@ -29,8 +46,9 @@ typedef void (*voidFuncPtr)(void);
|
||||
static voidFuncPtr __touchInterruptHandlers[10] = {0,};
|
||||
static intr_handle_t touch_intr_handle = NULL;
|
||||
|
||||
void IRAM_ATTR __touchISR(void * arg)
|
||||
void ARDUINO_ISR_ATTR __touchISR(void * arg)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
uint32_t pad_intr = READ_PERI_REG(SENS_SAR_TOUCH_CTRL2_REG) & 0x3ff;
|
||||
uint32_t rtc_intr = READ_PERI_REG(RTC_CNTL_INT_ST_REG);
|
||||
uint8_t i = 0;
|
||||
@ -47,16 +65,21 @@ void IRAM_ATTR __touchISR(void * arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void __touchSetCycles(uint16_t measure, uint16_t sleep)
|
||||
{
|
||||
__touchSleepCycles = sleep;
|
||||
__touchMeasureCycles = measure;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
//Touch pad SleepCycle Time
|
||||
SET_PERI_REG_BITS(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_SLEEP_CYCLES, __touchSleepCycles, SENS_TOUCH_SLEEP_CYCLES_S);
|
||||
//Touch Pad Measure Time
|
||||
SET_PERI_REG_BITS(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_MEAS_DELAY, __touchMeasureCycles, SENS_TOUCH_MEAS_DELAY_S);
|
||||
#else
|
||||
touch_pad_set_meas_time(sleep, measure);
|
||||
#endif
|
||||
}
|
||||
|
||||
void __touchInit()
|
||||
@ -66,15 +89,27 @@ void __touchInit()
|
||||
return;
|
||||
}
|
||||
initialized = true;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
SET_PERI_REG_BITS(RTC_IO_TOUCH_CFG_REG, RTC_IO_TOUCH_XPD_BIAS, 1, RTC_IO_TOUCH_XPD_BIAS_S);
|
||||
SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_MEAS_EN_CLR);
|
||||
//clear touch enable
|
||||
WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, 0x0);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_TOUCH_SLP_TIMER_EN);
|
||||
|
||||
__touchSetCycles(__touchMeasureCycles, __touchSleepCycles);
|
||||
|
||||
esp_intr_alloc(ETS_RTC_CORE_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, __touchISR, NULL, &touch_intr_handle);
|
||||
esp_intr_alloc(ETS_RTC_CORE_INTR_SOURCE, (int)ARDUINO_ISR_FLAG, __touchISR, NULL, &touch_intr_handle);
|
||||
#else
|
||||
touch_pad_init();
|
||||
touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_0V5);
|
||||
touch_pad_set_idle_channel_connect(TOUCH_PAD_CONN_GND);
|
||||
__touchSetCycles(__touchMeasureCycles, __touchSleepCycles);
|
||||
touch_pad_denoise_t denoise = {
|
||||
.grade = TOUCH_PAD_DENOISE_BIT4,
|
||||
.cap_level = TOUCH_PAD_DENOISE_CAP_L4,
|
||||
};
|
||||
touch_pad_denoise_set_config(&denoise);
|
||||
touch_pad_denoise_enable();
|
||||
touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
|
||||
touch_pad_fsm_start();
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t __touchRead(uint8_t pin)
|
||||
@ -88,6 +123,7 @@ uint16_t __touchRead(uint8_t pin)
|
||||
|
||||
__touchInit();
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
uint32_t v0 = READ_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG);
|
||||
//Disable Intr & enable touch pad
|
||||
WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG,
|
||||
@ -119,6 +155,25 @@ uint16_t __touchRead(uint8_t pin)
|
||||
//restore previous value
|
||||
WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, v0);
|
||||
return touch_value;
|
||||
#else
|
||||
static uint32_t chan_mask = 0;
|
||||
uint32_t value = 0;
|
||||
if((chan_mask & (1 << pad)) == 0){
|
||||
if(touch_pad_set_thresh((touch_pad_t)pad, TOUCH_PAD_THRESHOLD_MAX) != ESP_OK){
|
||||
log_e("touch_pad_set_thresh failed");
|
||||
} else if(touch_pad_config((touch_pad_t)pad) != ESP_OK){
|
||||
log_e("touch_pad_config failed");
|
||||
} else {
|
||||
chan_mask |= (1 << pad);
|
||||
}
|
||||
}
|
||||
if((chan_mask & (1 << pad)) != 0) {
|
||||
if(touch_pad_read_raw_data((touch_pad_t)pad, &value) != ESP_OK){
|
||||
log_e("touch_pad_read_raw_data failed");
|
||||
}
|
||||
}
|
||||
return value;
|
||||
#endif
|
||||
}
|
||||
|
||||
void __touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), uint16_t threshold)
|
||||
@ -134,6 +189,7 @@ void __touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), uint16_t thresh
|
||||
|
||||
__touchInterruptHandlers[pad] = userFunc;
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
//clear touch force ,select the Touch mode is Timer
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_EN_M|SENS_TOUCH_START_FORCE_M);
|
||||
|
||||
@ -161,6 +217,9 @@ void __touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), uint16_t thresh
|
||||
(1 << (pad + SENS_TOUCH_PAD_WORKEN_S)) | \
|
||||
(1 << (pad + SENS_TOUCH_PAD_OUTEN2_S)) | \
|
||||
(1 << (pad + SENS_TOUCH_PAD_OUTEN1_S)));
|
||||
#else
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
extern uint16_t touchRead(uint8_t pin) __attribute__ ((weak, alias("__touchRead")));
|
||||
|
@ -18,21 +18,46 @@
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_intr.h"
|
||||
#include "rom/uart.h"
|
||||
#include "soc/uart_reg.h"
|
||||
#include "soc/uart_struct.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#include "esp32/rom/uart.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/ets_sys.h"
|
||||
#include "esp32s2/rom/uart.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/uart.h"
|
||||
#include "esp_intr.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
#define UART_PORTS_NUM 2
|
||||
#define UART_REG_BASE(u) ((u==0)?DR_REG_UART_BASE:( (u==1)?DR_REG_UART1_BASE:0))
|
||||
#define UART_RXD_IDX(u) ((u==0)?U0RXD_IN_IDX:( (u==1)?U1RXD_IN_IDX:0))
|
||||
#define UART_TXD_IDX(u) ((u==0)?U0TXD_OUT_IDX:( (u==1)?U1TXD_OUT_IDX:0))
|
||||
#define UART_INTR_SOURCE(u) ((u==0)?ETS_UART0_INTR_SOURCE:( (u==1)?ETS_UART1_INTR_SOURCE:0))
|
||||
#else
|
||||
#define UART_PORTS_NUM 3
|
||||
#define UART_REG_BASE(u) ((u==0)?DR_REG_UART_BASE:( (u==1)?DR_REG_UART1_BASE:( (u==2)?DR_REG_UART2_BASE:0)))
|
||||
#define UART_RXD_IDX(u) ((u==0)?U0RXD_IN_IDX:( (u==1)?U1RXD_IN_IDX:( (u==2)?U2RXD_IN_IDX:0)))
|
||||
#define UART_TXD_IDX(u) ((u==0)?U0TXD_OUT_IDX:( (u==1)?U1TXD_OUT_IDX:( (u==2)?U2TXD_OUT_IDX:0)))
|
||||
#define UART_INTR_SOURCE(u) ((u==0)?ETS_UART0_INTR_SOURCE:( (u==1)?ETS_UART1_INTR_SOURCE:((u==2)?ETS_UART2_INTR_SOURCE:0)))
|
||||
#endif
|
||||
|
||||
static int s_uart_debug_nr = 0;
|
||||
|
||||
@ -50,29 +75,35 @@ struct uart_struct_t {
|
||||
#define UART_MUTEX_LOCK()
|
||||
#define UART_MUTEX_UNLOCK()
|
||||
|
||||
static uart_t _uart_bus_array[3] = {
|
||||
{(volatile uart_dev_t *)(DR_REG_UART_BASE), 0, NULL, NULL},
|
||||
{(volatile uart_dev_t *)(DR_REG_UART1_BASE), 1, NULL, NULL},
|
||||
{(volatile uart_dev_t *)(DR_REG_UART2_BASE), 2, NULL, NULL}
|
||||
static uart_t _uart_bus_array[] = {
|
||||
{&UART0, 0, NULL, NULL},
|
||||
{&UART1, 1, NULL, NULL},
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
{&UART2, 2, NULL, NULL}
|
||||
#endif
|
||||
};
|
||||
#else
|
||||
#define UART_MUTEX_LOCK() do {} while (xSemaphoreTake(uart->lock, portMAX_DELAY) != pdPASS)
|
||||
#define UART_MUTEX_UNLOCK() xSemaphoreGive(uart->lock)
|
||||
|
||||
static uart_t _uart_bus_array[3] = {
|
||||
{(volatile uart_dev_t *)(DR_REG_UART_BASE), NULL, 0, NULL, NULL},
|
||||
{(volatile uart_dev_t *)(DR_REG_UART1_BASE), NULL, 1, NULL, NULL},
|
||||
{(volatile uart_dev_t *)(DR_REG_UART2_BASE), NULL, 2, NULL, NULL}
|
||||
static uart_t _uart_bus_array[] = {
|
||||
{&UART0, NULL, 0, NULL, NULL},
|
||||
{&UART1, NULL, 1, NULL, NULL},
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
{&UART2, NULL, 2, NULL, NULL}
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
static void IRAM_ATTR _uart_isr(void *arg)
|
||||
static void uart_on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb);
|
||||
|
||||
static void ARDUINO_ISR_ATTR _uart_isr(void *arg)
|
||||
{
|
||||
uint8_t i, c;
|
||||
BaseType_t xHigherPriorityTaskWoken;
|
||||
uart_t* uart;
|
||||
|
||||
for(i=0;i<3;i++){
|
||||
for(i=0;i<UART_PORTS_NUM;i++){
|
||||
uart = &_uart_bus_array[i];
|
||||
if(uart->intr_handle == NULL){
|
||||
continue;
|
||||
@ -80,9 +111,15 @@ static void IRAM_ATTR _uart_isr(void *arg)
|
||||
uart->dev->int_clr.rxfifo_full = 1;
|
||||
uart->dev->int_clr.frm_err = 1;
|
||||
uart->dev->int_clr.rxfifo_tout = 1;
|
||||
while(uart->dev->status.rxfifo_cnt) {
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
while(uart->dev->status.rxfifo_cnt || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
|
||||
c = uart->dev->fifo.rw_byte;
|
||||
if(uart->queue != NULL && !xQueueIsQueueFullFromISR(uart->queue)) {
|
||||
#else
|
||||
uint32_t fifo_reg = UART_FIFO_AHB_REG(i);
|
||||
while(uart->dev->status.rxfifo_cnt) {
|
||||
c = ESP_REG(fifo_reg);
|
||||
#endif
|
||||
if(uart->queue != NULL) {
|
||||
xQueueSendFromISR(uart->queue, &c, &xHigherPriorityTaskWoken);
|
||||
}
|
||||
}
|
||||
@ -97,14 +134,18 @@ void uartEnableInterrupt(uart_t* uart)
|
||||
{
|
||||
UART_MUTEX_LOCK();
|
||||
uart->dev->conf1.rxfifo_full_thrhd = 112;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
uart->dev->conf1.rx_tout_thrhd = 2;
|
||||
#else
|
||||
uart->dev->mem_conf.rx_tout_thrhd = 2;
|
||||
#endif
|
||||
uart->dev->conf1.rx_tout_en = 1;
|
||||
uart->dev->int_ena.rxfifo_full = 1;
|
||||
uart->dev->int_ena.frm_err = 1;
|
||||
uart->dev->int_ena.rxfifo_tout = 1;
|
||||
uart->dev->int_clr.val = 0xffffffff;
|
||||
|
||||
esp_intr_alloc(UART_INTR_SOURCE(uart->num), (int)ESP_INTR_FLAG_IRAM, _uart_isr, NULL, &uart->intr_handle);
|
||||
esp_intr_alloc(UART_INTR_SOURCE(uart->num), (int)ARDUINO_ISR_FLAG, _uart_isr, NULL, &uart->intr_handle);
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
@ -140,7 +181,7 @@ void uartDetachTx(uart_t* uart)
|
||||
|
||||
void uartAttachRx(uart_t* uart, uint8_t rxPin, bool inverted)
|
||||
{
|
||||
if(uart == NULL || rxPin > 39) {
|
||||
if(uart == NULL || rxPin >= GPIO_PIN_COUNT) {
|
||||
return;
|
||||
}
|
||||
pinMode(rxPin, INPUT);
|
||||
@ -150,7 +191,7 @@ void uartAttachRx(uart_t* uart, uint8_t rxPin, bool inverted)
|
||||
|
||||
void uartAttachTx(uart_t* uart, uint8_t txPin, bool inverted)
|
||||
{
|
||||
if(uart == NULL || txPin > 39) {
|
||||
if(uart == NULL || txPin >= GPIO_PIN_COUNT) {
|
||||
return;
|
||||
}
|
||||
pinMode(txPin, OUTPUT);
|
||||
@ -159,7 +200,7 @@ void uartAttachTx(uart_t* uart, uint8_t txPin, bool inverted)
|
||||
|
||||
uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t queueLen, bool inverted)
|
||||
{
|
||||
if(uart_nr > 2) {
|
||||
if(uart_nr >= UART_PORTS_NUM) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -187,9 +228,11 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx
|
||||
if(uart_nr == 1){
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART1_CLK_EN);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART1_RST);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
} else if(uart_nr == 2){
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART2_CLK_EN);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART2_RST);
|
||||
#endif
|
||||
} else {
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART_CLK_EN);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART_RST);
|
||||
@ -205,6 +248,11 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx
|
||||
uart->dev->conf0.stop_bit_num = ONE_STOP_BITS_CONF;
|
||||
uart->dev->rs485_conf.dl1_en = 1;
|
||||
}
|
||||
|
||||
// tx_idle_num : idle interval after tx FIFO is empty(unit: the time it takes to send one bit under current baudrate)
|
||||
// Setting it to 0 prevents line idle time/delays when sending messages with small intervals
|
||||
uart->dev->idle_conf.tx_idle_num = 0; //
|
||||
|
||||
UART_MUTEX_UNLOCK();
|
||||
|
||||
if(rxPin != -1) {
|
||||
@ -214,7 +262,7 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx
|
||||
if(txPin != -1) {
|
||||
uartAttachTx(uart, txPin, inverted);
|
||||
}
|
||||
|
||||
addApbChangeCallback(uart, uart_on_apb_change);
|
||||
return uart;
|
||||
}
|
||||
|
||||
@ -223,11 +271,10 @@ void uartEnd(uart_t* uart)
|
||||
if(uart == NULL) {
|
||||
return;
|
||||
}
|
||||
removeApbChangeCallback(uart, uart_on_apb_change);
|
||||
|
||||
UART_MUTEX_LOCK();
|
||||
if(uart->queue != NULL) {
|
||||
uint8_t c;
|
||||
while(xQueueReceive(uart->queue, &c, 0));
|
||||
vQueueDelete(uart->queue);
|
||||
uart->queue = NULL;
|
||||
}
|
||||
@ -240,12 +287,30 @@ void uartEnd(uart_t* uart)
|
||||
uartDetachTx(uart);
|
||||
}
|
||||
|
||||
size_t uartResizeRxBuffer(uart_t * uart, size_t new_size) {
|
||||
if(uart == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
UART_MUTEX_LOCK();
|
||||
if(uart->queue != NULL) {
|
||||
vQueueDelete(uart->queue);
|
||||
uart->queue = xQueueCreate(new_size, sizeof(uint8_t));
|
||||
if(uart->queue == NULL) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
UART_MUTEX_UNLOCK();
|
||||
|
||||
return new_size;
|
||||
}
|
||||
|
||||
uint32_t uartAvailable(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || uart->queue == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return uxQueueMessagesWaiting(uart->queue);
|
||||
return (uxQueueMessagesWaiting(uart->queue) + uart->dev->status.rxfifo_cnt) ;
|
||||
}
|
||||
|
||||
uint32_t uartAvailableForWrite(uart_t* uart)
|
||||
@ -256,12 +321,41 @@ uint32_t uartAvailableForWrite(uart_t* uart)
|
||||
return 0x7f - uart->dev->status.txfifo_cnt;
|
||||
}
|
||||
|
||||
void uartRxFifoToQueue(uart_t* uart)
|
||||
{
|
||||
uint8_t c;
|
||||
UART_MUTEX_LOCK();
|
||||
//disable interrupts
|
||||
uart->dev->int_ena.val = 0;
|
||||
uart->dev->int_clr.val = 0xffffffff;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
while (uart->dev->status.rxfifo_cnt || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
|
||||
c = uart->dev->fifo.rw_byte;
|
||||
#else
|
||||
uint32_t fifo_reg = UART_FIFO_AHB_REG(uart->num);
|
||||
while (uart->dev->status.rxfifo_cnt) {
|
||||
c = ESP_REG(fifo_reg);
|
||||
#endif
|
||||
xQueueSend(uart->queue, &c, 0);
|
||||
}
|
||||
//enable interrupts
|
||||
uart->dev->int_ena.rxfifo_full = 1;
|
||||
uart->dev->int_ena.frm_err = 1;
|
||||
uart->dev->int_ena.rxfifo_tout = 1;
|
||||
uart->dev->int_clr.val = 0xffffffff;
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
uint8_t uartRead(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || uart->queue == NULL) {
|
||||
return 0;
|
||||
}
|
||||
uint8_t c;
|
||||
if ((uxQueueMessagesWaiting(uart->queue) == 0) && (uart->dev->status.rxfifo_cnt > 0))
|
||||
{
|
||||
uartRxFifoToQueue(uart);
|
||||
}
|
||||
if(xQueueReceive(uart->queue, &c, 0)) {
|
||||
return c;
|
||||
}
|
||||
@ -274,6 +368,10 @@ uint8_t uartPeek(uart_t* uart)
|
||||
return 0;
|
||||
}
|
||||
uint8_t c;
|
||||
if ((uxQueueMessagesWaiting(uart->queue) == 0) && (uart->dev->status.rxfifo_cnt > 0))
|
||||
{
|
||||
uartRxFifoToQueue(uart);
|
||||
}
|
||||
if(xQueuePeek(uart->queue, &c, 0)) {
|
||||
return c;
|
||||
}
|
||||
@ -287,7 +385,11 @@ void uartWrite(uart_t* uart, uint8_t c)
|
||||
}
|
||||
UART_MUTEX_LOCK();
|
||||
while(uart->dev->status.txfifo_cnt == 0x7F);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
uart->dev->fifo.rw_byte = c;
|
||||
#else
|
||||
ESP_REG(UART_FIFO_AHB_REG(uart->num)) = c;
|
||||
#endif
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
@ -297,29 +399,53 @@ void uartWriteBuf(uart_t* uart, const uint8_t * data, size_t len)
|
||||
return;
|
||||
}
|
||||
UART_MUTEX_LOCK();
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32
|
||||
uint32_t fifo_reg = UART_FIFO_AHB_REG(uart->num);
|
||||
#endif
|
||||
while(len) {
|
||||
while(len && uart->dev->status.txfifo_cnt < 0x7F) {
|
||||
while(uart->dev->status.txfifo_cnt == 0x7F);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
uart->dev->fifo.rw_byte = *data++;
|
||||
#else
|
||||
ESP_REG(fifo_reg) = *data++;
|
||||
#endif
|
||||
len--;
|
||||
}
|
||||
}
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
void uartFlush(uart_t* uart)
|
||||
{
|
||||
uartFlushTxOnly(uart,false);
|
||||
}
|
||||
|
||||
void uartFlushTxOnly(uart_t* uart, bool txOnly)
|
||||
{
|
||||
if(uart == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
UART_MUTEX_LOCK();
|
||||
while(uart->dev->status.txfifo_cnt);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
while(uart->dev->status.txfifo_cnt || uart->dev->status.st_utx_out);
|
||||
|
||||
if( !txOnly ){
|
||||
//Due to hardware issue, we can not use fifo_rst to reset uart fifo.
|
||||
//See description about UART_TXFIFO_RST and UART_RXFIFO_RST in <<esp32_technical_reference_manual>> v2.6 or later.
|
||||
|
||||
// we read the data out and make `fifo_len == 0 && rd_addr == wr_addr`.
|
||||
while(uart->dev->status.rxfifo_cnt != 0 || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
|
||||
READ_PERI_REG(UART_FIFO_REG(uart->num));
|
||||
}
|
||||
|
||||
xQueueReset(uart->queue);
|
||||
}
|
||||
#else
|
||||
while(uart->dev->status.txfifo_cnt);
|
||||
uart->dev->conf0.txfifo_rst = 1;
|
||||
uart->dev->conf0.txfifo_rst = 0;
|
||||
#endif
|
||||
|
||||
uart->dev->conf0.rxfifo_rst = 1;
|
||||
uart->dev->conf0.rxfifo_rst = 0;
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
@ -329,50 +455,107 @@ void uartSetBaudRate(uart_t* uart, uint32_t baud_rate)
|
||||
return;
|
||||
}
|
||||
UART_MUTEX_LOCK();
|
||||
uint32_t clk_div = ((UART_CLK_FREQ<<4)/baud_rate);
|
||||
uint32_t clk_div = ((getApbFrequency()<<4)/baud_rate);
|
||||
uart->dev->clk_div.div_int = clk_div>>4 ;
|
||||
uart->dev->clk_div.div_frag = clk_div & 0xf;
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
static void uart_on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb)
|
||||
{
|
||||
uart_t* uart = (uart_t*)arg;
|
||||
if(ev_type == APB_BEFORE_CHANGE){
|
||||
UART_MUTEX_LOCK();
|
||||
//disabple interrupt
|
||||
uart->dev->int_ena.val = 0;
|
||||
uart->dev->int_clr.val = 0xffffffff;
|
||||
// read RX fifo
|
||||
uint8_t c;
|
||||
// BaseType_t xHigherPriorityTaskWoken;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
while(uart->dev->status.rxfifo_cnt != 0 || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
|
||||
c = uart->dev->fifo.rw_byte;
|
||||
#else
|
||||
uint32_t fifo_reg = UART_FIFO_AHB_REG(uart->num);
|
||||
while(uart->dev->status.rxfifo_cnt != 0) {
|
||||
c = ESP_REG(fifo_reg);
|
||||
#endif
|
||||
if(uart->queue != NULL ) {
|
||||
xQueueSend(uart->queue, &c, 1); //&xHigherPriorityTaskWoken);
|
||||
}
|
||||
}
|
||||
UART_MUTEX_UNLOCK();
|
||||
|
||||
// wait TX empty
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
while(uart->dev->status.txfifo_cnt || uart->dev->status.st_utx_out);
|
||||
#else
|
||||
while(uart->dev->status.txfifo_cnt);
|
||||
#endif
|
||||
} else {
|
||||
//todo:
|
||||
// set baudrate
|
||||
UART_MUTEX_LOCK();
|
||||
uint32_t clk_div = (uart->dev->clk_div.div_int << 4) | (uart->dev->clk_div.div_frag & 0x0F);
|
||||
uint32_t baud_rate = ((old_apb<<4)/clk_div);
|
||||
clk_div = ((new_apb<<4)/baud_rate);
|
||||
uart->dev->clk_div.div_int = clk_div>>4 ;
|
||||
uart->dev->clk_div.div_frag = clk_div & 0xf;
|
||||
//enable interrupts
|
||||
uart->dev->int_ena.rxfifo_full = 1;
|
||||
uart->dev->int_ena.frm_err = 1;
|
||||
uart->dev->int_ena.rxfifo_tout = 1;
|
||||
uart->dev->int_clr.val = 0xffffffff;
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t uartGetBaudRate(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t clk_div = (uart->dev->clk_div.div_int << 4) | (uart->dev->clk_div.div_frag & 0x0F);
|
||||
return ((UART_CLK_FREQ<<4)/clk_div);
|
||||
if(!clk_div) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void IRAM_ATTR uart0_write_char(char c)
|
||||
return ((getApbFrequency()<<4)/clk_div);
|
||||
}
|
||||
|
||||
static void ARDUINO_ISR_ATTR uart0_write_char(char c)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
while(((ESP_REG(0x01C+DR_REG_UART_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) == 0x7F);
|
||||
ESP_REG(DR_REG_UART_BASE) = c;
|
||||
#else
|
||||
while(UART0.status.txfifo_cnt == 0x7F);
|
||||
WRITE_PERI_REG(UART_FIFO_AHB_REG(0), c);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void IRAM_ATTR uart1_write_char(char c)
|
||||
static void ARDUINO_ISR_ATTR uart1_write_char(char c)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
while(((ESP_REG(0x01C+DR_REG_UART1_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) == 0x7F);
|
||||
ESP_REG(DR_REG_UART1_BASE) = c;
|
||||
#else
|
||||
while(UART1.status.txfifo_cnt == 0x7F);
|
||||
WRITE_PERI_REG(UART_FIFO_AHB_REG(1), c);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void IRAM_ATTR uart2_write_char(char c)
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
static void ARDUINO_ISR_ATTR uart2_write_char(char c)
|
||||
{
|
||||
while(((ESP_REG(0x01C+DR_REG_UART2_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) == 0x7F);
|
||||
ESP_REG(DR_REG_UART2_BASE) = c;
|
||||
}
|
||||
#endif
|
||||
|
||||
void uartSetDebug(uart_t* uart)
|
||||
void uart_install_putc()
|
||||
{
|
||||
if(uart == NULL || uart->num > 2) {
|
||||
s_uart_debug_nr = -1;
|
||||
ets_install_putc1(NULL);
|
||||
return;
|
||||
}
|
||||
if(s_uart_debug_nr == uart->num) {
|
||||
return;
|
||||
}
|
||||
s_uart_debug_nr = uart->num;
|
||||
switch(s_uart_debug_nr) {
|
||||
case 0:
|
||||
ets_install_putc1((void (*)(char)) &uart0_write_char);
|
||||
@ -380,15 +563,31 @@ void uartSetDebug(uart_t* uart)
|
||||
case 1:
|
||||
ets_install_putc1((void (*)(char)) &uart1_write_char);
|
||||
break;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
case 2:
|
||||
ets_install_putc1((void (*)(char)) &uart2_write_char);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ets_install_putc1(NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void uartSetDebug(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || uart->num >= UART_PORTS_NUM) {
|
||||
s_uart_debug_nr = -1;
|
||||
//ets_install_putc1(NULL);
|
||||
//return;
|
||||
} else
|
||||
if(s_uart_debug_nr == uart->num) {
|
||||
return;
|
||||
} else
|
||||
s_uart_debug_nr = uart->num;
|
||||
uart_install_putc();
|
||||
}
|
||||
|
||||
int uartGetDebug()
|
||||
{
|
||||
return s_uart_debug_nr;
|
||||
@ -396,9 +595,6 @@ int uartGetDebug()
|
||||
|
||||
int log_printf(const char *format, ...)
|
||||
{
|
||||
if(s_uart_debug_nr < 0){
|
||||
return 0;
|
||||
}
|
||||
static char loc_buf[64];
|
||||
char * temp = loc_buf;
|
||||
int len;
|
||||
@ -416,8 +612,8 @@ int log_printf(const char *format, ...)
|
||||
}
|
||||
vsnprintf(temp, len+1, format, arg);
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
if(_uart_bus_array[s_uart_debug_nr].lock){
|
||||
while (xSemaphoreTake(_uart_bus_array[s_uart_debug_nr].lock, portMAX_DELAY) != pdPASS);
|
||||
if(s_uart_debug_nr != -1 && _uart_bus_array[s_uart_debug_nr].lock){
|
||||
xSemaphoreTake(_uart_bus_array[s_uart_debug_nr].lock, portMAX_DELAY);
|
||||
ets_printf("%s", temp);
|
||||
xSemaphoreGive(_uart_bus_array[s_uart_debug_nr].lock);
|
||||
} else {
|
||||
@ -427,8 +623,89 @@ int log_printf(const char *format, ...)
|
||||
ets_printf("%s", temp);
|
||||
#endif
|
||||
va_end(arg);
|
||||
if(len > 64){
|
||||
if(len >= sizeof(loc_buf)){
|
||||
free(temp);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* if enough pulses are detected return the minimum high pulse duration + minimum low pulse duration divided by two.
|
||||
* This equals one bit period. If flag is true the function return inmediately, otherwise it waits for enough pulses.
|
||||
*/
|
||||
unsigned long uartBaudrateDetect(uart_t *uart, bool flg)
|
||||
{
|
||||
while(uart->dev->rxd_cnt.edge_cnt < 30) { // UART_PULSE_NUM(uart_num)
|
||||
if(flg) return 0;
|
||||
ets_delay_us(1000);
|
||||
}
|
||||
|
||||
UART_MUTEX_LOCK();
|
||||
unsigned long ret = ((uart->dev->lowpulse.min_cnt + uart->dev->highpulse.min_cnt) >> 1) + 12;
|
||||
UART_MUTEX_UNLOCK();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* To start detection of baud rate with the uart the auto_baud.en bit needs to be cleared and set. The bit period is
|
||||
* detected calling uartBadrateDetect(). The raw baudrate is computed using the UART_CLK_FREQ. The raw baudrate is
|
||||
* rounded to the closed real baudrate.
|
||||
*/
|
||||
void uartStartDetectBaudrate(uart_t *uart) {
|
||||
if(!uart) return;
|
||||
|
||||
uart->dev->auto_baud.glitch_filt = 0x08;
|
||||
uart->dev->auto_baud.en = 0;
|
||||
uart->dev->auto_baud.en = 1;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
uartDetectBaudrate(uart_t *uart)
|
||||
{
|
||||
static bool uartStateDetectingBaudrate = false;
|
||||
|
||||
if(!uartStateDetectingBaudrate) {
|
||||
uart->dev->auto_baud.glitch_filt = 0x08;
|
||||
uart->dev->auto_baud.en = 0;
|
||||
uart->dev->auto_baud.en = 1;
|
||||
uartStateDetectingBaudrate = true;
|
||||
}
|
||||
|
||||
unsigned long divisor = uartBaudrateDetect(uart, true);
|
||||
if (!divisor) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uart->dev->auto_baud.en = 0;
|
||||
uartStateDetectingBaudrate = false; // Initialize for the next round
|
||||
|
||||
unsigned long baudrate = getApbFrequency() / divisor;
|
||||
|
||||
static const unsigned long default_rates[] = {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 74880, 115200, 230400, 256000, 460800, 921600, 1843200, 3686400};
|
||||
|
||||
size_t i;
|
||||
for (i = 1; i < sizeof(default_rates) / sizeof(default_rates[0]) - 1; i++) // find the nearest real baudrate
|
||||
{
|
||||
if (baudrate <= default_rates[i])
|
||||
{
|
||||
if (baudrate - default_rates[i - 1] < default_rates[i] - baudrate) {
|
||||
i--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return default_rates[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the status of the RX state machine, if the value is non-zero the state machine is active.
|
||||
*/
|
||||
bool uartRxActive(uart_t* uart) {
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
return uart->dev->status.st_urx_out != 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
@ -63,13 +63,21 @@ void uartWrite(uart_t* uart, uint8_t c);
|
||||
void uartWriteBuf(uart_t* uart, const uint8_t * data, size_t len);
|
||||
|
||||
void uartFlush(uart_t* uart);
|
||||
void uartFlushTxOnly(uart_t* uart, bool txOnly );
|
||||
|
||||
void uartSetBaudRate(uart_t* uart, uint32_t baud_rate);
|
||||
uint32_t uartGetBaudRate(uart_t* uart);
|
||||
|
||||
size_t uartResizeRxBuffer(uart_t* uart, size_t new_size);
|
||||
|
||||
void uartSetDebug(uart_t* uart);
|
||||
int uartGetDebug();
|
||||
|
||||
void uartStartDetectBaudrate(uart_t *uart);
|
||||
unsigned long uartDetectBaudrate(uart_t *uart);
|
||||
|
||||
bool uartRxActive(uart_t* uart);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -20,10 +20,6 @@
|
||||
#ifndef HAL_ESP32_HAL_H_
|
||||
#define HAL_ESP32_HAL_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
@ -33,9 +29,35 @@ extern "C" {
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_sleep.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef F_CPU
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#define F_CPU (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ * 1000000U)
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define F_CPU (CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ * 1000000U)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if CONFIG_ARDUINO_ISR_IRAM
|
||||
#define ARDUINO_ISR_ATTR IRAM_ATTR
|
||||
#define ARDUINO_ISR_FLAG ESP_INTR_FLAG_IRAM
|
||||
#else
|
||||
#define ARDUINO_ISR_ATTR
|
||||
#define ARDUINO_ISR_FLAG (0)
|
||||
#endif
|
||||
|
||||
#ifndef ARDUINO_RUNNING_CORE
|
||||
#define ARDUINO_RUNNING_CORE CONFIG_ARDUINO_RUNNING_CORE
|
||||
#endif
|
||||
|
||||
#ifndef ARDUINO_EVENT_RUNNING_CORE
|
||||
#define ARDUINO_EVENT_RUNNING_CORE CONFIG_ARDUINO_EVENT_RUNNING_CORE
|
||||
#endif
|
||||
|
||||
//forward declaration from freertos/portmacro.h
|
||||
@ -56,15 +78,43 @@ void yield(void);
|
||||
#include "esp32-hal-spi.h"
|
||||
#include "esp32-hal-i2c.h"
|
||||
#include "esp32-hal-ledc.h"
|
||||
#include "esp32-hal-rmt.h"
|
||||
#include "esp32-hal-sigmadelta.h"
|
||||
#include "esp32-hal-timer.h"
|
||||
#include "esp32-hal-bt.h"
|
||||
#include "esp32-hal-psram.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp32-hal-cpu.h"
|
||||
|
||||
//returns chip temperature in Celsius
|
||||
float temperatureRead();
|
||||
|
||||
#if CONFIG_AUTOSTART_ARDUINO
|
||||
//enable/disable WDT for Arduino's setup and loop functions
|
||||
void enableLoopWDT();
|
||||
void disableLoopWDT();
|
||||
//feed WDT for the loop task
|
||||
void feedLoopWDT();
|
||||
#endif
|
||||
|
||||
//enable/disable WDT for the IDLE task on Core 0 (SYSTEM)
|
||||
void enableCore0WDT();
|
||||
void disableCore0WDT();
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
//enable/disable WDT for the IDLE task on Core 1 (Arduino)
|
||||
void enableCore1WDT();
|
||||
void disableCore1WDT();
|
||||
#endif
|
||||
|
||||
//if xCoreID < 0 or CPU is unicore, it will use xTaskCreate, else xTaskCreatePinnedToCore
|
||||
//allows to easily handle all possible situations without repetitive code
|
||||
BaseType_t xTaskCreateUniversal( TaskFunction_t pxTaskCode,
|
||||
const char * const pcName,
|
||||
const uint32_t usStackDepth,
|
||||
void * const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t * const pxCreatedTask,
|
||||
const BaseType_t xCoreID );
|
||||
|
||||
unsigned long micros();
|
||||
unsigned long millis();
|
||||
void delay(uint32_t);
|
||||
|
@ -18,7 +18,7 @@
|
||||
#define _ESP8266_COMPAT_H_
|
||||
|
||||
#define ICACHE_FLASH_ATTR
|
||||
#define ICACHE_RAM_ATTR IRAM_ATTR
|
||||
#define ICACHE_RAM_ATTR ARDUINO_ISR_ATTR
|
||||
|
||||
|
||||
#endif /* _ESP8266_COMPAT_H_ */
|
@ -7,13 +7,10 @@ For details, see http://sourceforge.net/projects/libb64
|
||||
|
||||
#include "cencode.h"
|
||||
|
||||
const int CHARS_PER_LINE = 72;
|
||||
|
||||
void base64_init_encodestate(base64_encodestate* state_in)
|
||||
{
|
||||
state_in->step = step_A;
|
||||
state_in->result = 0;
|
||||
state_in->stepcount = 0;
|
||||
}
|
||||
|
||||
char base64_encode_value(char value_in)
|
||||
@ -68,12 +65,6 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out,
|
||||
*codechar++ = base64_encode_value(result);
|
||||
result = (fragment & 0x03f) >> 0;
|
||||
*codechar++ = base64_encode_value(result);
|
||||
|
||||
++(state_in->stepcount);
|
||||
if (state_in->stepcount == CHARS_PER_LINE/4) {
|
||||
*codechar++ = '\n';
|
||||
state_in->stepcount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* control should not reach here */
|
||||
|
@ -1,27 +1,50 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_task_wdt.h"
|
||||
#include "Arduino.h"
|
||||
#if ARDUINO_SERIAL_PORT //Serial used for USB CDC
|
||||
#include "USB.h"
|
||||
#endif
|
||||
|
||||
TaskHandle_t loopTaskHandle = NULL;
|
||||
|
||||
#if CONFIG_AUTOSTART_ARDUINO
|
||||
|
||||
#if CONFIG_FREERTOS_UNICORE
|
||||
#define ARDUINO_RUNNING_CORE 0
|
||||
#else
|
||||
#define ARDUINO_RUNNING_CORE 1
|
||||
void yieldIfNecessary(void){
|
||||
static uint64_t lastYield = 0;
|
||||
uint64_t now = millis();
|
||||
if((now - lastYield) > 2000) {
|
||||
lastYield = now;
|
||||
vTaskDelay(5); //delay 1 RTOS tick
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool loopTaskWDTEnabled;
|
||||
|
||||
void loopTask(void *pvParameters)
|
||||
{
|
||||
setup();
|
||||
for(;;) {
|
||||
#if CONFIG_FREERTOS_UNICORE
|
||||
yieldIfNecessary();
|
||||
#endif
|
||||
if(loopTaskWDTEnabled){
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
loop();
|
||||
if (serialEventRun) serialEventRun();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void app_main()
|
||||
{
|
||||
#if ARDUINO_SERIAL_PORT //Serial used for USB CDC
|
||||
USB.begin();
|
||||
#endif
|
||||
loopTaskWDTEnabled = false;
|
||||
initArduino();
|
||||
xTaskCreatePinnedToCore(loopTask, "loopTask", 8192, NULL, 1, NULL, ARDUINO_RUNNING_CORE);
|
||||
xTaskCreateUniversal(loopTask, "loopTask", 8192, NULL, 1, &loopTaskHandle, ARDUINO_RUNNING_CORE);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -32,7 +32,6 @@ typedef unsigned long prog_uint32_t;
|
||||
#define PROGMEM
|
||||
#define PGM_P const char *
|
||||
#define PGM_VOID_P const void *
|
||||
#define FPSTR(p) ((const char *)(p))
|
||||
#define PSTR(s) (s)
|
||||
#define _SFR_BYTE(n) (n)
|
||||
|
||||
|
@ -25,11 +25,12 @@ uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) {
|
||||
uint8_t i;
|
||||
|
||||
for(i = 0; i < 8; ++i) {
|
||||
digitalWrite(clockPin, HIGH);
|
||||
//digitalWrite(clockPin, HIGH);
|
||||
if(bitOrder == LSBFIRST)
|
||||
value |= digitalRead(dataPin) << i;
|
||||
else
|
||||
value |= digitalRead(dataPin) << (7 - i);
|
||||
digitalWrite(clockPin, HIGH);
|
||||
digitalWrite(clockPin, LOW);
|
||||
}
|
||||
return value;
|
||||
|
@ -1,24 +1,32 @@
|
||||
Please fill the info fields, it helps to get you faster support ;)
|
||||
Make your question, not a Statement, inclusive. Include all pertinent information:
|
||||
|
||||
If you have a Guru Meditation Error, please decode it:
|
||||
What you are trying to do.
|
||||
Describe your system( Hardware, computer, O/S, core version, environment)
|
||||
Describe what is failing
|
||||
Show the shortest possible code that will duplicate the error
|
||||
Show the EXACT error message(it doesn't work is not enough)
|
||||
Then if someone is interested and knowledgeable you might get a answer. All of this work on your part shows us that you have worked to solve YOUR problem. The more complete your issue posting is, the more likely someone will volunteer their time to help you.
|
||||
|
||||
If you have a Guru Meditation Error or Backtrace, ***please decode it***:
|
||||
https://github.com/me-no-dev/EspExceptionDecoder
|
||||
|
||||
----------------------------- Remove above -----------------------------
|
||||
|
||||
|
||||
### Hardware:
|
||||
Board: ?ESP32 Dev Module?
|
||||
Board: ?ESP32 Dev Module? ?node32? ?ttgo_lora?
|
||||
Core Installation/update date: ?11/jul/2017?
|
||||
IDE name: ?Arduino IDE? ?Platform.io? ?IDF component?
|
||||
Flash Frequency: ?40Mhz?
|
||||
PSRAM enabled: ?no?
|
||||
Upload Speed: ?115200?
|
||||
|
||||
Computer OS: ?Windows 10? ?Mac OSX? ?Ubuntu?
|
||||
|
||||
### Description:
|
||||
Describe your problem here
|
||||
|
||||
|
||||
### Sketch:
|
||||
### Sketch: (leave the backquotes for [code formatting](https://help.github.com/articles/creating-and-highlighting-code-blocks/))
|
||||
```cpp
|
||||
|
||||
//Change the code below by your sketch
|
||||
|
59
docs/OTAWebUpdate/OTAWebUpdate.md
Normal file
59
docs/OTAWebUpdate/OTAWebUpdate.md
Normal file
@ -0,0 +1,59 @@
|
||||
# Over the Air through Web browser
|
||||
OTAWebUpdate is done with a web browser that can be useful in the following typical scenarios:
|
||||
- Once the application developed and loading directly from Arduino IDE is inconvenient or not possible
|
||||
- after deployment if user is unable to expose Firmware for OTA from external update server
|
||||
- provide updates after deployment to small quantity of modules when setting an update server is not practicable
|
||||
|
||||
## Requirements
|
||||
- The ESP and the computer must be connected to the same network
|
||||
|
||||
## Implementation
|
||||
The sample implementation has been done using:
|
||||
- example sketch OTAWebUpdater.ino
|
||||
- ESP32 (Dev Module)
|
||||
|
||||
You can use another module also if it meets Flash chip size of the sketch
|
||||
|
||||
1-Before you begin, please make sure that you have the following software installed:
|
||||
- Arduino IDE
|
||||
- Host software depending on O/S you use:
|
||||
- Avahi http://avahi.org/ for Linux
|
||||
- Bonjour http://www.apple.com/support/bonjour/ for Windows
|
||||
- Mac OSX and iOS - support is already built in / no any extra s/w is required
|
||||
|
||||
Prepare the sketch and configuration for initial upload with a serial port
|
||||
- Start Arduino IDE and load sketch OTAWebUpdater.ino available under File > Examples > OTAWebUpdater.ino
|
||||
- Update ssid and pass in the sketch so the module can join your Wi-Fi network
|
||||
- Open File > Preferences, look for “Show verbose output during:” and check out “compilation” option
|
||||
|
||||

|
||||
|
||||
- Upload sketch (Ctrl+U)
|
||||
- Now open web browser and enter the url, i.e. http://esp32.local. Once entered, browser should display a form
|
||||
|
||||

|
||||
|
||||
> username= admin
|
||||
|
||||
> password= admin
|
||||
|
||||
**Note**-*If entering “http://ESP32.local” does not work, try replacing “ESP32” with module’s IP address.This workaround is useful in case the host software installed does not work*.
|
||||
|
||||
Now click on Login button and browser will display a upload form
|
||||
|
||||

|
||||
|
||||
For Uploading the New Firmware you need to provide the Binary File of your Code.
|
||||
|
||||
Exporting Binary file of the Firmware (Code)
|
||||
- Open up the Arduino IDE
|
||||
- Open up the Code, for Exporting up Binary file
|
||||
- Now go to Sketch > export compiled Binary
|
||||

|
||||
|
||||
- Binary file is exported to the same Directory where your code is present
|
||||
|
||||
Once you are comfortable with this procedure go ahead and modify OTAWebUpdater.ino sketch to print some additional messages, compile it, Export new binary file and upload it using web browser to see entered changes on a Serial Monitor
|
||||
|
||||
|
||||
|
BIN
docs/OTAWebUpdate/esp32login.PNG
Normal file
BIN
docs/OTAWebUpdate/esp32login.PNG
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
docs/OTAWebUpdate/esp32upload.PNG
Normal file
BIN
docs/OTAWebUpdate/esp32upload.PNG
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.8 KiB |
BIN
docs/OTAWebUpdate/esp32verbose.PNG
Normal file
BIN
docs/OTAWebUpdate/esp32verbose.PNG
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
docs/OTAWebUpdate/exportTobinary.PNG
Normal file
BIN
docs/OTAWebUpdate/exportTobinary.PNG
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
12
docs/arduino-ide/boards_manager.md
Normal file
12
docs/arduino-ide/boards_manager.md
Normal file
@ -0,0 +1,12 @@
|
||||
## Installation instructions using Arduino IDE Boards Manager
|
||||
### ==========================================================
|
||||
|
||||
- Stable release link: `https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json`
|
||||
- Development release link: `https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json`
|
||||
|
||||
Starting with 1.6.4, Arduino allows installation of third-party platform packages using Boards Manager. We have packages available for Windows, Mac OS, and Linux (32, 64 bit and ARM).
|
||||
|
||||
- Install the current upstream Arduino IDE at the 1.8 level or later. The current version is at the [Arduino website](http://www.arduino.cc/en/main/software).
|
||||
- Start Arduino and open Preferences window.
|
||||
- Enter one of the release links above into *Additional Board Manager URLs* field. You can add multiple URLs, separating them with commas.
|
||||
- Open Boards Manager from Tools > Board menu and install *esp32* platform (and don't forget to select your ESP32 board from Tools > Board menu after installation).
|
@ -16,20 +16,21 @@ Installation instructions for Debian / Ubuntu OS
|
||||
cd esp32 && \
|
||||
git submodule update --init --recursive && \
|
||||
cd tools && \
|
||||
python2 get.py
|
||||
python3 get.py
|
||||
```
|
||||
- Restart Arduino IDE
|
||||
|
||||
|
||||
|
||||
- If you have Arduino.app installed to /Applications/, modify the installation as follows, beginning at `mkdir -p ~/Arduino...`:
|
||||
- If you have Arduino installed to ~/, modify the installation as follows, beginning at `mkdir -p ~/Arduino/hardware`:
|
||||
|
||||
```bash
|
||||
cd /Applications/Arduino_*/Contents/java/hardware/
|
||||
cd ~/Arduino/hardware
|
||||
mkdir -p espressif && \
|
||||
cd espressif && \
|
||||
git clone https://github.com/espressif/arduino-esp32.git esp32 && \
|
||||
cd esp32 && \
|
||||
git submodule update --init --recursive && \
|
||||
cd tools && \
|
||||
python2 get.py```
|
||||
python3 get.py
|
||||
```
|
||||
|
@ -21,5 +21,9 @@ Installation instructions for Mac OS
|
||||
|
||||
```xcode-select --install```
|
||||
|
||||
- Try `python3` instead of `python` if you get the error: `IOError: [Errno socket error] [SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:590)` when running `python get.py`
|
||||
|
||||
- If you get the following error when running `python get.py` urllib.error.URLError: <urlopen error SSL: CERTIFICATE_VERIFY_FAILED, go to Macintosh HD > Applications > Python3.6 folder (or any other python version), and run the following scripts: Install Certificates.command and Update Shell Profile.command
|
||||
|
||||
- Restart Arduino IDE
|
||||
|
||||
|
@ -1,6 +1,10 @@
|
||||
To use as a component of ESP-IDF
|
||||
=================================================
|
||||
|
||||
## esp32-arduino-lib-builder
|
||||
|
||||
For a simplified method, see [lib-builder](lib_builder.md)
|
||||
|
||||
## Installation
|
||||
|
||||
- Download and install [esp-idf](https://github.com/espressif/esp-idf)
|
||||
|
14
docs/lib_builder.md
Normal file
14
docs/lib_builder.md
Normal file
@ -0,0 +1,14 @@
|
||||
## Using esp32-arduino-lib-builder to compile custom libraries
|
||||
|
||||
Espressif has provided a [tool](https://github.com/espressif/esp32-arduino-lib-builder) to simplify building your own compiled libraries for use in Arduino IDE (or your favorite IDE).
|
||||
To use it to generate custom libraries, follow these steps:
|
||||
1. `git clone https://github.com/espressif/esp32-arduino-lib-builder`
|
||||
2. `cd esp32-arduino-lib-builder`
|
||||
3. `./tools/update-components.sh`
|
||||
4. `./tools/install-esp-idf.sh` (if you already have an $IDF_PATH defined, it will use your local copy of the repository)
|
||||
5. `make menuconfig` or directly edit sdkconfig.
|
||||
6. `./build.sh`
|
||||
|
||||
The script automates the process of building [arduino as an ESP-IDF component](https://github.com/espressif/arduino-esp32/blob/master/docs/esp-idf_component.md).
|
||||
Once it is complete, you can cherry pick the needed libraries from `out/tools/sdk/lib`, or run `tools/copy-to-arduino.sh` to copy the entire built system.
|
||||
`tools/config.sh` contains a number of variables that control the process, particularly the $IDF_BRANCH variable. You can adjust this to try building against newer versions, but there are absolutely no guarantees that any components will work or even successfully compile against a newer IDF.
|
@ -1,11 +1,11 @@
|
||||
Installation instructions for using PlatformIO
|
||||
=================================================
|
||||
|
||||
- [What is PlatformIO?](http://docs.platformio.org/en/latest/what-is-platformio.html?utm_source=github&utm_medium=arduino-esp32)
|
||||
- [PlatformIO IDE](http://platformio.org/platformio-ide?utm_source=github&utm_medium=arduino-esp32)
|
||||
- [PlatformIO Core](http://docs.platformio.org/en/latest/core.html?utm_source=github&utm_medium=arduino-esp32) (command line tool)
|
||||
- [Advanced usage](http://docs.platformio.org/en/latest/platforms/espressif32.html?utm_source=github&utm_medium=arduino-esp32) -
|
||||
- [What is PlatformIO?](https://docs.platformio.org/en/latest/what-is-platformio.html?utm_source=github&utm_medium=arduino-esp32)
|
||||
- [PlatformIO IDE](https://platformio.org/platformio-ide?utm_source=github&utm_medium=arduino-esp32)
|
||||
- [PlatformIO Core](https://docs.platformio.org/en/latest/core.html?utm_source=github&utm_medium=arduino-esp32) (command line tool)
|
||||
- [Advanced usage](https://docs.platformio.org/en/latest/platforms/espressif32.html?utm_source=github&utm_medium=arduino-esp32) -
|
||||
custom settings, uploading to SPIFFS, Over-the-Air (OTA), staging version
|
||||
- [Integration with Cloud and Standalone IDEs](http://docs.platformio.org/en/latest/ide.html?utm_source=github&utm_medium=arduino-esp32) -
|
||||
- [Integration with Cloud and Standalone IDEs](https://docs.platformio.org/en/latest/ide.html?utm_source=github&utm_medium=arduino-esp32) -
|
||||
Cloud9, Codeanywhere, Eclipse Che (Codenvy), Atom, CLion, Eclipse, Emacs, NetBeans, Qt Creator, Sublime Text, VIM, Visual Studio, and VSCode
|
||||
- [Project Examples](http://docs.platformio.org/en/latest/platforms/espressif32.html?utm_source=github&utm_medium=arduino-esp32#examples)
|
||||
- [Project Examples](https://docs.platformio.org/en/latest/platforms/espressif32.html?utm_source=github&utm_medium=arduino-esp32#examples)
|
||||
|
@ -4,18 +4,23 @@
|
||||
#include <ESPmDNS.h>
|
||||
#include <Update.h>
|
||||
|
||||
const char* host = "ESP32";
|
||||
const char* host = "esp32";
|
||||
const char* ssid = "xxx";
|
||||
const char* password = "xxxx";
|
||||
|
||||
WebServer server(80);
|
||||
|
||||
const char* loginIndex = "<form name='loginForm'>"
|
||||
/*
|
||||
* Login page
|
||||
*/
|
||||
|
||||
const char* loginIndex =
|
||||
"<form name='loginForm'>"
|
||||
"<table width='20%' bgcolor='A09F9F' align='center'>"
|
||||
"<tr>"
|
||||
"<td colspan=2><center><font size=4><b>ESP32 Login Page</b></font></center>"
|
||||
"<td colspan=2>"
|
||||
"<center><font size=4><b>ESP32 Login Page</b></font></center>"
|
||||
"<br>"
|
||||
|
||||
"</td>"
|
||||
"<br>"
|
||||
"<br>"
|
||||
@ -31,7 +36,6 @@ const char* loginIndex = "<form name='loginForm'>"
|
||||
"<br>"
|
||||
"<br>"
|
||||
"</tr>"
|
||||
|
||||
"<tr>"
|
||||
"<td><input type='submit' onclick='check(this.form)' value='Login'></td>"
|
||||
"</tr>"
|
||||
@ -47,16 +51,16 @@ const char* loginIndex = "<form name='loginForm'>"
|
||||
"else"
|
||||
"{"
|
||||
" alert('Error Password or Username')/*displays error message*/"
|
||||
|
||||
"}"
|
||||
"}"
|
||||
"</script>";
|
||||
|
||||
/*
|
||||
* Server Index Page
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
const char* serverIndex = "<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>"
|
||||
const char* serverIndex =
|
||||
"<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>"
|
||||
"<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>"
|
||||
"<input type='file' name='update'>"
|
||||
"<input type='submit' value='Update'>"
|
||||
@ -91,6 +95,10 @@ const char* serverIndex = "<script src='https://ajax.googleapis.com/ajax/libs/jq
|
||||
"});"
|
||||
"});"
|
||||
"</script>";
|
||||
|
||||
/*
|
||||
* setup function
|
||||
*/
|
||||
void setup(void) {
|
||||
Serial.begin(115200);
|
||||
|
||||
|
@ -20,6 +20,7 @@ ArduinoOTAClass::ArduinoOTAClass()
|
||||
, _size(0)
|
||||
, _cmd(0)
|
||||
, _ota_port(0)
|
||||
, _ota_timeout(1000)
|
||||
, _start_callback(NULL)
|
||||
, _end_callback(NULL)
|
||||
, _error_callback(NULL)
|
||||
@ -126,9 +127,7 @@ void ArduinoOTAClass::begin() {
|
||||
}
|
||||
_initialized = true;
|
||||
_state = OTA_IDLE;
|
||||
#ifdef OTA_DEBUG
|
||||
OTA_DEBUG.printf("OTA server at: %s.local:%u\n", _hostname.c_str(), _port);
|
||||
#endif
|
||||
log_i("OTA server at: %s.local:%u", _hostname.c_str(), _port);
|
||||
}
|
||||
|
||||
int ArduinoOTAClass::parseInt(){
|
||||
@ -172,6 +171,7 @@ void ArduinoOTAClass::_onRx(){
|
||||
_md5 = readStringUntil('\n');
|
||||
_md5.trim();
|
||||
if(_md5.length() != 32){
|
||||
log_e("bad md5 length");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -197,6 +197,7 @@ void ArduinoOTAClass::_onRx(){
|
||||
} else if (_state == OTA_WAITAUTH) {
|
||||
int cmd = parseInt();
|
||||
if (cmd != U_AUTH) {
|
||||
log_e("%d was expected. got %d instead", U_AUTH, cmd);
|
||||
_state = OTA_IDLE;
|
||||
return;
|
||||
}
|
||||
@ -204,6 +205,7 @@ void ArduinoOTAClass::_onRx(){
|
||||
String cnonce = readStringUntil(' ');
|
||||
String response = readStringUntil('\n');
|
||||
if (cnonce.length() != 32 || response.length() != 32) {
|
||||
log_e("auth param fail");
|
||||
_state = OTA_IDLE;
|
||||
return;
|
||||
}
|
||||
@ -224,6 +226,7 @@ void ArduinoOTAClass::_onRx(){
|
||||
} else {
|
||||
_udp_ota.beginPacket(_udp_ota.remoteIP(), _udp_ota.remotePort());
|
||||
_udp_ota.print("Authentication Failed");
|
||||
log_w("Authentication Failed");
|
||||
_udp_ota.endPacket();
|
||||
if (_error_callback) _error_callback(OTA_AUTH_ERROR);
|
||||
_state = OTA_IDLE;
|
||||
@ -233,9 +236,9 @@ void ArduinoOTAClass::_onRx(){
|
||||
|
||||
void ArduinoOTAClass::_runUpdate() {
|
||||
if (!Update.begin(_size, _cmd)) {
|
||||
#ifdef OTA_DEBUG
|
||||
Update.printError(OTA_DEBUG);
|
||||
#endif
|
||||
|
||||
log_e("Begin ERROR: %s", Update.errorString());
|
||||
|
||||
if (_error_callback) {
|
||||
_error_callback(OTA_BEGIN_ERROR);
|
||||
}
|
||||
@ -260,8 +263,9 @@ void ArduinoOTAClass::_runUpdate() {
|
||||
}
|
||||
|
||||
uint32_t written = 0, total = 0, tried = 0;
|
||||
|
||||
while (!Update.isFinished() && client.connected()) {
|
||||
size_t waited = 1000;
|
||||
size_t waited = _ota_timeout;
|
||||
size_t available = client.available();
|
||||
while (!available && waited){
|
||||
delay(1);
|
||||
@ -270,21 +274,15 @@ void ArduinoOTAClass::_runUpdate() {
|
||||
}
|
||||
if (!waited){
|
||||
if(written && tried++ < 3){
|
||||
#ifdef OTA_DEBUG
|
||||
OTA_DEBUG.printf("Try[%u]: %u\n", tried, written);
|
||||
#endif
|
||||
log_i("Try[%u]: %u", tried, written);
|
||||
if(!client.printf("%u", written)){
|
||||
#ifdef OTA_DEBUG
|
||||
OTA_DEBUG.printf("failed to respond\n");
|
||||
#endif
|
||||
log_e("failed to respond");
|
||||
_state = OTA_IDLE;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#ifdef OTA_DEBUG
|
||||
OTA_DEBUG.printf("Receive Failed\n");
|
||||
#endif
|
||||
log_e("Receive Failed");
|
||||
if (_error_callback) {
|
||||
_error_callback(OTA_RECEIVE_ERROR);
|
||||
}
|
||||
@ -293,9 +291,7 @@ void ArduinoOTAClass::_runUpdate() {
|
||||
return;
|
||||
}
|
||||
if(!available){
|
||||
#ifdef OTA_DEBUG
|
||||
OTA_DEBUG.printf("No Data: %u\n", waited);
|
||||
#endif
|
||||
log_e("No Data: %u", waited);
|
||||
_state = OTA_IDLE;
|
||||
break;
|
||||
}
|
||||
@ -315,18 +311,14 @@ void ArduinoOTAClass::_runUpdate() {
|
||||
log_w("didn't write enough! %u != %u", written, r);
|
||||
}
|
||||
if(!client.printf("%u", written)){
|
||||
#ifdef OTA_DEBUG
|
||||
OTA_DEBUG.printf("failed to respond\n");
|
||||
#endif
|
||||
log_w("failed to respond");
|
||||
}
|
||||
total += written;
|
||||
if(_progress_callback) {
|
||||
_progress_callback(total, _size);
|
||||
}
|
||||
} else {
|
||||
#ifdef OTA_DEBUG
|
||||
Update.printError(OTA_DEBUG);
|
||||
#endif
|
||||
log_e("Write ERROR: %s", Update.errorString());
|
||||
}
|
||||
}
|
||||
|
||||
@ -349,10 +341,7 @@ void ArduinoOTAClass::_runUpdate() {
|
||||
Update.printError(client);
|
||||
client.stop();
|
||||
delay(10);
|
||||
#ifdef OTA_DEBUG
|
||||
OTA_DEBUG.print("Update ERROR: ");
|
||||
Update.printError(OTA_DEBUG);
|
||||
#endif
|
||||
log_e("Update ERROR: %s", Update.errorString());
|
||||
_state = OTA_IDLE;
|
||||
}
|
||||
}
|
||||
@ -364,9 +353,7 @@ void ArduinoOTAClass::end() {
|
||||
MDNS.end();
|
||||
}
|
||||
_state = OTA_IDLE;
|
||||
#ifdef OTA_DEBUG
|
||||
OTA_DEBUG.println("OTA server stopped.");
|
||||
#endif
|
||||
log_i("OTA server stopped.");
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::handle() {
|
||||
@ -387,6 +374,10 @@ int ArduinoOTAClass::getCommand() {
|
||||
return _cmd;
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::setTimeout(int timeoutInMillis) {
|
||||
_ota_timeout = timeoutInMillis;
|
||||
}
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_ARDUINOOTA)
|
||||
ArduinoOTAClass ArduinoOTA;
|
||||
#endif
|
||||
|
@ -7,7 +7,6 @@
|
||||
|
||||
#define INT_BUFFER_SIZE 16
|
||||
|
||||
|
||||
typedef enum {
|
||||
OTA_IDLE,
|
||||
OTA_WAITAUTH,
|
||||
@ -75,6 +74,8 @@ class ArduinoOTAClass
|
||||
//Gets update command type after OTA has started. Either U_FLASH or U_SPIFFS
|
||||
int getCommand();
|
||||
|
||||
void setTimeout(int timeoutInMillis);
|
||||
|
||||
private:
|
||||
int _port;
|
||||
String _password;
|
||||
@ -88,6 +89,7 @@ class ArduinoOTAClass
|
||||
int _size;
|
||||
int _cmd;
|
||||
int _ota_port;
|
||||
int _ota_timeout;
|
||||
IPAddress _ota_ip;
|
||||
String _md5;
|
||||
|
||||
|
@ -1,17 +0,0 @@
|
||||
{
|
||||
"name":"AsyncUDP",
|
||||
"description":"Asynchronous UDP Library for ESP32",
|
||||
"keywords":"async,udp,server,client,multicast,broadcast",
|
||||
"authors":
|
||||
{
|
||||
"name": "Hristo Gochkov",
|
||||
"maintainer": true
|
||||
},
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/me-no-dev/ESPAsyncUDP.git"
|
||||
},
|
||||
"frameworks": "arduino",
|
||||
"platforms":"espressif"
|
||||
}
|
@ -8,6 +8,7 @@ extern "C" {
|
||||
#include "lwip/igmp.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/mld6.h"
|
||||
#include "lwip/prot/ethernet.h"
|
||||
#include <esp_err.h>
|
||||
#include <esp_wifi.h>
|
||||
}
|
||||
@ -15,7 +16,7 @@ extern "C" {
|
||||
#include "lwip/priv/tcpip_priv.h"
|
||||
|
||||
typedef struct {
|
||||
struct tcpip_api_call call;
|
||||
struct tcpip_api_call_data call;
|
||||
udp_pcb * pcb;
|
||||
const ip_addr_t *addr;
|
||||
uint16_t port;
|
||||
@ -24,7 +25,7 @@ typedef struct {
|
||||
err_t err;
|
||||
} udp_api_call_t;
|
||||
|
||||
static err_t _udp_connect_api(struct tcpip_api_call *api_call_msg){
|
||||
static err_t _udp_connect_api(struct tcpip_api_call_data *api_call_msg){
|
||||
udp_api_call_t * msg = (udp_api_call_t *)api_call_msg;
|
||||
msg->err = udp_connect(msg->pcb, msg->addr, msg->port);
|
||||
return msg->err;
|
||||
@ -35,11 +36,11 @@ static err_t _udp_connect(struct udp_pcb *pcb, const ip_addr_t *addr, u16_t port
|
||||
msg.pcb = pcb;
|
||||
msg.addr = addr;
|
||||
msg.port = port;
|
||||
tcpip_api_call(_udp_connect_api, (struct tcpip_api_call*)&msg);
|
||||
tcpip_api_call(_udp_connect_api, (struct tcpip_api_call_data*)&msg);
|
||||
return msg.err;
|
||||
}
|
||||
|
||||
static err_t _udp_disconnect_api(struct tcpip_api_call *api_call_msg){
|
||||
static err_t _udp_disconnect_api(struct tcpip_api_call_data *api_call_msg){
|
||||
udp_api_call_t * msg = (udp_api_call_t *)api_call_msg;
|
||||
msg->err = 0;
|
||||
udp_disconnect(msg->pcb);
|
||||
@ -49,10 +50,10 @@ static err_t _udp_disconnect_api(struct tcpip_api_call *api_call_msg){
|
||||
static void _udp_disconnect(struct udp_pcb *pcb){
|
||||
udp_api_call_t msg;
|
||||
msg.pcb = pcb;
|
||||
tcpip_api_call(_udp_disconnect_api, (struct tcpip_api_call*)&msg);
|
||||
tcpip_api_call(_udp_disconnect_api, (struct tcpip_api_call_data*)&msg);
|
||||
}
|
||||
|
||||
static err_t _udp_remove_api(struct tcpip_api_call *api_call_msg){
|
||||
static err_t _udp_remove_api(struct tcpip_api_call_data *api_call_msg){
|
||||
udp_api_call_t * msg = (udp_api_call_t *)api_call_msg;
|
||||
msg->err = 0;
|
||||
udp_remove(msg->pcb);
|
||||
@ -62,10 +63,10 @@ static err_t _udp_remove_api(struct tcpip_api_call *api_call_msg){
|
||||
static void _udp_remove(struct udp_pcb *pcb){
|
||||
udp_api_call_t msg;
|
||||
msg.pcb = pcb;
|
||||
tcpip_api_call(_udp_remove_api, (struct tcpip_api_call*)&msg);
|
||||
tcpip_api_call(_udp_remove_api, (struct tcpip_api_call_data*)&msg);
|
||||
}
|
||||
|
||||
static err_t _udp_bind_api(struct tcpip_api_call *api_call_msg){
|
||||
static err_t _udp_bind_api(struct tcpip_api_call_data *api_call_msg){
|
||||
udp_api_call_t * msg = (udp_api_call_t *)api_call_msg;
|
||||
msg->err = udp_bind(msg->pcb, msg->addr, msg->port);
|
||||
return msg->err;
|
||||
@ -76,11 +77,11 @@ static err_t _udp_bind(struct udp_pcb *pcb, const ip_addr_t *addr, u16_t port){
|
||||
msg.pcb = pcb;
|
||||
msg.addr = addr;
|
||||
msg.port = port;
|
||||
tcpip_api_call(_udp_bind_api, (struct tcpip_api_call*)&msg);
|
||||
tcpip_api_call(_udp_bind_api, (struct tcpip_api_call_data*)&msg);
|
||||
return msg.err;
|
||||
}
|
||||
|
||||
static err_t _udp_sendto_api(struct tcpip_api_call *api_call_msg){
|
||||
static err_t _udp_sendto_api(struct tcpip_api_call_data *api_call_msg){
|
||||
udp_api_call_t * msg = (udp_api_call_t *)api_call_msg;
|
||||
msg->err = udp_sendto(msg->pcb, msg->pb, msg->addr, msg->port);
|
||||
return msg->err;
|
||||
@ -92,11 +93,11 @@ static err_t _udp_sendto(struct udp_pcb *pcb, struct pbuf *pb, const ip_addr_t *
|
||||
msg.addr = addr;
|
||||
msg.port = port;
|
||||
msg.pb = pb;
|
||||
tcpip_api_call(_udp_sendto_api, (struct tcpip_api_call*)&msg);
|
||||
tcpip_api_call(_udp_sendto_api, (struct tcpip_api_call_data*)&msg);
|
||||
return msg.err;
|
||||
}
|
||||
|
||||
static err_t _udp_sendto_if_api(struct tcpip_api_call *api_call_msg){
|
||||
static err_t _udp_sendto_if_api(struct tcpip_api_call_data *api_call_msg){
|
||||
udp_api_call_t * msg = (udp_api_call_t *)api_call_msg;
|
||||
msg->err = udp_sendto_if(msg->pcb, msg->pb, msg->addr, msg->port, msg->netif);
|
||||
return msg->err;
|
||||
@ -109,7 +110,7 @@ static err_t _udp_sendto_if(struct udp_pcb *pcb, struct pbuf *pb, const ip_addr_
|
||||
msg.port = port;
|
||||
msg.pb = pb;
|
||||
msg.netif = netif;
|
||||
tcpip_api_call(_udp_sendto_if_api, (struct tcpip_api_call*)&msg);
|
||||
tcpip_api_call(_udp_sendto_if_api, (struct tcpip_api_call_data*)&msg);
|
||||
return msg.err;
|
||||
}
|
||||
|
||||
@ -131,7 +132,7 @@ static void _udp_task(void *pvParameters){
|
||||
if(xQueueReceive(_udp_queue, &e, portMAX_DELAY) == pdTRUE){
|
||||
if(!e->pb){
|
||||
free((void*)(e));
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
AsyncUDP::_s_recv(e->arg, e->pcb, e->pb, e->addr, e->port, e->netif);
|
||||
free((void*)(e));
|
||||
@ -149,7 +150,7 @@ static bool _udp_task_start(){
|
||||
}
|
||||
}
|
||||
if(!_udp_task_handle){
|
||||
xTaskCreate(_udp_task, "async_udp", 4096, NULL, 3, (TaskHandle_t*)&_udp_task_handle);
|
||||
xTaskCreateUniversal(_udp_task, "async_udp", 4096, NULL, 3, (TaskHandle_t*)&_udp_task_handle, CONFIG_ARDUINO_UDP_RUNNING_CORE);
|
||||
if(!_udp_task_handle){
|
||||
return false;
|
||||
}
|
||||
@ -286,23 +287,29 @@ AsyncUDPPacket::AsyncUDPPacket(AsyncUDP *udp, pbuf *pb, const ip_addr_t *raddr,
|
||||
_len = pb->len;
|
||||
_index = 0;
|
||||
|
||||
pbuf_ref(_pb);
|
||||
|
||||
//memcpy(&_remoteIp, raddr, sizeof(ip_addr_t));
|
||||
_remoteIp.type = raddr->type;
|
||||
_localIp.type = _remoteIp.type;
|
||||
|
||||
eth_hdr* eth = NULL;
|
||||
udp_hdr* udphdr = reinterpret_cast<udp_hdr*>(_data - UDP_HLEN);
|
||||
_localPort = ntohs(udphdr->dest);
|
||||
_remotePort = ntohs(udphdr->src);
|
||||
|
||||
if (_remoteIp.type == IPADDR_TYPE_V4) {
|
||||
eth = (eth_hdr *)(((uint8_t *)(pb->payload)) - UDP_HLEN - IP_HLEN - SIZEOF_ETH_HDR);
|
||||
struct ip_hdr * iphdr = (struct ip_hdr *)(((uint8_t *)(pb->payload)) - UDP_HLEN - IP_HLEN);
|
||||
_localIp.u_addr.ip4.addr = iphdr->dest.addr;
|
||||
_remoteIp.u_addr.ip4.addr = iphdr->src.addr;
|
||||
} else {
|
||||
eth = (eth_hdr *)(((uint8_t *)(pb->payload)) - UDP_HLEN - IP6_HLEN - SIZEOF_ETH_HDR);
|
||||
struct ip6_hdr * ip6hdr = (struct ip6_hdr *)(((uint8_t *)(pb->payload)) - UDP_HLEN - IP6_HLEN);
|
||||
memcpy(&_localIp.u_addr.ip6.addr, (uint8_t *)ip6hdr->dest.addr, 16);
|
||||
memcpy(&_remoteIp.u_addr.ip6.addr, (uint8_t *)ip6hdr->src.addr, 16);
|
||||
}
|
||||
memcpy(_remoteMac, eth->src.addr, 6);
|
||||
|
||||
struct netif * netif = NULL;
|
||||
void * nif = NULL;
|
||||
@ -413,6 +420,11 @@ uint16_t AsyncUDPPacket::remotePort()
|
||||
return _remotePort;
|
||||
}
|
||||
|
||||
void AsyncUDPPacket::remoteMac(uint8_t * mac)
|
||||
{
|
||||
memcpy(mac, _remoteMac, 6);
|
||||
}
|
||||
|
||||
bool AsyncUDPPacket::isIPv6()
|
||||
{
|
||||
return _localIp.type == IPADDR_TYPE_V6;
|
||||
@ -450,16 +462,24 @@ size_t AsyncUDPPacket::send(AsyncUDPMessage &message)
|
||||
return write(message.data(), message.length());
|
||||
}
|
||||
|
||||
AsyncUDP::AsyncUDP()
|
||||
{
|
||||
bool AsyncUDP::_init(){
|
||||
if(_pcb){
|
||||
return true;
|
||||
}
|
||||
_pcb = udp_new();
|
||||
_connected = false;
|
||||
_handler = NULL;
|
||||
if(!_pcb){
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
//_lock = xSemaphoreCreateMutex();
|
||||
udp_recv(_pcb, &_udp_recv, (void *) this);
|
||||
return true;
|
||||
}
|
||||
|
||||
AsyncUDP::AsyncUDP()
|
||||
{
|
||||
_pcb = NULL;
|
||||
_connected = false;
|
||||
_handler = NULL;
|
||||
}
|
||||
|
||||
AsyncUDP::~AsyncUDP()
|
||||
@ -481,8 +501,7 @@ void AsyncUDP::close()
|
||||
_udp_disconnect(_pcb);
|
||||
}
|
||||
_connected = false;
|
||||
_pcb->multicast_ip.type = IPADDR_TYPE_V4;
|
||||
_pcb->multicast_ip.u_addr.ip4.addr = 0;
|
||||
//todo: unjoin multicast group
|
||||
}
|
||||
UDP_MUTEX_UNLOCK();
|
||||
}
|
||||
@ -493,7 +512,7 @@ bool AsyncUDP::connect(const ip_addr_t *addr, uint16_t port)
|
||||
log_e("failed to start task");
|
||||
return false;
|
||||
}
|
||||
if(_pcb == NULL) {
|
||||
if(!_init()) {
|
||||
return false;
|
||||
}
|
||||
close();
|
||||
@ -514,7 +533,7 @@ bool AsyncUDP::listen(const ip_addr_t *addr, uint16_t port)
|
||||
log_e("failed to start task");
|
||||
return false;
|
||||
}
|
||||
if(_pcb == NULL) {
|
||||
if(!_init()) {
|
||||
return false;
|
||||
}
|
||||
close();
|
||||
@ -532,57 +551,75 @@ bool AsyncUDP::listen(const ip_addr_t *addr, uint16_t port)
|
||||
return true;
|
||||
}
|
||||
|
||||
static esp_err_t joinMulticastGroup(const ip_addr_t *addr, bool join, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX)
|
||||
{
|
||||
struct netif * netif = NULL;
|
||||
if(tcpip_if < TCPIP_ADAPTER_IF_MAX){
|
||||
void * nif = NULL;
|
||||
esp_err_t err = tcpip_adapter_get_netif(tcpip_if, &nif);
|
||||
if (err) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
netif = (struct netif *)nif;
|
||||
|
||||
if (addr->type == IPADDR_TYPE_V4) {
|
||||
if(join){
|
||||
if (igmp_joingroup_netif(netif, (const ip4_addr *)&(addr->u_addr.ip4))) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
} else {
|
||||
if (igmp_leavegroup_netif(netif, (const ip4_addr *)&(addr->u_addr.ip4))) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(join){
|
||||
if (mld6_joingroup_netif(netif, &(addr->u_addr.ip6))) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
} else {
|
||||
if (mld6_leavegroup_netif(netif, &(addr->u_addr.ip6))) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (addr->type == IPADDR_TYPE_V4) {
|
||||
if(join){
|
||||
if (igmp_joingroup((const ip4_addr *)IP4_ADDR_ANY, (const ip4_addr *)&(addr->u_addr.ip4))) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
} else {
|
||||
if (igmp_leavegroup((const ip4_addr *)IP4_ADDR_ANY, (const ip4_addr *)&(addr->u_addr.ip4))) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(join){
|
||||
if (mld6_joingroup((const ip6_addr *)IP6_ADDR_ANY, &(addr->u_addr.ip6))) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
} else {
|
||||
if (mld6_leavegroup((const ip6_addr *)IP6_ADDR_ANY, &(addr->u_addr.ip6))) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
bool AsyncUDP::listenMulticast(const ip_addr_t *addr, uint16_t port, uint8_t ttl, tcpip_adapter_if_t tcpip_if)
|
||||
{
|
||||
if(!ip_addr_ismulticast(addr)) {
|
||||
return false;
|
||||
}
|
||||
ip_addr_t multicast_if_addr;
|
||||
uint8_t mode;
|
||||
if(esp_wifi_get_mode((wifi_mode_t*)&mode)){
|
||||
mode = WIFI_MODE_NULL;
|
||||
}
|
||||
|
||||
if(addr->type == IPADDR_TYPE_V6){
|
||||
multicast_if_addr.type = IPADDR_TYPE_V6;
|
||||
|
||||
if((tcpip_if == TCPIP_ADAPTER_IF_STA && (mode & WIFI_MODE_STA))
|
||||
|| (tcpip_if == TCPIP_ADAPTER_IF_AP && (mode & WIFI_MODE_AP))
|
||||
|| (tcpip_if == TCPIP_ADAPTER_IF_ETH)) {
|
||||
if(tcpip_adapter_get_ip6_linklocal(tcpip_if, &multicast_if_addr.u_addr.ip6)){
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (joinMulticastGroup(addr, true, tcpip_if)!= ERR_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mld6_joingroup(&(multicast_if_addr.u_addr.ip6), &(addr->u_addr.ip6))) {
|
||||
return false;
|
||||
}
|
||||
} else if(addr->type == IPADDR_TYPE_V4){
|
||||
tcpip_adapter_ip_info_t ifIpInfo;
|
||||
|
||||
if((tcpip_if == TCPIP_ADAPTER_IF_STA && (mode & WIFI_MODE_STA))
|
||||
|| (tcpip_if == TCPIP_ADAPTER_IF_AP && (mode & WIFI_MODE_AP))
|
||||
|| (tcpip_if == TCPIP_ADAPTER_IF_ETH)) {
|
||||
if(tcpip_adapter_get_ip_info(tcpip_if, &ifIpInfo)){
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
multicast_if_addr.type = IPADDR_TYPE_V4;
|
||||
multicast_if_addr.u_addr.ip4.addr = ifIpInfo.ip.addr;
|
||||
|
||||
if (igmp_joingroup((const ip4_addr *)&multicast_if_addr.u_addr.ip4, (const ip4_addr *)&addr->u_addr.ip4)!= ERR_OK) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!listen(&multicast_if_addr, port)) {
|
||||
if(!listen(NULL, port)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -590,9 +627,7 @@ bool AsyncUDP::listenMulticast(const ip_addr_t *addr, uint16_t port, uint8_t ttl
|
||||
_pcb->mcast_ttl = ttl;
|
||||
_pcb->remote_port = port;
|
||||
ip_addr_copy(_pcb->remote_ip, *addr);
|
||||
if(addr->type == IPADDR_TYPE_V4){
|
||||
ip_addr_copy(_pcb->multicast_ip, multicast_if_addr);
|
||||
}
|
||||
//ip_addr_copy(_pcb->remote_ip, ip_addr_any_type);
|
||||
UDP_MUTEX_UNLOCK();
|
||||
|
||||
return true;
|
||||
@ -602,7 +637,7 @@ size_t AsyncUDP::writeTo(const uint8_t * data, size_t len, const ip_addr_t * add
|
||||
{
|
||||
if(!_pcb) {
|
||||
UDP_MUTEX_LOCK();
|
||||
_pcb = udp_new_ip_type(addr->type);
|
||||
_pcb = udp_new();
|
||||
UDP_MUTEX_UNLOCK();
|
||||
if(_pcb == NULL) {
|
||||
return 0;
|
||||
@ -617,7 +652,7 @@ size_t AsyncUDP::writeTo(const uint8_t * data, size_t len, const ip_addr_t * add
|
||||
uint8_t* dst = reinterpret_cast<uint8_t*>(pbt->payload);
|
||||
memcpy(dst, data, len);
|
||||
UDP_MUTEX_LOCK();
|
||||
if(tcpip_if != TCPIP_ADAPTER_IF_MAX){
|
||||
if(tcpip_if < TCPIP_ADAPTER_IF_MAX){
|
||||
void * nif = NULL;
|
||||
tcpip_adapter_get_netif((tcpip_adapter_if_t)tcpip_if, &nif);
|
||||
if(!nif){
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include <functional>
|
||||
extern "C" {
|
||||
#include "lwip/ip_addr.h"
|
||||
#include <tcpip_adapter.h>
|
||||
#include "esp_netif.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
}
|
||||
@ -53,6 +53,7 @@ protected:
|
||||
uint16_t _localPort;
|
||||
ip_addr_t _remoteIp;
|
||||
uint16_t _remotePort;
|
||||
uint8_t _remoteMac[6];
|
||||
uint8_t *_data;
|
||||
size_t _len;
|
||||
size_t _index;
|
||||
@ -74,6 +75,7 @@ public:
|
||||
IPAddress remoteIP();
|
||||
IPv6Address remoteIPv6();
|
||||
uint16_t remotePort();
|
||||
void remoteMac(uint8_t * mac);
|
||||
|
||||
size_t send(AsyncUDPMessage &message);
|
||||
|
||||
@ -95,6 +97,7 @@ protected:
|
||||
bool _connected;
|
||||
AuPacketHandlerFunction _handler;
|
||||
|
||||
bool _init();
|
||||
void _recv(udp_pcb *upcb, pbuf *pb, const ip_addr_t *addr, uint16_t port, struct netif * netif);
|
||||
|
||||
public:
|
||||
@ -109,9 +112,9 @@ public:
|
||||
bool listen(const IPv6Address addr, uint16_t port);
|
||||
bool listen(uint16_t port);
|
||||
|
||||
bool listenMulticast(const ip_addr_t *addr, uint16_t port, uint8_t ttl=1, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_STA);
|
||||
bool listenMulticast(const IPAddress addr, uint16_t port, uint8_t ttl=1, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_STA);
|
||||
bool listenMulticast(const IPv6Address addr, uint16_t port, uint8_t ttl=1, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_STA);
|
||||
bool listenMulticast(const ip_addr_t *addr, uint16_t port, uint8_t ttl=1, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX);
|
||||
bool listenMulticast(const IPAddress addr, uint16_t port, uint8_t ttl=1, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX);
|
||||
bool listenMulticast(const IPv6Address addr, uint16_t port, uint8_t ttl=1, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX);
|
||||
|
||||
bool connect(const ip_addr_t *addr, uint16_t port);
|
||||
bool connect(const IPAddress addr, uint16_t port);
|
||||
|
Submodule libraries/AzureIoT deleted from 67dfa4f31e
Submodule libraries/BLE deleted from 7951347ed6
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user