mirror of
https://github.com/0xFEEDC0DE64/arduino-esp32.git
synced 2025-06-25 09:51:33 +02:00
Compare commits
374 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 |
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -24,7 +24,7 @@ https://github.com/me-no-dev/EspExceptionDecoder
|
||||
|
||||
### 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?
|
||||
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?
|
||||
|
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
|
||||
}
|
6
package/merge_packages.py → .github/scripts/merge_packages.py
vendored
Normal file → Executable file
6
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:
|
||||
verStr = str(versionString) + '-rc' + str(sys.maxint)
|
||||
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
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +0,0 @@
|
||||
[submodule "libraries/AzureIoT"]
|
||||
path = libraries/AzureIoT
|
||||
url = https://github.com/VSChina/ESP32_AzureIoT_Arduino
|
||||
|
46
.travis.yml
46
.travis.yml
@ -1,8 +1,6 @@
|
||||
sudo: false
|
||||
|
||||
language: python
|
||||
python:
|
||||
- "2.7"
|
||||
|
||||
os:
|
||||
- linux
|
||||
@ -10,22 +8,40 @@ os:
|
||||
git:
|
||||
depth: false
|
||||
|
||||
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
|
||||
|
||||
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:
|
||||
|
@ -15,6 +15,7 @@ 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
|
||||
@ -31,6 +32,8 @@ set(CORE_SRCS
|
||||
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
|
||||
@ -49,6 +52,7 @@ set(LIBRARY_SRCS
|
||||
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
|
||||
@ -71,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
|
||||
@ -78,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
|
||||
@ -170,14 +115,12 @@ 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
|
||||
@ -188,6 +131,7 @@ set(COMPONENT_ADD_INCLUDEDIRS
|
||||
libraries/FS/src
|
||||
libraries/HTTPClient/src
|
||||
libraries/HTTPUpdate/src
|
||||
libraries/LITTLEFS/src
|
||||
libraries/NetBIOS/src
|
||||
libraries/Preferences/src
|
||||
libraries/SD_MMC/src
|
||||
@ -203,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 bt)
|
||||
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"
|
||||
@ -168,6 +241,12 @@ config ARDUINO_SELECTIVE_ESPmDNS
|
||||
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
|
||||
|
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!
|
23
README.md
23
README.md
@ -1,4 +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)
|
||||
|
||||
@ -9,17 +10,12 @@
|
||||
- [Issue/Bug report template](#issuebug-report-template)
|
||||
- [ESP32Dev Board PINMAP](#esp32dev-board-pinmap)
|
||||
|
||||
## Development Status
|
||||
### Development Status
|
||||
[Latest stable release  ](https://github.com/espressif/arduino-esp32/releases/latest/) 
|
||||
|
||||
[Latest development release  ](https://github.com/espressif/arduino-esp32/releases/latest/) 
|
||||
|
||||
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
|
||||
|
||||
## Installation Instructions
|
||||
### 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
|
||||
@ -33,20 +29,19 @@ Most of the framework is implemented. Most noticable is the missing analogWrite.
|
||||
- [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
|
2394
boards.txt
2394
boards.txt
File diff suppressed because it is too large
Load Diff
@ -68,12 +68,6 @@
|
||||
#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 radians(deg) ((deg)*DEG_TO_RAD)
|
||||
#define degrees(rad) ((rad)*RAD_TO_DEG)
|
||||
@ -121,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);
|
||||
|
||||
@ -160,6 +156,7 @@ 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;
|
||||
|
@ -19,7 +19,6 @@
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "Esp.h"
|
||||
#include "rom/spi_flash.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "esp_spi_flash.h"
|
||||
#include <memory>
|
||||
@ -32,6 +31,19 @@ extern "C" {
|
||||
}
|
||||
#include <MD5Builder.h>
|
||||
|
||||
#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
|
||||
* usage:
|
||||
@ -92,13 +104,6 @@ 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();
|
||||
@ -128,24 +133,36 @@ uint32_t EspClass::getMaxAllocHeap(void)
|
||||
|
||||
uint32_t EspClass::getPsramSize(void)
|
||||
{
|
||||
multi_heap_info_t info;
|
||||
heap_caps_get_info(&info, MALLOC_CAP_SPIRAM);
|
||||
return info.total_free_bytes + info.total_allocated_bytes;
|
||||
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)
|
||||
{
|
||||
return heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
|
||||
if(psramFound()){
|
||||
return heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t EspClass::getMinFreePsram(void)
|
||||
{
|
||||
return heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM);
|
||||
if(psramFound()){
|
||||
return heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t EspClass::getMaxAllocPsram(void)
|
||||
{
|
||||
return heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM);
|
||||
if(psramFound()){
|
||||
return heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t sketchSize(sketchSize_t response) {
|
||||
|
@ -75,8 +75,8 @@ public:
|
||||
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);
|
||||
@ -101,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
|
||||
|
@ -16,7 +16,7 @@ extern "C"
|
||||
extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type, bool functional);
|
||||
}
|
||||
|
||||
void IRAM_ATTR interruptFunctional(void* arg)
|
||||
void ARDUINO_ISR_ATTR interruptFunctional(void* arg)
|
||||
{
|
||||
InterruptArgStructure* localArg = (InterruptArgStructure*)arg;
|
||||
if (localArg->interruptFunction)
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include "pins_arduino.h"
|
||||
#include "HardwareSerial.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
#ifndef RX1
|
||||
#define RX1 9
|
||||
#endif
|
||||
@ -22,11 +24,29 @@
|
||||
#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) {}
|
||||
|
||||
@ -40,21 +60,28 @@ 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 = RX1;
|
||||
txPin = TX1;
|
||||
}
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
if(_uart_nr == 2 && rxPin < 0 && txPin < 0) {
|
||||
rxPin = RX2;
|
||||
txPin = TX2;
|
||||
}
|
||||
|
||||
#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))) {
|
||||
@ -100,7 +127,7 @@ void HardwareSerial::setDebugOutput(bool en)
|
||||
uartSetDebug(_uart);
|
||||
} else {
|
||||
if(uartGetDebug() == _uart_nr) {
|
||||
uartSetDebug(0);
|
||||
uartSetDebug(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -130,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);
|
||||
|
@ -62,10 +62,19 @@ public:
|
||||
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));
|
||||
@ -97,10 +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);
|
||||
}
|
||||
len = vsnprintf(temp, len+1, format, arg);
|
||||
write((uint8_t*)temp, len);
|
||||
va_end(arg);
|
||||
if(len >= sizeof(loc_buf)){
|
||||
delete[] temp;
|
||||
len = write((uint8_t*)temp, len);
|
||||
if(temp != loc_buf){
|
||||
free(temp);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
@ -154,8 +159,10 @@ size_t Print::print(struct tm * timeinfo, const char * format)
|
||||
}
|
||||
char buf[64];
|
||||
size_t written = strftime(buf, 64, f, timeinfo);
|
||||
print(buf);
|
||||
return written;
|
||||
if(written == 0){
|
||||
return written;
|
||||
}
|
||||
return print(buf);
|
||||
}
|
||||
|
||||
size_t Print::println(void)
|
||||
|
@ -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 */
|
@ -65,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,295 +36,327 @@ 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
|
||||
{
|
||||
// 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
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
// constructors
|
||||
// creates a copy of the initial value.
|
||||
// if the initial value is null or invalid, or if memory allocation
|
||||
// fails, the string will be marked as invalid (i.e. "if (s)" will
|
||||
// be false).
|
||||
String(const char *cstr = "");
|
||||
String(const String &str);
|
||||
String(const __FlashStringHelper *str) : String(reinterpret_cast<const char *>(str)) {};
|
||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
||||
String(String &&rval);
|
||||
String(StringSumHelper &&rval);
|
||||
#endif
|
||||
explicit String(char c);
|
||||
explicit String(unsigned char, unsigned char base = 10);
|
||||
explicit String(int, unsigned char base = 10);
|
||||
explicit String(unsigned int, unsigned char base = 10);
|
||||
explicit String(long, unsigned char base = 10);
|
||||
explicit String(unsigned long, unsigned char base = 10);
|
||||
explicit String(float, unsigned char decimalPlaces = 2);
|
||||
explicit String(double, unsigned char decimalPlaces = 2);
|
||||
~String(void);
|
||||
|
||||
// memory management
|
||||
// return true on success, false on failure (in which case, the string
|
||||
// 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;
|
||||
} else {
|
||||
return 0;
|
||||
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 {
|
||||
}
|
||||
}
|
||||
|
||||
// creates a copy of the assigned value. if the value is null or
|
||||
// invalid, or if the memory allocation fails, the string will be
|
||||
// marked as invalid ("if (s)" will be false).
|
||||
String & operator =(const String &rhs);
|
||||
String & operator =(const char *cstr);
|
||||
String & operator = (const __FlashStringHelper *str);
|
||||
public:
|
||||
// constructors
|
||||
// creates a copy of the initial value.
|
||||
// if the initial value is null or invalid, or if memory allocation
|
||||
// fails, the string will be marked as invalid (i.e. "if (s)" will
|
||||
// be false).
|
||||
String(const char *cstr = "");
|
||||
String(const String &str);
|
||||
String(const __FlashStringHelper *str);
|
||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
||||
String & operator =(String &&rval);
|
||||
String & operator =(StringSumHelper &&rval);
|
||||
String(String &&rval);
|
||||
String(StringSumHelper &&rval);
|
||||
#endif
|
||||
explicit String(char c);
|
||||
explicit String(unsigned char, unsigned char base = 10);
|
||||
explicit String(int, unsigned char base = 10);
|
||||
explicit String(unsigned int, unsigned char base = 10);
|
||||
explicit String(long, unsigned char base = 10);
|
||||
explicit String(unsigned long, unsigned char base = 10);
|
||||
explicit String(float, unsigned char decimalPlaces = 2);
|
||||
explicit String(double, unsigned char decimalPlaces = 2);
|
||||
~String(void);
|
||||
|
||||
// memory management
|
||||
// return true on success, false on failure (in which case, the string
|
||||
// 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();
|
||||
} 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
|
||||
// marked as invalid ("if (s)" will be false).
|
||||
String & operator =(const String &rhs);
|
||||
String & operator =(const char *cstr);
|
||||
String & operator = (const __FlashStringHelper *str);
|
||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
||||
String & operator =(String &&rval);
|
||||
String & operator =(StringSumHelper &&rval);
|
||||
#endif
|
||||
|
||||
// concatenate (works w/ built-in types)
|
||||
// concatenate (works w/ built-in types)
|
||||
|
||||
// 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.
|
||||
unsigned char concat(const String &str);
|
||||
unsigned char concat(const char *cstr);
|
||||
unsigned char concat(char c);
|
||||
unsigned char concat(unsigned char c);
|
||||
unsigned char concat(int num);
|
||||
unsigned char concat(unsigned int num);
|
||||
unsigned char concat(long num);
|
||||
unsigned char concat(unsigned long num);
|
||||
unsigned char concat(float num);
|
||||
unsigned char concat(double num);
|
||||
unsigned char concat(const __FlashStringHelper * str);
|
||||
// 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 unsuccessful.
|
||||
unsigned char concat(const String &str);
|
||||
unsigned char concat(const char *cstr);
|
||||
unsigned char concat(char c);
|
||||
unsigned char concat(unsigned char c);
|
||||
unsigned char concat(int num);
|
||||
unsigned char concat(unsigned int num);
|
||||
unsigned char concat(long num);
|
||||
unsigned char concat(unsigned long num);
|
||||
unsigned char concat(float num);
|
||||
unsigned char concat(double num);
|
||||
unsigned char concat(const __FlashStringHelper * str);
|
||||
|
||||
// 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)
|
||||
{
|
||||
concat(rhs);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(const char *cstr)
|
||||
{
|
||||
concat(cstr);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(char c)
|
||||
{
|
||||
concat(c);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(unsigned char num)
|
||||
{
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(int num)
|
||||
{
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(unsigned int num)
|
||||
{
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(long num)
|
||||
{
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(unsigned long num)
|
||||
{
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(float num)
|
||||
{
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(double num)
|
||||
{
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator += (const __FlashStringHelper *str)
|
||||
{
|
||||
concat(str);
|
||||
return (*this);
|
||||
}
|
||||
// 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) {
|
||||
concat(rhs);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(const char *cstr) {
|
||||
concat(cstr);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(char c) {
|
||||
concat(c);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(unsigned char num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(int num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(unsigned int num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(long num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(unsigned long num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(float num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(double num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator += (const __FlashStringHelper *str){
|
||||
concat(str);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, const String &rhs);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, const char *cstr);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, char c);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned char num);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, int num);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned int num);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, long num);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned long num);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, float num);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, double num);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, const __FlashStringHelper *rhs);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, const String &rhs);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, const char *cstr);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, char c);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned char num);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, int num);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned int num);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, long num);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned long num);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, float num);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, double num);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, const __FlashStringHelper *rhs);
|
||||
|
||||
// comparison (only works w/ Strings and "strings")
|
||||
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
|
||||
{
|
||||
return equals(rhs);
|
||||
}
|
||||
unsigned char operator ==(const char *cstr) const
|
||||
{
|
||||
return equals(cstr);
|
||||
}
|
||||
unsigned char operator !=(const String &rhs) const
|
||||
{
|
||||
return !equals(rhs);
|
||||
}
|
||||
unsigned char operator !=(const char *cstr) const
|
||||
{
|
||||
return !equals(cstr);
|
||||
}
|
||||
unsigned char operator <(const String &rhs) const;
|
||||
unsigned char operator >(const String &rhs) const;
|
||||
unsigned char operator <=(const String &rhs) const;
|
||||
unsigned char operator >=(const String &rhs) const;
|
||||
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 String &prefix, unsigned int offset) const;
|
||||
unsigned char endsWith(const String &suffix) const;
|
||||
// comparison (only works w/ Strings and "strings")
|
||||
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 {
|
||||
return equals(rhs);
|
||||
}
|
||||
unsigned char operator ==(const char *cstr) const {
|
||||
return equals(cstr);
|
||||
}
|
||||
unsigned char operator !=(const String &rhs) const {
|
||||
return !equals(rhs);
|
||||
}
|
||||
unsigned char operator !=(const char *cstr) const {
|
||||
return !equals(cstr);
|
||||
}
|
||||
unsigned char operator <(const String &rhs) const;
|
||||
unsigned char operator >(const String &rhs) const;
|
||||
unsigned char operator <=(const String &rhs) const;
|
||||
unsigned char operator >=(const String &rhs) const;
|
||||
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
|
||||
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
|
||||
{
|
||||
getBytes((unsigned char *) buf, bufsize, index);
|
||||
}
|
||||
const char * c_str() const
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
// 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 {
|
||||
getBytes((unsigned char *) buf, bufsize, index);
|
||||
}
|
||||
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;
|
||||
int indexOf(char ch, unsigned int fromIndex) const;
|
||||
int indexOf(const String &str) const;
|
||||
int indexOf(const String &str, unsigned int fromIndex) const;
|
||||
int lastIndexOf(char ch) const;
|
||||
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, unsigned int endIndex) const;
|
||||
// search
|
||||
int indexOf(char ch) const;
|
||||
int indexOf(char ch, unsigned int fromIndex) const;
|
||||
int indexOf(const String &str) const;
|
||||
int indexOf(const String &str, unsigned int fromIndex) const;
|
||||
int lastIndexOf(char ch) const;
|
||||
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, unsigned int endIndex) const;
|
||||
|
||||
// modification
|
||||
void replace(char find, char replace);
|
||||
void replace(const String& find, const String& replace);
|
||||
void remove(unsigned int index);
|
||||
void remove(unsigned int index, unsigned int count);
|
||||
void toLowerCase(void);
|
||||
void toUpperCase(void);
|
||||
void trim(void);
|
||||
// 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);
|
||||
void toUpperCase(void);
|
||||
void trim(void);
|
||||
|
||||
// parsing/conversion
|
||||
long toInt(void) const;
|
||||
float toFloat(void) const;
|
||||
double toDouble(void) const;
|
||||
// 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')
|
||||
protected:
|
||||
void init(void);
|
||||
void invalidate(void);
|
||||
unsigned char changeBuffer(unsigned int maxStrLen);
|
||||
unsigned char concat(const char *cstr, unsigned int length);
|
||||
protected:
|
||||
// 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
|
||||
|
||||
// copy and move
|
||||
String & copy(const char *cstr, unsigned int length);
|
||||
String & copy(const __FlashStringHelper *pstr, unsigned int length);
|
||||
protected:
|
||||
void init(void);
|
||||
void invalidate(void);
|
||||
unsigned char changeBuffer(unsigned int maxStrLen);
|
||||
unsigned char concat(const char *cstr, unsigned int length);
|
||||
|
||||
// copy and move
|
||||
String & copy(const char *cstr, unsigned int length);
|
||||
String & copy(const __FlashStringHelper *pstr, unsigned int length);
|
||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
||||
void move(String &rhs);
|
||||
void move(String &rhs);
|
||||
#endif
|
||||
};
|
||||
|
||||
class StringSumHelper: public String
|
||||
{
|
||||
public:
|
||||
StringSumHelper(const String &s) :
|
||||
String(s)
|
||||
{
|
||||
}
|
||||
StringSumHelper(const char *p) :
|
||||
String(p)
|
||||
{
|
||||
}
|
||||
StringSumHelper(char c) :
|
||||
String(c)
|
||||
{
|
||||
}
|
||||
StringSumHelper(unsigned char num) :
|
||||
String(num)
|
||||
{
|
||||
}
|
||||
StringSumHelper(int num) :
|
||||
String(num)
|
||||
{
|
||||
}
|
||||
StringSumHelper(unsigned int num) :
|
||||
String(num)
|
||||
{
|
||||
}
|
||||
StringSumHelper(long num) :
|
||||
String(num)
|
||||
{
|
||||
}
|
||||
StringSumHelper(unsigned long num) :
|
||||
String(num)
|
||||
{
|
||||
}
|
||||
StringSumHelper(float num) :
|
||||
String(num)
|
||||
{
|
||||
}
|
||||
StringSumHelper(double num) :
|
||||
String(num)
|
||||
{
|
||||
}
|
||||
class StringSumHelper: public String {
|
||||
public:
|
||||
StringSumHelper(const String &s) :
|
||||
String(s) {
|
||||
}
|
||||
StringSumHelper(const char *p) :
|
||||
String(p) {
|
||||
}
|
||||
StringSumHelper(char c) :
|
||||
String(c) {
|
||||
}
|
||||
StringSumHelper(unsigned char num) :
|
||||
String(num) {
|
||||
}
|
||||
StringSumHelper(int num) :
|
||||
String(num) {
|
||||
}
|
||||
StringSumHelper(unsigned int num) :
|
||||
String(num) {
|
||||
}
|
||||
StringSumHelper(long num) :
|
||||
String(num) {
|
||||
}
|
||||
StringSumHelper(unsigned long num) :
|
||||
String(num) {
|
||||
}
|
||||
StringSumHelper(float num) :
|
||||
String(num) {
|
||||
}
|
||||
StringSumHelper(double num) :
|
||||
String(num) {
|
||||
}
|
||||
};
|
||||
|
||||
extern const String emptyString;
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // String_class_h
|
||||
|
@ -31,11 +31,11 @@ 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)
|
||||
{
|
||||
size_t size = base64_encode_expected_len(length) + 1;
|
||||
char * buffer = (char *) malloc(size);
|
||||
@ -54,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);
|
||||
|
||||
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);
|
||||
adc1_config_width(__analogWidth);
|
||||
}
|
||||
#endif
|
||||
|
||||
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");
|
||||
|
@ -21,18 +21,31 @@
|
||||
#include "esp_log.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "rom/rtc.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;
|
||||
|
||||
const uint32_t MHZ = 1000000;
|
||||
|
||||
static apb_change_t * apb_change_callbacks = NULL;
|
||||
static xSemaphoreHandle apb_change_lock = NULL;
|
||||
@ -52,9 +65,19 @@ static void triggerApbChangeCallback(apb_change_ev_t ev_type, uint32_t old_apb,
|
||||
initApbChangeCallback();
|
||||
xSemaphoreTake(apb_change_lock, portMAX_DELAY);
|
||||
apb_change_t * r = apb_change_callbacks;
|
||||
while(r != NULL){
|
||||
r->cb(r->arg, ev_type, old_apb, new_apb);
|
||||
r=r->next;
|
||||
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);
|
||||
}
|
||||
@ -67,6 +90,7 @@ bool addApbChangeCallback(void * arg, apb_change_cb_t cb){
|
||||
return false;
|
||||
}
|
||||
c->next = NULL;
|
||||
c->prev = NULL;
|
||||
c->arg = arg;
|
||||
c->cb = cb;
|
||||
xSemaphoreTake(apb_change_lock, portMAX_DELAY);
|
||||
@ -74,18 +98,20 @@ bool addApbChangeCallback(void * arg, apb_change_cb_t cb){
|
||||
apb_change_callbacks = c;
|
||||
} else {
|
||||
apb_change_t * r = apb_change_callbacks;
|
||||
if(r->cb != cb || r->arg != arg){
|
||||
while(r->next){
|
||||
r = r->next;
|
||||
if(r->cb == cb && r->arg == arg){
|
||||
free(c);
|
||||
goto unlock_and_exit;
|
||||
}
|
||||
}
|
||||
r->next = c;
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
unlock_and_exit:
|
||||
xSemaphoreGive(apb_change_lock);
|
||||
return true;
|
||||
}
|
||||
@ -94,24 +120,21 @@ bool removeApbChangeCallback(void * arg, apb_change_cb_t cb){
|
||||
initApbChangeCallback();
|
||||
xSemaphoreTake(apb_change_lock, portMAX_DELAY);
|
||||
apb_change_t * r = apb_change_callbacks;
|
||||
if(r == NULL){
|
||||
// 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;
|
||||
}
|
||||
if(r->cb == cb && r->arg == arg){
|
||||
apb_change_callbacks = r->next;
|
||||
}
|
||||
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);
|
||||
} else {
|
||||
while(r->next && (r->next->cb != cb || r->next->arg != arg)){
|
||||
r = r->next;
|
||||
}
|
||||
if(r->next == NULL || r->next->cb != cb || r->next->arg != arg){
|
||||
xSemaphoreGive(apb_change_lock);
|
||||
return false;
|
||||
}
|
||||
apb_change_t * c = r->next;
|
||||
r->next = c->next;
|
||||
free(c);
|
||||
}
|
||||
xSemaphoreGive(apb_change_lock);
|
||||
return true;
|
||||
@ -131,6 +154,7 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz){
|
||||
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)){
|
||||
@ -142,6 +166,7 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz){
|
||||
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);
|
||||
@ -150,6 +175,17 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz){
|
||||
}
|
||||
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
|
||||
@ -176,7 +212,7 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz){
|
||||
//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
|
||||
|
@ -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,14 +84,64 @@ 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);
|
||||
@ -76,56 +151,57 @@ typedef struct {
|
||||
void* arg;
|
||||
bool functional;
|
||||
} InterruptHandle_t;
|
||||
static InterruptHandle_t __pinInterruptHandlers[GPIO_PIN_COUNT] = {0,};
|
||||
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);
|
||||
@ -133,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 {
|
||||
@ -153,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);
|
||||
}
|
||||
@ -167,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;
|
||||
@ -199,7 +281,7 @@ extern int IRAM_ATTR __digitalRead(uint8_t pin)
|
||||
|
||||
static intr_handle_t gpio_intr_handle = NULL;
|
||||
|
||||
static void IRAM_ATTR __onPinInterrupt()
|
||||
static void ARDUINO_ISR_ATTR __onPinInterrupt()
|
||||
{
|
||||
uint32_t gpio_intr_status_l=0;
|
||||
uint32_t gpio_intr_status_h=0;
|
||||
@ -247,7 +329,7 @@ extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc,
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// if new attach without detach remove old info
|
||||
@ -260,11 +342,15 @@ extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc,
|
||||
__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);
|
||||
}
|
||||
|
@ -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,15 +75,15 @@ 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);
|
||||
|
@ -18,13 +18,28 @@
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "soc/i2c_reg.h"
|
||||
#include "soc/i2c_struct.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp32-hal-cpu.h" // cpu clock change support 31DEC2018
|
||||
|
||||
#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_IDF_TARGET_ESP32
|
||||
//#define I2C_DEV(i) (volatile i2c_dev_t *)((i)?DR_REG_I2C1_EXT_BASE:DR_REG_I2C_EXT_BASE)
|
||||
//#define I2C_DEV(i) ((i2c_dev_t *)(REG_I2C_BASE(i)))
|
||||
#define I2C_SCL_IDX(p) ((p==0)?I2CEXT0_SCL_OUT_IDX:((p==1)?I2CEXT1_SCL_OUT_IDX:0))
|
||||
@ -227,7 +242,7 @@ static i2c_t _i2c_bus_array[2] = {
|
||||
|
||||
/* Stickbreaker ISR mode debug support
|
||||
*/
|
||||
static void IRAM_ATTR i2cDumpCmdQueue(i2c_t *i2c)
|
||||
static void ARDUINO_ISR_ATTR i2cDumpCmdQueue(i2c_t *i2c)
|
||||
{
|
||||
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR)&&(defined ENABLE_I2C_DEBUG_BUFFER)
|
||||
static const char * const cmdName[] ={"RSTART","WRITE","READ","STOP","END"};
|
||||
@ -357,7 +372,7 @@ static void i2cDumpInts(uint8_t num)
|
||||
#endif
|
||||
|
||||
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)&&(defined ENABLE_I2C_DEBUG_BUFFER)
|
||||
static void IRAM_ATTR i2cDumpStatus(i2c_t * i2c){
|
||||
static void ARDUINO_ISR_ATTR i2cDumpStatus(i2c_t * i2c){
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t ack_rec: 1; /*This register stores the value of ACK bit.*/
|
||||
@ -431,7 +446,7 @@ if(i != fifoPos){// actual data
|
||||
}
|
||||
#endif
|
||||
|
||||
static void IRAM_ATTR i2cTriggerDumps(i2c_t * i2c, uint8_t trigger, const char locus[]){
|
||||
static void ARDUINO_ISR_ATTR i2cTriggerDumps(i2c_t * i2c, uint8_t trigger, const char locus[]){
|
||||
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)&&(defined ENABLE_I2C_DEBUG_BUFFER)
|
||||
if( trigger ){
|
||||
log_i("%s",locus);
|
||||
@ -478,7 +493,7 @@ static void i2cApbChangeCallback(void * arg, apb_change_ev_t ev_type, uint32_t o
|
||||
}
|
||||
/* End of CPU Clock change Support
|
||||
*/
|
||||
static void IRAM_ATTR i2cSetCmd(i2c_t * i2c, uint8_t index, uint8_t op_code, uint8_t byte_num, bool ack_val, bool ack_exp, bool ack_check)
|
||||
static void ARDUINO_ISR_ATTR i2cSetCmd(i2c_t * i2c, uint8_t index, uint8_t op_code, uint8_t byte_num, bool ack_val, bool ack_exp, bool ack_check)
|
||||
{
|
||||
I2C_COMMAND_t cmd;
|
||||
cmd.val=0;
|
||||
@ -491,7 +506,7 @@ static void IRAM_ATTR i2cSetCmd(i2c_t * i2c, uint8_t index, uint8_t op_code, uin
|
||||
}
|
||||
|
||||
|
||||
static void IRAM_ATTR fillCmdQueue(i2c_t * i2c, bool INTS)
|
||||
static void ARDUINO_ISR_ATTR fillCmdQueue(i2c_t * i2c, bool INTS)
|
||||
{
|
||||
/* this function is called on initial i2cProcQueue() or when a I2C_END_DETECT_INT occurs
|
||||
*/
|
||||
@ -649,7 +664,7 @@ static void IRAM_ATTR fillCmdQueue(i2c_t * i2c, bool INTS)
|
||||
}
|
||||
}
|
||||
|
||||
static void IRAM_ATTR fillTxFifo(i2c_t * i2c)
|
||||
static void ARDUINO_ISR_ATTR fillTxFifo(i2c_t * i2c)
|
||||
{
|
||||
/*
|
||||
12/01/2017 The Fifo's are independent, 32 bytes of tx and 32 bytes of Rx.
|
||||
@ -741,7 +756,7 @@ static void IRAM_ATTR fillTxFifo(i2c_t * i2c)
|
||||
}
|
||||
|
||||
|
||||
static void IRAM_ATTR emptyRxFifo(i2c_t * i2c)
|
||||
static void ARDUINO_ISR_ATTR emptyRxFifo(i2c_t * i2c)
|
||||
{
|
||||
uint32_t d, cnt=0, moveCnt;
|
||||
|
||||
@ -800,7 +815,7 @@ static void IRAM_ATTR emptyRxFifo(i2c_t * i2c)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void IRAM_ATTR i2cIsrExit(i2c_t * i2c,const uint32_t eventCode,bool Fatal)
|
||||
static void ARDUINO_ISR_ATTR i2cIsrExit(i2c_t * i2c,const uint32_t eventCode,bool Fatal)
|
||||
{
|
||||
|
||||
switch(eventCode) {
|
||||
@ -845,7 +860,7 @@ static void IRAM_ATTR i2cIsrExit(i2c_t * i2c,const uint32_t eventCode,bool Fatal
|
||||
|
||||
}
|
||||
|
||||
static void IRAM_ATTR i2c_update_error_byte_cnt(i2c_t * i2c)
|
||||
static void ARDUINO_ISR_ATTR i2c_update_error_byte_cnt(i2c_t * i2c)
|
||||
{
|
||||
/* i2c_update_error_byte_cnt 07/18/2018
|
||||
Only called after an error has occurred, so, most of the time this function is never used.
|
||||
@ -892,7 +907,7 @@ static void IRAM_ATTR i2c_update_error_byte_cnt(i2c_t * i2c)
|
||||
i2c->errorByteCnt = bc;
|
||||
}
|
||||
|
||||
static void IRAM_ATTR i2c_isr_handler_default(void* arg)
|
||||
static void ARDUINO_ISR_ATTR i2c_isr_handler_default(void* arg)
|
||||
{
|
||||
i2c_t* p_i2c = (i2c_t*) arg; // recover data
|
||||
uint32_t activeInt = p_i2c->dev->int_status.val&0x7FF;
|
||||
@ -1239,7 +1254,7 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis)
|
||||
if(!i2c->intr_handle) { // create ISR for either peripheral
|
||||
// log_i("create ISR %d",i2c->num);
|
||||
uint32_t ret = 0;
|
||||
uint32_t flags = ESP_INTR_FLAG_IRAM | //< ISR can be called if cache is disabled
|
||||
uint32_t flags = ARDUINO_ISR_FLAG | //< ISR can be called if cache is disabled
|
||||
ESP_INTR_FLAG_LOWMED | //< Low and medium prio interrupts. These can be handled in C.
|
||||
ESP_INTR_FLAG_SHARED; //< Reduce resource requirements, Share interrupts
|
||||
|
||||
@ -1270,7 +1285,7 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis)
|
||||
|
||||
i2c->dev->ctr.trans_start=1; // go for it
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
|
||||
portTickType tBefore=xTaskGetTickCount();
|
||||
#endif
|
||||
|
||||
@ -1278,7 +1293,7 @@ i2c_err_t i2cProcQueue(i2c_t * i2c, uint32_t *readCount, uint16_t timeOutMillis)
|
||||
|
||||
uint32_t eBits = xEventGroupWaitBits(i2c->i2c_event,EVENT_DONE,pdFALSE,pdTRUE,ticksTimeOut);
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
|
||||
portTickType tAfter=xTaskGetTickCount();
|
||||
#endif
|
||||
|
||||
@ -1757,7 +1772,133 @@ uint32_t i2cGetStatus(i2c_t * i2c){
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
#else
|
||||
#include "driver/i2c.h"
|
||||
|
||||
#define ACK_CHECK_EN 1 /*!< I2C master will check ack from slave*/
|
||||
#define ACK_CHECK_DIS 0 /*!< I2C master will not check ack from slave */
|
||||
#define ACK_VAL 0x0 /*!< I2C ack value */
|
||||
#define NACK_VAL 0x1 /*!< I2C nack value */
|
||||
|
||||
struct i2c_struct_t {
|
||||
i2c_port_t num;
|
||||
};
|
||||
|
||||
static i2c_t * i2c_ports[2] = {NULL, NULL};
|
||||
|
||||
i2c_t * i2cInit(uint8_t i2c_num, int8_t sda, int8_t scl, uint32_t clk_speed){
|
||||
if(i2c_num >= 2){
|
||||
return NULL;
|
||||
}
|
||||
i2c_t * out = NULL;
|
||||
if(i2c_ports[i2c_num] == NULL){
|
||||
out = (i2c_t*)malloc(sizeof(i2c_t));
|
||||
if(out == NULL){
|
||||
log_e("malloc failed");
|
||||
return NULL;
|
||||
}
|
||||
out->num = (i2c_port_t)i2c_num;
|
||||
i2c_ports[i2c_num] = out;
|
||||
} else {
|
||||
out = i2c_ports[i2c_num];
|
||||
i2c_driver_delete((i2c_port_t)i2c_num);
|
||||
}
|
||||
|
||||
i2c_config_t conf;
|
||||
conf.mode = I2C_MODE_MASTER;
|
||||
conf.scl_io_num = (gpio_num_t)scl;
|
||||
conf.sda_io_num = (gpio_num_t)sda;
|
||||
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
|
||||
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
|
||||
conf.master.clk_speed = clk_speed;
|
||||
esp_err_t ret = i2c_param_config(out->num, &conf);
|
||||
if (ret != ESP_OK) {
|
||||
log_e("i2c_param_config failed");
|
||||
free(out);
|
||||
i2c_ports[i2c_num] = NULL;
|
||||
return NULL;
|
||||
}
|
||||
ret = i2c_driver_install(out->num, conf.mode, 0, 0, 0);
|
||||
if (ret != ESP_OK) {
|
||||
log_e("i2c_driver_install failed");
|
||||
free(out);
|
||||
i2c_ports[i2c_num] = NULL;
|
||||
return NULL;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
i2c_err_t i2cWrite(i2c_t * i2c, uint16_t address, uint8_t* buff, uint16_t size, bool sendStop, uint16_t timeOutMillis){
|
||||
esp_err_t ret = ESP_OK;
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (address << 1) | I2C_MASTER_WRITE, ACK_CHECK_EN);
|
||||
i2c_master_write(cmd, buff, size, ACK_CHECK_EN);
|
||||
//if send stop?
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(i2c->num, cmd, timeOutMillis / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
i2c_err_t i2cRead(i2c_t * i2c, uint16_t address, uint8_t* buff, uint16_t size, bool sendStop, uint16_t timeOutMillis, uint32_t *readCount){
|
||||
esp_err_t ret = ESP_OK;
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (address << 1) | I2C_MASTER_READ, ACK_CHECK_EN);
|
||||
if (size > 1) {
|
||||
i2c_master_read(cmd, buff, size - 1, ACK_VAL);
|
||||
}
|
||||
i2c_master_read_byte(cmd, buff + size - 1, NACK_VAL);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(i2c->num, cmd, timeOutMillis / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret == ESP_OK){
|
||||
*readCount = size;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void i2cRelease(i2c_t *i2c){
|
||||
log_w("");
|
||||
return;
|
||||
}
|
||||
i2c_err_t i2cFlush(i2c_t *i2c){
|
||||
esp_err_t ret = i2c_reset_tx_fifo(i2c->num);
|
||||
if(ret != ESP_OK){
|
||||
return ret;
|
||||
}
|
||||
return i2c_reset_rx_fifo(i2c->num);
|
||||
}
|
||||
i2c_err_t i2cSetFrequency(i2c_t * i2c, uint32_t clk_speed){
|
||||
log_w("");
|
||||
return ESP_OK;
|
||||
}
|
||||
uint32_t i2cGetFrequency(i2c_t * i2c){
|
||||
log_w("");
|
||||
return 0;
|
||||
}
|
||||
uint32_t i2cGetStatus(i2c_t * i2c){
|
||||
log_w("");
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Functions below should be used only if well understood
|
||||
//Might be deprecated and removed in future
|
||||
i2c_err_t i2cAttachSCL(i2c_t * i2c, int8_t scl){
|
||||
return ESP_FAIL;
|
||||
}
|
||||
i2c_err_t i2cDetachSCL(i2c_t * i2c, int8_t scl){
|
||||
return ESP_FAIL;
|
||||
}
|
||||
i2c_err_t i2cAttachSDA(i2c_t * i2c, int8_t sda){
|
||||
return ESP_FAIL;
|
||||
}
|
||||
i2c_err_t i2cDetachSDA(i2c_t * i2c, int8_t sda){
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IDF_TARGET_ESP32 */
|
||||
|
||||
/* todo
|
||||
22JUL18
|
||||
|
@ -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
|
||||
|
||||
/*
|
||||
@ -55,27 +70,35 @@ xSemaphoreHandle _ledc_sys_lock;
|
||||
|
||||
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){
|
||||
uint32_t iarg = (uint32_t)arg;
|
||||
uint8_t chan = iarg;
|
||||
uint8_t group=(chan/8), timer=((chan/2)%4);
|
||||
uint16_t iarg = *(uint16_t*)arg;
|
||||
uint8_t chan = 0;
|
||||
old_apb /= 1000000;
|
||||
new_apb /= 1000000;
|
||||
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){
|
||||
new_apb = REF_CLK_FREQ / 1000000;
|
||||
div_num = (new_apb * old_div) / old_apb;
|
||||
if(div_num > LEDC_DIV_NUM_HSTIMER0_V) {
|
||||
div_num = LEDC_DIV_NUM_HSTIMER0_V;//lowest clock possible
|
||||
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);
|
||||
}
|
||||
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();
|
||||
iarg = iarg >> 1;
|
||||
chan++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -85,11 +108,14 @@ static void _ledcSetupTimer(uint8_t chan, uint32_t div_num, uint8_t bit_num, boo
|
||||
{
|
||||
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
|
||||
@ -98,15 +124,18 @@ 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();
|
||||
uint32_t iarg = chan;
|
||||
addApbChangeCallback((void*)iarg, _on_apb_change);
|
||||
_activeChannels |= (1 << chan); // mark as active for APB callback
|
||||
}
|
||||
|
||||
//max div_num 0x3FFFF (262143)
|
||||
@ -166,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) {
|
||||
#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);
|
||||
@ -186,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);
|
||||
@ -195,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) {
|
||||
#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) {
|
||||
#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;
|
||||
@ -230,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) {
|
||||
@ -257,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,7 +76,7 @@ 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__)
|
||||
|
@ -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);
|
||||
}
|
||||
*/
|
||||
|
@ -31,10 +31,22 @@
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/apb_ctrl_reg.h"
|
||||
#include "rom/rtc.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
|
||||
uint8_t temprature_sens_read();
|
||||
@ -44,11 +56,13 @@ float temperatureRead()
|
||||
return (temprature_sens_read() - 32) / 1.8;
|
||||
}
|
||||
|
||||
void yield()
|
||||
void __yield()
|
||||
{
|
||||
vPortYield();
|
||||
}
|
||||
|
||||
void yield() __attribute__ ((weak, alias("__yield")));
|
||||
|
||||
#if CONFIG_AUTOSTART_ARDUINO
|
||||
|
||||
extern TaskHandle_t loopTaskHandle;
|
||||
@ -111,12 +125,30 @@ void disableCore1WDT(){
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned long IRAM_ATTR micros()
|
||||
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());
|
||||
}
|
||||
|
||||
unsigned long IRAM_ATTR millis()
|
||||
unsigned long ARDUINO_ISR_ATTR millis()
|
||||
{
|
||||
return (unsigned long) (esp_timer_get_time() / 1000ULL);
|
||||
}
|
||||
@ -126,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){
|
||||
@ -178,7 +210,7 @@ void initArduino()
|
||||
#ifdef F_CPU
|
||||
setCpuFrequencyMhz(F_CPU/1000000);
|
||||
#endif
|
||||
#if CONFIG_SPIRAM_SUPPORT
|
||||
#if CONFIG_SPIRAM_SUPPORT || CONFIG_SPIRAM
|
||||
psramInit();
|
||||
#endif
|
||||
esp_log_level_set("*", CONFIG_LOG_DEFAULT_LEVEL);
|
||||
@ -207,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,11 +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"
|
||||
|
||||
#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;
|
||||
|
||||
@ -17,6 +43,7 @@ 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) {
|
||||
@ -25,13 +52,21 @@ bool psramInit(){
|
||||
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!");
|
||||
@ -42,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;
|
||||
}
|
||||
@ -79,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;
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,17 @@
|
||||
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();
|
||||
|
||||
|
@ -19,18 +19,20 @@
|
||||
#include "esp32-hal.h"
|
||||
#include "esp8266-compat.h"
|
||||
#include "soc/gpio_reg.h"
|
||||
#include "soc/gpio_reg.h"
|
||||
|
||||
#include "esp32-hal-rmt.h"
|
||||
#include "driver/periph_ctrl.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)
|
||||
@ -100,7 +102,10 @@ struct rmt_obj_s
|
||||
* Internal variables for channel descriptors
|
||||
*/
|
||||
static xSemaphoreHandle g_rmt_objlocks[MAX_CHANNELS] = {
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
|
||||
NULL, NULL, NULL, NULL,
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
NULL, NULL, NULL, NULL
|
||||
#endif
|
||||
};
|
||||
|
||||
static rmt_obj_t g_rmt_objects[MAX_CHANNELS] = {
|
||||
@ -108,10 +113,12 @@ 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},
|
||||
#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
|
||||
};
|
||||
|
||||
/**
|
||||
@ -128,19 +135,19 @@ static xSemaphoreHandle g_rmt_block_lock = NULL;
|
||||
*/
|
||||
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);
|
||||
static bool _rmtSendOnce(rmt_obj_t* rmt, rmt_data_t* data, size_t size, bool continuous);
|
||||
|
||||
static void IRAM_ATTR _rmt_isr(void* arg);
|
||||
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 IRAM_ATTR _rmt_get_mem_len(uint8_t channel);
|
||||
static int ARDUINO_ISR_ATTR _rmt_get_mem_len(uint8_t channel);
|
||||
|
||||
static void IRAM_ATTR _rmt_tx_mem_first(uint8_t ch);
|
||||
static void ARDUINO_ISR_ATTR _rmt_tx_mem_first(uint8_t ch);
|
||||
|
||||
static void IRAM_ATTR _rmt_tx_mem_second(uint8_t ch);
|
||||
static void ARDUINO_ISR_ATTR _rmt_tx_mem_second(uint8_t ch);
|
||||
|
||||
|
||||
/**
|
||||
@ -234,6 +241,20 @@ bool rmtDeinit(rmt_obj_t *rmt)
|
||||
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) {
|
||||
@ -249,7 +270,7 @@ bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size)
|
||||
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)ESP_INTR_FLAG_IRAM, _rmt_isr, NULL, &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;
|
||||
@ -282,10 +303,10 @@ bool rmtWrite(rmt_obj_t* rmt, rmt_data_t* data, size_t size)
|
||||
RMT_MUTEX_UNLOCK(channel);
|
||||
|
||||
// start the transation
|
||||
return _rmtSendOnce(rmt, data, MAX_DATA_PER_ITTERATION);
|
||||
return _rmtSendOnce(rmt, data, MAX_DATA_PER_ITTERATION, false);
|
||||
} else {
|
||||
// use one-go mode if data fits one buffer
|
||||
return _rmtSendOnce(rmt, data, size);
|
||||
return _rmtSendOnce(rmt, data, size, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -483,7 +504,7 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == MAX_CHANNELS || i+j >= MAX_CHANNELS || j != buffers) {
|
||||
if (i == MAX_CHANNELS || i+j > MAX_CHANNELS || j != buffers) {
|
||||
xSemaphoreGive(g_rmt_block_lock);
|
||||
return NULL;
|
||||
}
|
||||
@ -518,12 +539,17 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize)
|
||||
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
|
||||
@ -543,7 +569,7 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize)
|
||||
|
||||
// install interrupt if at least one channel is active
|
||||
if (!intr_handle) {
|
||||
esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ESP_INTR_FLAG_IRAM, _rmt_isr, NULL, &intr_handle);
|
||||
esp_intr_alloc(ETS_RMT_INTR_SOURCE, (int)ARDUINO_ISR_FLAG, _rmt_isr, NULL, &intr_handle);
|
||||
}
|
||||
RMT_MUTEX_UNLOCK(channel);
|
||||
|
||||
@ -553,7 +579,7 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize)
|
||||
/**
|
||||
* Private methods definitions
|
||||
*/
|
||||
bool _rmtSendOnce(rmt_obj_t* rmt, rmt_data_t* data, size_t size)
|
||||
bool _rmtSendOnce(rmt_obj_t* rmt, rmt_data_t* data, size_t size, bool continuous)
|
||||
{
|
||||
if (!rmt) {
|
||||
return false;
|
||||
@ -571,6 +597,7 @@ bool _rmtSendOnce(rmt_obj_t* rmt, rmt_data_t* data, size_t size)
|
||||
}
|
||||
|
||||
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);
|
||||
@ -610,7 +637,7 @@ static void _initPin(int pin, int channel, bool tx_not_rx)
|
||||
}
|
||||
|
||||
|
||||
static void IRAM_ATTR _rmt_isr(void* arg)
|
||||
static void ARDUINO_ISR_ATTR _rmt_isr(void* arg)
|
||||
{
|
||||
int intr_val = RMT.int_st.val;
|
||||
size_t ch;
|
||||
@ -665,7 +692,6 @@ static void IRAM_ATTR _rmt_isr(void* arg)
|
||||
}
|
||||
|
||||
if (intr_val & _INT_ERROR(ch)) {
|
||||
digitalWrite(2, 1);
|
||||
// clear the flag
|
||||
RMT.int_clr.val = _INT_ERROR(ch);
|
||||
RMT.int_ena.val &= ~_INT_ERROR(ch);
|
||||
@ -701,7 +727,7 @@ static void IRAM_ATTR _rmt_isr(void* arg)
|
||||
}
|
||||
}
|
||||
|
||||
static void IRAM_ATTR _rmt_tx_mem_second(uint8_t 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;
|
||||
@ -753,7 +779,7 @@ static void IRAM_ATTR _rmt_tx_mem_second(uint8_t ch)
|
||||
DEBUG_INTERRUPT_END(4);
|
||||
}
|
||||
|
||||
static void IRAM_ATTR _rmt_tx_mem_first(uint8_t ch)
|
||||
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;
|
||||
@ -804,7 +830,7 @@ static void IRAM_ATTR _rmt_tx_mem_first(uint8_t ch)
|
||||
DEBUG_INTERRUPT_END(2);
|
||||
}
|
||||
|
||||
static int IRAM_ATTR _rmt_get_mem_len(uint8_t channel)
|
||||
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;
|
||||
|
@ -73,6 +73,12 @@ float rmtSetTick(rmt_obj_t* rmt, float tick);
|
||||
*/
|
||||
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
|
||||
*
|
||||
|
@ -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()
|
||||
@ -69,6 +81,9 @@ uint32_t sigmaDeltaSetup(uint8_t channel, uint32_t freq) //chan 0-7 freq 1220-31
|
||||
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;
|
||||
|
@ -17,10 +17,7 @@
|
||||
#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"
|
||||
@ -28,17 +25,24 @@
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/rtc.h"
|
||||
|
||||
#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))))
|
||||
#define SPI_MOSI_IDX(p) ((p==0)?SPID_IN_IDX:((p==1)?SPID_IN_IDX:((p==2)?HSPID_IN_IDX:((p==3)?VSPID_IN_IDX:0))))
|
||||
|
||||
#define SPI_SPI_SS_IDX(n) ((n==0)?SPICS0_OUT_IDX:((n==1)?SPICS1_OUT_IDX:((n==2)?SPICS2_OUT_IDX:SPICS0_OUT_IDX)))
|
||||
#define SPI_HSPI_SS_IDX(n) ((n==0)?HSPICS0_OUT_IDX:((n==1)?HSPICS1_OUT_IDX:((n==2)?HSPICS2_OUT_IDX:HSPICS0_OUT_IDX)))
|
||||
#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))))
|
||||
#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;
|
||||
@ -48,25 +52,69 @@ struct spi_struct_t {
|
||||
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))))
|
||||
#define SPI_MOSI_IDX(p) ((p==0)?SPID_IN_IDX:((p==1)?SPID_IN_IDX:((p==2)?HSPID_IN_IDX:((p==3)?VSPID_IN_IDX:0))))
|
||||
|
||||
#define SPI_SPI_SS_IDX(n) ((n==0)?SPICS0_OUT_IDX:((n==1)?SPICS1_OUT_IDX:((n==2)?SPICS2_OUT_IDX:SPICS0_OUT_IDX)))
|
||||
#define SPI_HSPI_SS_IDX(n) ((n==0)?HSPICS0_OUT_IDX:((n==1)?HSPICS1_OUT_IDX:((n==2)?HSPICS2_OUT_IDX:HSPICS0_OUT_IDX)))
|
||||
#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_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))))
|
||||
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
@ -76,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) {
|
||||
@ -83,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);
|
||||
@ -94,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) {
|
||||
@ -101,6 +166,7 @@ void spiAttachMISO(spi_t * spi, int8_t miso)
|
||||
} else {
|
||||
miso = 7;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
SPI_MUTEX_LOCK();
|
||||
pinMode(miso, INPUT);
|
||||
@ -114,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) {
|
||||
@ -121,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);
|
||||
@ -132,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) {
|
||||
@ -139,6 +222,7 @@ void spiDetachSCK(spi_t * spi, int8_t sck)
|
||||
} else {
|
||||
sck = 6;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
pinMatrixOutDetach(sck, false, false);
|
||||
pinMode(sck, INPUT);
|
||||
@ -150,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) {
|
||||
@ -157,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);
|
||||
@ -168,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) {
|
||||
@ -175,6 +276,7 @@ void spiDetachMOSI(spi_t * spi, int8_t mosi)
|
||||
} else {
|
||||
mosi = 8;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
pinMatrixOutDetach(mosi, false, false);
|
||||
pinMode(mosi, INPUT);
|
||||
@ -190,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) {
|
||||
@ -197,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);
|
||||
@ -209,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) {
|
||||
@ -216,6 +335,7 @@ void spiDetachSS(spi_t * spi, int8_t ss)
|
||||
} else {
|
||||
ss = 11;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
pinMatrixOutDetach(ss, false, false);
|
||||
pinMode(ss, INPUT);
|
||||
@ -227,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();
|
||||
}
|
||||
|
||||
@ -237,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();
|
||||
}
|
||||
|
||||
@ -269,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();
|
||||
}
|
||||
|
||||
@ -279,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();
|
||||
}
|
||||
|
||||
@ -306,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) {
|
||||
@ -328,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;
|
||||
}
|
||||
@ -384,28 +540,39 @@ static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb
|
||||
}
|
||||
}
|
||||
|
||||
void spiStopBus(spi_t * spi)
|
||||
static void spiInitBus(spi_t * spi)
|
||||
{
|
||||
if(!spi) {
|
||||
return;
|
||||
}
|
||||
SPI_MUTEX_LOCK();
|
||||
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;
|
||||
SPI_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -420,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;
|
||||
@ -447,6 +623,10 @@ 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;
|
||||
}
|
||||
@ -459,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;
|
||||
@ -532,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;
|
||||
@ -630,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;
|
||||
@ -671,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;
|
||||
@ -722,23 +897,39 @@ void spiTransaction(spi_t * spi, uint32_t clockDiv, uint8_t dataMode, uint8_t bi
|
||||
SPI_MUTEX_LOCK();
|
||||
spi->dev->clock.val = clockDiv;
|
||||
switch (dataMode) {
|
||||
case SPI_MODE1:
|
||||
spi->dev->pin.ck_idle_edge = 0;
|
||||
spi->dev->user.ck_out_edge = 1;
|
||||
break;
|
||||
case SPI_MODE2:
|
||||
spi->dev->pin.ck_idle_edge = 1;
|
||||
spi->dev->user.ck_out_edge = 1;
|
||||
break;
|
||||
case SPI_MODE3:
|
||||
spi->dev->pin.ck_idle_edge = 1;
|
||||
spi->dev->user.ck_out_edge = 0;
|
||||
break;
|
||||
case SPI_MODE0:
|
||||
default:
|
||||
spi->dev->pin.ck_idle_edge = 0;
|
||||
spi->dev->user.ck_out_edge = 0;
|
||||
break;
|
||||
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;
|
||||
}
|
||||
if (SPI_MSBFIRST == bitOrder) {
|
||||
spi->dev->ctrl.wr_bit_order = 0;
|
||||
@ -765,7 +956,7 @@ void spiEndTransaction(spi_t * spi)
|
||||
SPI_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
void IRAM_ATTR spiWriteByteNL(spi_t * spi, uint8_t data)
|
||||
void ARDUINO_ISR_ATTR spiWriteByteNL(spi_t * spi, uint8_t data)
|
||||
{
|
||||
if(!spi) {
|
||||
return;
|
||||
@ -791,7 +982,7 @@ uint8_t spiTransferByteNL(spi_t * spi, uint8_t data)
|
||||
return data;
|
||||
}
|
||||
|
||||
void IRAM_ATTR spiWriteShortNL(spi_t * spi, uint16_t data)
|
||||
void ARDUINO_ISR_ATTR spiWriteShortNL(spi_t * spi, uint16_t data)
|
||||
{
|
||||
if(!spi) {
|
||||
return;
|
||||
@ -826,7 +1017,7 @@ uint16_t spiTransferShortNL(spi_t * spi, uint16_t data)
|
||||
return data;
|
||||
}
|
||||
|
||||
void IRAM_ATTR spiWriteLongNL(spi_t * spi, uint32_t data)
|
||||
void ARDUINO_ISR_ATTR spiWriteLongNL(spi_t * spi, uint32_t data)
|
||||
{
|
||||
if(!spi) {
|
||||
return;
|
||||
@ -861,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++;
|
||||
@ -887,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;
|
||||
}
|
||||
@ -974,7 +1165,7 @@ void spiTransferBitsNL(spi_t * spi, uint32_t data, uint32_t * out, uint8_t bits)
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR 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++;
|
||||
|
@ -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);
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
#include "esp32-hal.h"
|
||||
#include "lwip/apps/sntp.h"
|
||||
//#include "tcpip_adapter.h"
|
||||
#include "esp_netif.h"
|
||||
|
||||
static void setTimeZone(long offset, int daylight)
|
||||
{
|
||||
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -202,15 +226,29 @@ hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){
|
||||
}
|
||||
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);
|
||||
@ -228,6 +266,9 @@ void timerEnd(hw_timer_t *timer){
|
||||
}
|
||||
|
||||
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){
|
||||
@ -239,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 {
|
||||
@ -263,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));
|
||||
}
|
||||
|
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,10 +18,7 @@
|
||||
#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"
|
||||
@ -30,10 +27,37 @@
|
||||
#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;
|
||||
|
||||
@ -51,31 +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 uart_on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb);
|
||||
|
||||
static void IRAM_ATTR _uart_isr(void *arg)
|
||||
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;
|
||||
@ -83,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;
|
||||
#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);
|
||||
}
|
||||
}
|
||||
@ -100,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();
|
||||
}
|
||||
|
||||
@ -143,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);
|
||||
@ -153,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);
|
||||
@ -162,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;
|
||||
}
|
||||
|
||||
@ -190,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);
|
||||
@ -208,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) {
|
||||
@ -217,7 +262,6 @@ 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;
|
||||
}
|
||||
@ -253,7 +297,7 @@ size_t uartResizeRxBuffer(uart_t * uart, size_t new_size) {
|
||||
vQueueDelete(uart->queue);
|
||||
uart->queue = xQueueCreate(new_size, sizeof(uint8_t));
|
||||
if(uart->queue == NULL) {
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
UART_MUTEX_UNLOCK();
|
||||
@ -266,7 +310,7 @@ 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)
|
||||
@ -277,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;
|
||||
}
|
||||
@ -295,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;
|
||||
}
|
||||
@ -308,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();
|
||||
}
|
||||
|
||||
@ -318,31 +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(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();
|
||||
#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.
|
||||
|
||||
//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));
|
||||
}
|
||||
|
||||
// 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_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
@ -368,18 +471,31 @@ static void uart_on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old
|
||||
uart->dev->int_clr.val = 0xffffffff;
|
||||
// read RX fifo
|
||||
uint8_t c;
|
||||
BaseType_t xHigherPriorityTaskWoken;
|
||||
// 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;
|
||||
if(uart->queue != NULL && !xQueueIsQueueFullFromISR(uart->queue)) {
|
||||
xQueueSendFromISR(uart->queue, &c, &xHigherPriorityTaskWoken);
|
||||
#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);
|
||||
@ -399,27 +515,44 @@ 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);
|
||||
if(!clk_div) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ((getApbFrequency()<<4)/clk_div);
|
||||
}
|
||||
|
||||
static void IRAM_ATTR uart0_write_char(char c)
|
||||
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 uart_install_putc()
|
||||
{
|
||||
@ -430,9 +563,11 @@ void uart_install_putc()
|
||||
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;
|
||||
@ -441,7 +576,7 @@ void uart_install_putc()
|
||||
|
||||
void uartSetDebug(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || uart->num > 2) {
|
||||
if(uart == NULL || uart->num >= UART_PORTS_NUM) {
|
||||
s_uart_debug_nr = -1;
|
||||
//ets_install_putc1(NULL);
|
||||
//return;
|
||||
@ -460,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;
|
||||
@ -480,7 +612,7 @@ 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){
|
||||
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);
|
||||
@ -520,6 +652,14 @@ unsigned long uartBaudrateDetect(uart_t *uart, bool flg)
|
||||
* 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)
|
||||
{
|
||||
@ -563,5 +703,9 @@ uartDetectBaudrate(uart_t *uart)
|
||||
* 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,6 +63,7 @@ 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);
|
||||
@ -72,6 +73,7 @@ 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);
|
||||
|
@ -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>
|
||||
@ -34,9 +30,34 @@ extern "C" {
|
||||
#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
|
||||
@ -64,12 +85,6 @@ void yield(void);
|
||||
#include "esp32-hal-psram.h"
|
||||
#include "esp32-hal-cpu.h"
|
||||
|
||||
#ifndef BOARD_HAS_PSRAM
|
||||
#ifdef CONFIG_SPIRAM_SUPPORT
|
||||
#undef CONFIG_SPIRAM_SUPPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//returns chip temperature in Celsius
|
||||
float temperatureRead();
|
||||
|
||||
@ -90,6 +105,16 @@ 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_ */
|
@ -2,15 +2,22 @@
|
||||
#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;
|
||||
@ -19,18 +26,25 @@ 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, &loopTaskHandle, 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)
|
||||
|
||||
|
@ -1,13 +1,12 @@
|
||||
Installation instructions using Arduino IDE Boards Manager
|
||||
==========================================================
|
||||
## Installation instructions using Arduino IDE Boards Manager
|
||||
### ==========================================================
|
||||
|
||||
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 and 64 bit).
|
||||
- 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 ```https://dl.espressif.com/dl/package_esp32_index.json``` into *Additional Board Manager URLs* field. You can add multiple URLs, separating them with commas.
|
||||
- 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).
|
||||
|
||||
Stable release link: `https://dl.espressif.com/dl/package_esp32_index.json`
|
||||
|
||||
Development release link: `https://dl.espressif.com/dl/package_esp32_dev_index.json`
|
||||
|
@ -23,5 +23,7 @@ Installation instructions for Mac OS
|
||||
|
||||
- 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)
|
||||
|
@ -127,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(){
|
||||
@ -173,6 +171,7 @@ void ArduinoOTAClass::_onRx(){
|
||||
_md5 = readStringUntil('\n');
|
||||
_md5.trim();
|
||||
if(_md5.length() != 32){
|
||||
log_e("bad md5 length");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -198,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;
|
||||
}
|
||||
@ -205,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;
|
||||
}
|
||||
@ -225,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;
|
||||
@ -234,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);
|
||||
}
|
||||
@ -272,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);
|
||||
}
|
||||
@ -295,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;
|
||||
}
|
||||
@ -317,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());
|
||||
}
|
||||
}
|
||||
|
||||
@ -351,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;
|
||||
}
|
||||
}
|
||||
@ -366,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() {
|
||||
@ -395,4 +380,4 @@ void ArduinoOTAClass::setTimeout(int timeoutInMillis) {
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_ARDUINOOTA)
|
||||
ArduinoOTAClass ArduinoOTA;
|
||||
#endif
|
||||
#endif
|
||||
|
@ -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"
|
||||
}
|
@ -150,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;
|
||||
}
|
||||
@ -682,8 +682,9 @@ void AsyncUDP::_recv(udp_pcb *upcb, pbuf *pb, const ip_addr_t *addr, uint16_t po
|
||||
if(_handler) {
|
||||
AsyncUDPPacket packet(this, this_pb, addr, port, netif);
|
||||
_handler(packet);
|
||||
} else {
|
||||
pbuf_free(this_pb);
|
||||
}
|
||||
pbuf_free(this_pb);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
}
|
||||
|
Submodule libraries/AzureIoT deleted from 67dfa4f31e
0
libraries/BLE/examples/BLE_client/.skip.esp32s2
Normal file
0
libraries/BLE/examples/BLE_client/.skip.esp32s2
Normal file
@ -87,6 +87,7 @@ bool connectToServer() {
|
||||
pRemoteCharacteristic->registerForNotify(notifyCallback);
|
||||
|
||||
connected = true;
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Scan for BLE servers and find the first one that advertises the service we are looking for.
|
||||
@ -153,7 +154,7 @@ void loop() {
|
||||
// Set the characteristic's value to be the array of bytes that is actually a string.
|
||||
pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length());
|
||||
}else if(doScan){
|
||||
BLEDevice::getScan()->start(0); // this is just eample to start scan after disconnect, most likely there is better way to do it in arduino
|
||||
BLEDevice::getScan()->start(0); // this is just example to start scan after disconnect, most likely there is better way to do it in arduino
|
||||
}
|
||||
|
||||
delay(1000); // Delay a second between loops.
|
||||
|
0
libraries/BLE/examples/BLE_iBeacon/.skip.esp32s2
Normal file
0
libraries/BLE/examples/BLE_iBeacon/.skip.esp32s2
Normal file
@ -65,6 +65,7 @@ void setBeacon() {
|
||||
|
||||
pAdvertising->setAdvertisementData(oAdvertisementData);
|
||||
pAdvertising->setScanResponseData(oScanResponseData);
|
||||
pAdvertising->setAdvertisementType(ADV_TYPE_NONCONN_IND);
|
||||
|
||||
}
|
||||
|
||||
|
0
libraries/BLE/examples/BLE_notify/.skip.esp32s2
Normal file
0
libraries/BLE/examples/BLE_notify/.skip.esp32s2
Normal file
0
libraries/BLE/examples/BLE_scan/.skip.esp32s2
Normal file
0
libraries/BLE/examples/BLE_scan/.skip.esp32s2
Normal file
0
libraries/BLE/examples/BLE_server/.skip.esp32s2
Normal file
0
libraries/BLE/examples/BLE_server/.skip.esp32s2
Normal file
0
libraries/BLE/examples/BLE_uart/.skip.esp32s2
Normal file
0
libraries/BLE/examples/BLE_uart/.skip.esp32s2
Normal file
0
libraries/BLE/examples/BLE_write/.skip.esp32s2
Normal file
0
libraries/BLE/examples/BLE_write/.skip.esp32s2
Normal file
@ -13,6 +13,7 @@
|
||||
#include <iomanip>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "esp32-hal-log.h"
|
||||
#endif
|
||||
@ -83,13 +84,11 @@ esp_bd_addr_t *BLEAddress::getNative() {
|
||||
* @return The string representation of the address.
|
||||
*/
|
||||
std::string BLEAddress::toString() {
|
||||
std::stringstream stream;
|
||||
stream << std::setfill('0') << std::setw(2) << std::hex << (int) ((uint8_t*) (m_address))[0] << ':';
|
||||
stream << std::setfill('0') << std::setw(2) << std::hex << (int) ((uint8_t*) (m_address))[1] << ':';
|
||||
stream << std::setfill('0') << std::setw(2) << std::hex << (int) ((uint8_t*) (m_address))[2] << ':';
|
||||
stream << std::setfill('0') << std::setw(2) << std::hex << (int) ((uint8_t*) (m_address))[3] << ':';
|
||||
stream << std::setfill('0') << std::setw(2) << std::hex << (int) ((uint8_t*) (m_address))[4] << ':';
|
||||
stream << std::setfill('0') << std::setw(2) << std::hex << (int) ((uint8_t*) (m_address))[5];
|
||||
return stream.str();
|
||||
auto size = 18;
|
||||
char *res = (char*)malloc(size);
|
||||
snprintf(res, size, "%02x:%02x:%02x:%02x:%02x:%02x", m_address[0], m_address[1], m_address[2], m_address[3], m_address[4], m_address[5]);
|
||||
std::string ret(res);
|
||||
free(res);
|
||||
return ret;
|
||||
} // toString
|
||||
#endif
|
||||
|
@ -16,13 +16,7 @@
|
||||
#include <sstream>
|
||||
#include "BLEAdvertisedDevice.h"
|
||||
#include "BLEUtils.h"
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define LOG_TAG ""
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* LOG_TAG="BLEAdvertisedDevice";
|
||||
#endif
|
||||
|
||||
BLEAdvertisedDevice::BLEAdvertisedDevice() {
|
||||
m_adFlag = 0;
|
||||
@ -31,7 +25,8 @@ BLEAdvertisedDevice::BLEAdvertisedDevice() {
|
||||
m_manufacturerData = "";
|
||||
m_name = "";
|
||||
m_rssi = -9999;
|
||||
m_serviceData = "";
|
||||
m_serviceData = {};
|
||||
m_serviceDataUUIDs = {};
|
||||
m_txPower = 0;
|
||||
m_pScan = nullptr;
|
||||
|
||||
@ -107,33 +102,66 @@ BLEScan* BLEAdvertisedDevice::getScan() {
|
||||
return m_pScan;
|
||||
} // getScan
|
||||
|
||||
/**
|
||||
* @brief Get the number of service data.
|
||||
* @return Number of service data discovered.
|
||||
*/
|
||||
int BLEAdvertisedDevice::getServiceDataCount() {
|
||||
if (m_haveServiceData)
|
||||
return m_serviceData.size();
|
||||
else
|
||||
return 0;
|
||||
|
||||
} //getServiceDataCount
|
||||
|
||||
/**
|
||||
* @brief Get the service data.
|
||||
* @return The ServiceData of the advertised device.
|
||||
*/
|
||||
std::string BLEAdvertisedDevice::getServiceData() {
|
||||
return m_serviceData;
|
||||
return m_serviceData[0];
|
||||
} //getServiceData
|
||||
|
||||
/**
|
||||
* @brief Get the service data.
|
||||
* @return The ServiceData of the advertised device.
|
||||
*/
|
||||
std::string BLEAdvertisedDevice::getServiceData(int i) {
|
||||
return m_serviceData[i];
|
||||
} //getServiceData
|
||||
|
||||
/**
|
||||
* @brief Get the service data UUID.
|
||||
* @return The service data UUID.
|
||||
*/
|
||||
BLEUUID BLEAdvertisedDevice::getServiceDataUUID() {
|
||||
return m_serviceDataUUID;
|
||||
return m_serviceDataUUIDs[0];
|
||||
} // getServiceDataUUID
|
||||
|
||||
/**
|
||||
* @brief Get the service data UUID.
|
||||
* @return The service data UUID.
|
||||
*/
|
||||
BLEUUID BLEAdvertisedDevice::getServiceDataUUID(int i) {
|
||||
return m_serviceDataUUIDs[i];
|
||||
} // getServiceDataUUID
|
||||
|
||||
/**
|
||||
* @brief Get the Service UUID.
|
||||
* @return The Service UUID of the advertised device.
|
||||
*/
|
||||
BLEUUID BLEAdvertisedDevice::getServiceUUID() { //TODO Remove it eventually, is no longer useful
|
||||
BLEUUID BLEAdvertisedDevice::getServiceUUID() {
|
||||
return m_serviceUUIDs[0];
|
||||
} // getServiceUUID
|
||||
|
||||
/**
|
||||
* @brief Get the Service UUID.
|
||||
* @return The Service UUID of the advertised device.
|
||||
*/
|
||||
BLEUUID BLEAdvertisedDevice::getServiceUUID(int i) {
|
||||
return m_serviceUUIDs[i];
|
||||
} // getServiceUUID
|
||||
|
||||
/**
|
||||
* @brief Check advertised serviced for existence required UUID
|
||||
* @return Return true if service is advertised
|
||||
@ -249,7 +277,7 @@ void BLEAdvertisedDevice::parseAdvertisement(uint8_t* payload, size_t total_len)
|
||||
length--;
|
||||
|
||||
char* pHex = BLEUtils::buildHexData(nullptr, payload, length);
|
||||
ESP_LOGD(LOG_TAG, "Type: 0x%.2x (%s), length: %d, data: %s",
|
||||
log_d("Type: 0x%.2x (%s), length: %d, data: %s",
|
||||
ad_type, BLEUtils::advTypeToString(ad_type), length, pHex);
|
||||
free(pHex);
|
||||
|
||||
@ -308,7 +336,7 @@ void BLEAdvertisedDevice::parseAdvertisement(uint8_t* payload, size_t total_len)
|
||||
|
||||
case ESP_BLE_AD_TYPE_SERVICE_DATA: { // Adv Data Type: 0x16 (Service Data) - 2 byte UUID
|
||||
if (length < 2) {
|
||||
ESP_LOGE(LOG_TAG, "Length too small for ESP_BLE_AD_TYPE_SERVICE_DATA");
|
||||
log_e("Length too small for ESP_BLE_AD_TYPE_SERVICE_DATA");
|
||||
break;
|
||||
}
|
||||
uint16_t uuid = *(uint16_t*)payload;
|
||||
@ -321,7 +349,7 @@ void BLEAdvertisedDevice::parseAdvertisement(uint8_t* payload, size_t total_len)
|
||||
|
||||
case ESP_BLE_AD_TYPE_32SERVICE_DATA: { // Adv Data Type: 0x20 (Service Data) - 4 byte UUID
|
||||
if (length < 4) {
|
||||
ESP_LOGE(LOG_TAG, "Length too small for ESP_BLE_AD_TYPE_32SERVICE_DATA");
|
||||
log_e("Length too small for ESP_BLE_AD_TYPE_32SERVICE_DATA");
|
||||
break;
|
||||
}
|
||||
uint32_t uuid = *(uint32_t*) payload;
|
||||
@ -334,7 +362,7 @@ void BLEAdvertisedDevice::parseAdvertisement(uint8_t* payload, size_t total_len)
|
||||
|
||||
case ESP_BLE_AD_TYPE_128SERVICE_DATA: { // Adv Data Type: 0x21 (Service Data) - 16 byte UUID
|
||||
if (length < 16) {
|
||||
ESP_LOGE(LOG_TAG, "Length too small for ESP_BLE_AD_TYPE_128SERVICE_DATA");
|
||||
log_e("Length too small for ESP_BLE_AD_TYPE_128SERVICE_DATA");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -346,7 +374,7 @@ void BLEAdvertisedDevice::parseAdvertisement(uint8_t* payload, size_t total_len)
|
||||
} //ESP_BLE_AD_TYPE_32SERVICE_DATA
|
||||
|
||||
default: {
|
||||
ESP_LOGD(LOG_TAG, "Unhandled type: adType: %d - 0x%.2x", ad_type, ad_type);
|
||||
log_d("Unhandled type: adType: %d - 0x%.2x", ad_type, ad_type);
|
||||
break;
|
||||
}
|
||||
} // switch
|
||||
@ -386,7 +414,7 @@ void BLEAdvertisedDevice::setAdFlag(uint8_t adFlag) {
|
||||
void BLEAdvertisedDevice::setAppearance(uint16_t appearance) {
|
||||
m_appearance = appearance;
|
||||
m_haveAppearance = true;
|
||||
ESP_LOGD(LOG_TAG, "- appearance: %d", m_appearance);
|
||||
log_d("- appearance: %d", m_appearance);
|
||||
} // setAppearance
|
||||
|
||||
|
||||
@ -398,7 +426,7 @@ void BLEAdvertisedDevice::setManufacturerData(std::string manufacturerData) {
|
||||
m_manufacturerData = manufacturerData;
|
||||
m_haveManufacturerData = true;
|
||||
char* pHex = BLEUtils::buildHexData(nullptr, (uint8_t*) m_manufacturerData.data(), (uint8_t) m_manufacturerData.length());
|
||||
ESP_LOGD(LOG_TAG, "- manufacturer data: %s", pHex);
|
||||
log_d("- manufacturer data: %s", pHex);
|
||||
free(pHex);
|
||||
} // setManufacturerData
|
||||
|
||||
@ -410,7 +438,7 @@ void BLEAdvertisedDevice::setManufacturerData(std::string manufacturerData) {
|
||||
void BLEAdvertisedDevice::setName(std::string name) {
|
||||
m_name = name;
|
||||
m_haveName = true;
|
||||
ESP_LOGD(LOG_TAG, "- setName(): name: %s", m_name.c_str());
|
||||
log_d("- setName(): name: %s", m_name.c_str());
|
||||
} // setName
|
||||
|
||||
|
||||
@ -421,7 +449,7 @@ void BLEAdvertisedDevice::setName(std::string name) {
|
||||
void BLEAdvertisedDevice::setRSSI(int rssi) {
|
||||
m_rssi = rssi;
|
||||
m_haveRSSI = true;
|
||||
ESP_LOGD(LOG_TAG, "- setRSSI(): rssi: %d", m_rssi);
|
||||
log_d("- setRSSI(): rssi: %d", m_rssi);
|
||||
} // setRSSI
|
||||
|
||||
|
||||
@ -450,7 +478,7 @@ void BLEAdvertisedDevice::setServiceUUID(const char* serviceUUID) {
|
||||
void BLEAdvertisedDevice::setServiceUUID(BLEUUID serviceUUID) {
|
||||
m_serviceUUIDs.push_back(serviceUUID);
|
||||
m_haveServiceUUID = true;
|
||||
ESP_LOGD(LOG_TAG, "- addServiceUUID(): serviceUUID: %s", serviceUUID.toString().c_str());
|
||||
log_d("- addServiceUUID(): serviceUUID: %s", serviceUUID.toString().c_str());
|
||||
} // setServiceUUID
|
||||
|
||||
|
||||
@ -460,7 +488,7 @@ void BLEAdvertisedDevice::setServiceUUID(BLEUUID serviceUUID) {
|
||||
*/
|
||||
void BLEAdvertisedDevice::setServiceData(std::string serviceData) {
|
||||
m_haveServiceData = true; // Set the flag that indicates we have service data.
|
||||
m_serviceData = serviceData; // Save the service data that we received.
|
||||
m_serviceData.push_back(serviceData); // Save the service data that we received.
|
||||
} //setServiceData
|
||||
|
||||
|
||||
@ -470,7 +498,8 @@ void BLEAdvertisedDevice::setServiceData(std::string serviceData) {
|
||||
*/
|
||||
void BLEAdvertisedDevice::setServiceDataUUID(BLEUUID uuid) {
|
||||
m_haveServiceData = true; // Set the flag that indicates we have service data.
|
||||
m_serviceDataUUID = uuid;
|
||||
m_serviceDataUUIDs.push_back(uuid);
|
||||
log_d("- addServiceDataUUID(): serviceDataUUID: %s", uuid.toString().c_str());
|
||||
} // setServiceDataUUID
|
||||
|
||||
|
||||
@ -481,7 +510,7 @@ void BLEAdvertisedDevice::setServiceDataUUID(BLEUUID uuid) {
|
||||
void BLEAdvertisedDevice::setTXPower(int8_t txPower) {
|
||||
m_txPower = txPower;
|
||||
m_haveTXPower = true;
|
||||
ESP_LOGD(LOG_TAG, "- txPower: %d", m_txPower);
|
||||
log_d("- txPower: %d", m_txPower);
|
||||
} // setTXPower
|
||||
|
||||
|
||||
@ -490,23 +519,31 @@ void BLEAdvertisedDevice::setTXPower(int8_t txPower) {
|
||||
* @return A string representation of this device.
|
||||
*/
|
||||
std::string BLEAdvertisedDevice::toString() {
|
||||
std::stringstream ss;
|
||||
ss << "Name: " << getName() << ", Address: " << getAddress().toString();
|
||||
std::string res = "Name: " + getName() + ", Address: " + getAddress().toString();
|
||||
if (haveAppearance()) {
|
||||
ss << ", appearance: " << getAppearance();
|
||||
char val[6];
|
||||
snprintf(val, sizeof(val), "%d", getAppearance());
|
||||
res += ", appearance: ";
|
||||
res += val;
|
||||
}
|
||||
if (haveManufacturerData()) {
|
||||
char *pHex = BLEUtils::buildHexData(nullptr, (uint8_t*)getManufacturerData().data(), getManufacturerData().length());
|
||||
ss << ", manufacturer data: " << pHex;
|
||||
res += ", manufacturer data: ";
|
||||
res += pHex;
|
||||
free(pHex);
|
||||
}
|
||||
if (haveServiceUUID()) {
|
||||
ss << ", serviceUUID: " << getServiceUUID().toString();
|
||||
for (int i=0; i < m_serviceUUIDs.size(); i++) {
|
||||
res += ", serviceUUID: " + getServiceUUID(i).toString();
|
||||
}
|
||||
}
|
||||
if (haveTXPower()) {
|
||||
ss << ", txPower: " << (int)getTXPower();
|
||||
char val[6];
|
||||
snprintf(val, sizeof(val), "%d", getTXPower());
|
||||
res += ", txPower: ";
|
||||
res += val;
|
||||
}
|
||||
return ss.str();
|
||||
return res;
|
||||
} // toString
|
||||
|
||||
uint8_t* BLEAdvertisedDevice::getPayload() {
|
||||
|
@ -36,8 +36,12 @@ public:
|
||||
int getRSSI();
|
||||
BLEScan* getScan();
|
||||
std::string getServiceData();
|
||||
std::string getServiceData(int i);
|
||||
BLEUUID getServiceDataUUID();
|
||||
BLEUUID getServiceDataUUID(int i);
|
||||
BLEUUID getServiceUUID();
|
||||
BLEUUID getServiceUUID(int i);
|
||||
int getServiceDataCount();
|
||||
int8_t getTXPower();
|
||||
uint8_t* getPayload();
|
||||
size_t getPayloadLength();
|
||||
@ -93,8 +97,8 @@ private:
|
||||
int m_rssi;
|
||||
std::vector<BLEUUID> m_serviceUUIDs;
|
||||
int8_t m_txPower;
|
||||
std::string m_serviceData;
|
||||
BLEUUID m_serviceDataUUID;
|
||||
std::vector<std::string> m_serviceData;
|
||||
std::vector<BLEUUID> m_serviceDataUUIDs;
|
||||
uint8_t* m_payload;
|
||||
size_t m_payloadLength = 0;
|
||||
esp_ble_addr_type_t m_addressType;
|
||||
|
@ -22,16 +22,7 @@
|
||||
#include <esp_err.h>
|
||||
#include "BLEUtils.h"
|
||||
#include "GeneralUtils.h"
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define LOG_TAG ""
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* LOG_TAG = "BLEAdvertising";
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Construct a default advertising object.
|
||||
@ -94,6 +85,10 @@ void BLEAdvertising::setAppearance(uint16_t appearance) {
|
||||
m_advData.appearance = appearance;
|
||||
} // setAppearance
|
||||
|
||||
void BLEAdvertising::setAdvertisementType(esp_ble_adv_type_t adv_type){
|
||||
m_advParams.adv_type = adv_type;
|
||||
} // setAdvertisementType
|
||||
|
||||
void BLEAdvertising::setMinInterval(uint16_t mininterval) {
|
||||
m_advParams.adv_int_min = mininterval;
|
||||
} // setMinInterval
|
||||
@ -120,25 +115,25 @@ void BLEAdvertising::setScanResponse(bool set) {
|
||||
* @param [in] connectWhitelistOnly If true, only allow connections from those on the white list.
|
||||
*/
|
||||
void BLEAdvertising::setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly) {
|
||||
ESP_LOGD(LOG_TAG, ">> setScanFilter: scanRequestWhitelistOnly: %d, connectWhitelistOnly: %d", scanRequestWhitelistOnly, connectWhitelistOnly);
|
||||
log_v(">> setScanFilter: scanRequestWhitelistOnly: %d, connectWhitelistOnly: %d", scanRequestWhitelistOnly, connectWhitelistOnly);
|
||||
if (!scanRequestWhitelistOnly && !connectWhitelistOnly) {
|
||||
m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY;
|
||||
ESP_LOGD(LOG_TAG, "<< setScanFilter");
|
||||
log_v("<< setScanFilter");
|
||||
return;
|
||||
}
|
||||
if (scanRequestWhitelistOnly && !connectWhitelistOnly) {
|
||||
m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_WLST_CON_ANY;
|
||||
ESP_LOGD(LOG_TAG, "<< setScanFilter");
|
||||
log_v("<< setScanFilter");
|
||||
return;
|
||||
}
|
||||
if (!scanRequestWhitelistOnly && connectWhitelistOnly) {
|
||||
m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_WLST;
|
||||
ESP_LOGD(LOG_TAG, "<< setScanFilter");
|
||||
log_v("<< setScanFilter");
|
||||
return;
|
||||
}
|
||||
if (scanRequestWhitelistOnly && connectWhitelistOnly) {
|
||||
m_advParams.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_WLST_CON_WLST;
|
||||
ESP_LOGD(LOG_TAG, "<< setScanFilter");
|
||||
log_v("<< setScanFilter");
|
||||
return;
|
||||
}
|
||||
} // setScanFilter
|
||||
@ -149,15 +144,15 @@ void BLEAdvertising::setScanFilter(bool scanRequestWhitelistOnly, bool connectWh
|
||||
* @param [in] advertisementData The data to be advertised.
|
||||
*/
|
||||
void BLEAdvertising::setAdvertisementData(BLEAdvertisementData& advertisementData) {
|
||||
ESP_LOGD(LOG_TAG, ">> setAdvertisementData");
|
||||
log_v(">> setAdvertisementData");
|
||||
esp_err_t errRc = ::esp_ble_gap_config_adv_data_raw(
|
||||
(uint8_t*)advertisementData.getPayload().data(),
|
||||
advertisementData.getPayload().length());
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_config_adv_data_raw: %d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_ble_gap_config_adv_data_raw: %d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
m_customAdvData = true; // Set the flag that indicates we are using custom advertising data.
|
||||
ESP_LOGD(LOG_TAG, "<< setAdvertisementData");
|
||||
log_v("<< setAdvertisementData");
|
||||
} // setAdvertisementData
|
||||
|
||||
|
||||
@ -166,15 +161,15 @@ void BLEAdvertising::setAdvertisementData(BLEAdvertisementData& advertisementDat
|
||||
* @param [in] advertisementData The data to be advertised.
|
||||
*/
|
||||
void BLEAdvertising::setScanResponseData(BLEAdvertisementData& advertisementData) {
|
||||
ESP_LOGD(LOG_TAG, ">> setScanResponseData");
|
||||
log_v(">> setScanResponseData");
|
||||
esp_err_t errRc = ::esp_ble_gap_config_scan_rsp_data_raw(
|
||||
(uint8_t*)advertisementData.getPayload().data(),
|
||||
advertisementData.getPayload().length());
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_config_scan_rsp_data_raw: %d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_ble_gap_config_scan_rsp_data_raw: %d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
m_customScanResponseData = true; // Set the flag that indicates we are using custom scan response data.
|
||||
ESP_LOGD(LOG_TAG, "<< setScanResponseData");
|
||||
log_v("<< setScanResponseData");
|
||||
} // setScanResponseData
|
||||
|
||||
/**
|
||||
@ -183,7 +178,7 @@ void BLEAdvertising::setScanResponseData(BLEAdvertisementData& advertisementData
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLEAdvertising::start() {
|
||||
ESP_LOGD(LOG_TAG, ">> start: customAdvData: %d, customScanResponseData: %d", m_customAdvData, m_customScanResponseData);
|
||||
log_v(">> start: customAdvData: %d, customScanResponseData: %d", m_customAdvData, m_customScanResponseData);
|
||||
|
||||
// We have a vector of service UUIDs that we wish to advertise. In order to use the
|
||||
// ESP-IDF framework, these must be supplied in a contiguous array of their 128bit (16 byte)
|
||||
@ -195,14 +190,14 @@ void BLEAdvertising::start() {
|
||||
m_advData.p_service_uuid = new uint8_t[m_advData.service_uuid_len];
|
||||
uint8_t* p = m_advData.p_service_uuid;
|
||||
for (int i = 0; i < numServices; i++) {
|
||||
ESP_LOGD(LOG_TAG, "- advertising service: %s", m_serviceUUIDs[i].toString().c_str());
|
||||
log_d("- advertising service: %s", m_serviceUUIDs[i].toString().c_str());
|
||||
BLEUUID serviceUUID128 = m_serviceUUIDs[i].to128();
|
||||
memcpy(p, serviceUUID128.getNative()->uuid.uuid128, 16);
|
||||
p += 16;
|
||||
}
|
||||
} else {
|
||||
m_advData.service_uuid_len = 0;
|
||||
ESP_LOGD(LOG_TAG, "- no services advertised");
|
||||
log_d("- no services advertised");
|
||||
}
|
||||
|
||||
esp_err_t errRc;
|
||||
@ -214,7 +209,7 @@ void BLEAdvertising::start() {
|
||||
m_advData.include_txpower = !m_scanResp;
|
||||
errRc = ::esp_ble_gap_config_adv_data(&m_advData);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "<< esp_ble_gap_config_adv_data: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("<< esp_ble_gap_config_adv_data: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -225,7 +220,7 @@ void BLEAdvertising::start() {
|
||||
m_advData.include_txpower = m_scanResp;
|
||||
errRc = ::esp_ble_gap_config_adv_data(&m_advData);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "<< esp_ble_gap_config_adv_data (Scan response): rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("<< esp_ble_gap_config_adv_data (Scan response): rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -240,10 +235,10 @@ void BLEAdvertising::start() {
|
||||
// Start advertising.
|
||||
errRc = ::esp_ble_gap_start_advertising(&m_advParams);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "<< esp_ble_gap_start_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("<< esp_ble_gap_start_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(LOG_TAG, "<< start");
|
||||
log_v("<< start");
|
||||
} // start
|
||||
|
||||
|
||||
@ -253,15 +248,36 @@ void BLEAdvertising::start() {
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLEAdvertising::stop() {
|
||||
ESP_LOGD(LOG_TAG, ">> stop");
|
||||
log_v(">> stop");
|
||||
esp_err_t errRc = ::esp_ble_gap_stop_advertising();
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_stop_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_ble_gap_stop_advertising: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(LOG_TAG, "<< stop");
|
||||
log_v("<< stop");
|
||||
} // stop
|
||||
|
||||
/**
|
||||
* @brief Set BLE address.
|
||||
* @param [in] Bluetooth address.
|
||||
* @param [in] Bluetooth address type.
|
||||
* Set BLE address.
|
||||
*/
|
||||
|
||||
void BLEAdvertising::setDeviceAddress(esp_bd_addr_t addr, esp_ble_addr_type_t type)
|
||||
{
|
||||
log_v(">> setPrivateAddress");
|
||||
|
||||
m_advParams.own_addr_type = type;
|
||||
esp_err_t errRc = esp_ble_gap_set_rand_addr((uint8_t*)addr);
|
||||
if (errRc != ESP_OK)
|
||||
{
|
||||
log_e("esp_ble_gap_set_rand_addr: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
log_v("<< setPrivateAddress");
|
||||
} // setPrivateAddress
|
||||
|
||||
/**
|
||||
* @brief Add data to the payload to be advertised.
|
||||
* @param [in] data The data to be added to the payload.
|
||||
@ -352,12 +368,12 @@ void BLEAdvertisementData::setFlags(uint8_t flag) {
|
||||
* @param [in] data Manufacturer data.
|
||||
*/
|
||||
void BLEAdvertisementData::setManufacturerData(std::string data) {
|
||||
ESP_LOGD("BLEAdvertisementData", ">> setManufacturerData");
|
||||
log_d("BLEAdvertisementData", ">> setManufacturerData");
|
||||
char cdata[2];
|
||||
cdata[0] = data.length() + 1;
|
||||
cdata[1] = ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE; // 0xff
|
||||
addData(std::string(cdata, 2) + data);
|
||||
ESP_LOGD("BLEAdvertisementData", "<< setManufacturerData");
|
||||
log_d("BLEAdvertisementData", "<< setManufacturerData");
|
||||
} // setManufacturerData
|
||||
|
||||
|
||||
@ -366,12 +382,12 @@ void BLEAdvertisementData::setManufacturerData(std::string data) {
|
||||
* @param [in] The complete name of the device.
|
||||
*/
|
||||
void BLEAdvertisementData::setName(std::string name) {
|
||||
ESP_LOGD("BLEAdvertisementData", ">> setName: %s", name.c_str());
|
||||
log_d("BLEAdvertisementData", ">> setName: %s", name.c_str());
|
||||
char cdata[2];
|
||||
cdata[0] = name.length() + 1;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_NAME_CMPL; // 0x09
|
||||
addData(std::string(cdata, 2) + name);
|
||||
ESP_LOGD("BLEAdvertisementData", "<< setName");
|
||||
log_d("BLEAdvertisementData", "<< setName");
|
||||
} // setName
|
||||
|
||||
|
||||
@ -455,12 +471,12 @@ void BLEAdvertisementData::setServiceData(BLEUUID uuid, std::string data) {
|
||||
* @param [in] The short name of the device.
|
||||
*/
|
||||
void BLEAdvertisementData::setShortName(std::string name) {
|
||||
ESP_LOGD("BLEAdvertisementData", ">> setShortName: %s", name.c_str());
|
||||
log_d("BLEAdvertisementData", ">> setShortName: %s", name.c_str());
|
||||
char cdata[2];
|
||||
cdata[0] = name.length() + 1;
|
||||
cdata[1] = ESP_BLE_AD_TYPE_NAME_SHORT; // 0x08
|
||||
addData(std::string(cdata, 2) + name);
|
||||
ESP_LOGD("BLEAdvertisementData", "<< setShortName");
|
||||
log_d("BLEAdvertisementData", "<< setShortName");
|
||||
} // setShortName
|
||||
|
||||
|
||||
@ -476,7 +492,7 @@ void BLEAdvertising::handleGAPEvent(
|
||||
esp_gap_ble_cb_event_t event,
|
||||
esp_ble_gap_cb_param_t* param) {
|
||||
|
||||
ESP_LOGD(LOG_TAG, "handleGAPEvent [event no: %d]", (int)event);
|
||||
log_d("handleGAPEvent [event no: %d]", (int)event);
|
||||
|
||||
switch(event) {
|
||||
case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: {
|
||||
@ -492,8 +508,8 @@ void BLEAdvertising::handleGAPEvent(
|
||||
break;
|
||||
}
|
||||
case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: {
|
||||
ESP_LOGI(LOG_TAG, "STOP advertising");
|
||||
start();
|
||||
log_i("STOP advertising");
|
||||
//start();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include <esp_gap_ble_api.h>
|
||||
#include "BLEUUID.h"
|
||||
#include <vector>
|
||||
#include "FreeRTOS.h"
|
||||
#include "RTOS.h"
|
||||
|
||||
/**
|
||||
* @brief Advertisement data set by the programmer to be published by the %BLE server.
|
||||
@ -52,12 +52,14 @@ public:
|
||||
void start();
|
||||
void stop();
|
||||
void setAppearance(uint16_t appearance);
|
||||
void setAdvertisementType(esp_ble_adv_type_t adv_type);
|
||||
void setMaxInterval(uint16_t maxinterval);
|
||||
void setMinInterval(uint16_t mininterval);
|
||||
void setAdvertisementData(BLEAdvertisementData& advertisementData);
|
||||
void setScanFilter(bool scanRequertWhitelistOnly, bool connectWhitelistOnly);
|
||||
void setScanResponseData(BLEAdvertisementData& advertisementData);
|
||||
void setPrivateAddress(esp_ble_addr_type_t type = BLE_ADDR_TYPE_RANDOM);
|
||||
void setDeviceAddress(esp_bd_addr_t addr, esp_ble_addr_type_t type = BLE_ADDR_TYPE_RANDOM);
|
||||
|
||||
void handleGAPEvent(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t* param);
|
||||
void setMinPreferred(uint16_t);
|
||||
@ -75,4 +77,4 @@ private:
|
||||
|
||||
};
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ */
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLEADVERTISING_H_ */
|
||||
|
@ -8,13 +8,7 @@
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <string.h>
|
||||
#include "BLEBeacon.h"
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define LOG_TAG ""
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* LOG_TAG = "BLEBeacon";
|
||||
#endif
|
||||
|
||||
#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00)>>8) + (((x)&0xFF)<<8))
|
||||
|
||||
@ -58,7 +52,7 @@ int8_t BLEBeacon::getSignalPower() {
|
||||
*/
|
||||
void BLEBeacon::setData(std::string data) {
|
||||
if (data.length() != sizeof(m_beaconData)) {
|
||||
ESP_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and expected %d", data.length(), sizeof(m_beaconData));
|
||||
log_e("Unable to set the data ... length passed in was %d and expected %d", data.length(), sizeof(m_beaconData));
|
||||
return;
|
||||
}
|
||||
memcpy(&m_beaconData, data.data(), sizeof(m_beaconData));
|
||||
|
@ -18,16 +18,11 @@
|
||||
#include "BLEUtils.h"
|
||||
#include "BLE2902.h"
|
||||
#include "GeneralUtils.h"
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define LOG_TAG ""
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* LOG_TAG = "BLECharacteristic";
|
||||
#endif
|
||||
|
||||
#define NULL_HANDLE (0xffff)
|
||||
|
||||
static BLECharacteristicCallbacks defaultCallback; //null-object-pattern
|
||||
|
||||
/**
|
||||
* @brief Construct a characteristic
|
||||
@ -46,7 +41,7 @@ BLECharacteristic::BLECharacteristic(BLEUUID uuid, uint32_t properties) {
|
||||
m_bleUUID = uuid;
|
||||
m_handle = NULL_HANDLE;
|
||||
m_properties = (esp_gatt_char_prop_t)0;
|
||||
m_pCallbacks = nullptr;
|
||||
m_pCallbacks = &defaultCallback;
|
||||
|
||||
setBroadcastProperty((properties & PROPERTY_BROADCAST) != 0);
|
||||
setReadProperty((properties & PROPERTY_READ) != 0);
|
||||
@ -70,9 +65,9 @@ BLECharacteristic::~BLECharacteristic() {
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLECharacteristic::addDescriptor(BLEDescriptor* pDescriptor) {
|
||||
ESP_LOGD(LOG_TAG, ">> addDescriptor(): Adding %s to %s", pDescriptor->toString().c_str(), toString().c_str());
|
||||
log_v(">> addDescriptor(): Adding %s to %s", pDescriptor->toString().c_str(), toString().c_str());
|
||||
m_descriptorMap.setByUUID(pDescriptor->getUUID(), pDescriptor);
|
||||
ESP_LOGD(LOG_TAG, "<< addDescriptor()");
|
||||
log_v("<< addDescriptor()");
|
||||
} // addDescriptor
|
||||
|
||||
|
||||
@ -81,16 +76,16 @@ void BLECharacteristic::addDescriptor(BLEDescriptor* pDescriptor) {
|
||||
* @param [in] pService The service with which to associate this characteristic.
|
||||
*/
|
||||
void BLECharacteristic::executeCreate(BLEService* pService) {
|
||||
ESP_LOGD(LOG_TAG, ">> executeCreate()");
|
||||
log_v(">> executeCreate()");
|
||||
|
||||
if (m_handle != NULL_HANDLE) {
|
||||
ESP_LOGE(LOG_TAG, "Characteristic already has a handle.");
|
||||
log_e("Characteristic already has a handle.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_pService = pService; // Save the service to which this characteristic belongs.
|
||||
|
||||
ESP_LOGD(LOG_TAG, "Registering characteristic (esp_ble_gatts_add_char): uuid: %s, service: %s",
|
||||
log_d("Registering characteristic (esp_ble_gatts_add_char): uuid: %s, service: %s",
|
||||
getUUID().toString().c_str(),
|
||||
m_pService->toString().c_str());
|
||||
|
||||
@ -107,7 +102,7 @@ void BLECharacteristic::executeCreate(BLEService* pService) {
|
||||
&control); // Whether to auto respond or not.
|
||||
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_add_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("<< esp_ble_gatts_add_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
m_semaphoreCreateEvt.wait("executeCreate");
|
||||
@ -118,7 +113,7 @@ void BLECharacteristic::executeCreate(BLEService* pService) {
|
||||
pDescriptor = m_descriptorMap.getNext();
|
||||
} // End while
|
||||
|
||||
ESP_LOGD(LOG_TAG, "<< executeCreate");
|
||||
log_v("<< executeCreate");
|
||||
} // executeCreate
|
||||
|
||||
|
||||
@ -200,7 +195,7 @@ void BLECharacteristic::handleGATTServerEvent(
|
||||
esp_gatts_cb_event_t event,
|
||||
esp_gatt_if_t gatts_if,
|
||||
esp_ble_gatts_cb_param_t* param) {
|
||||
ESP_LOGD(LOG_TAG, ">> handleGATTServerEvent: %s", BLEUtils::gattServerEventTypeToString(event).c_str());
|
||||
log_v(">> handleGATTServerEvent: %s", BLEUtils::gattServerEventTypeToString(event).c_str());
|
||||
|
||||
switch(event) {
|
||||
// Events handled:
|
||||
@ -226,9 +221,7 @@ void BLECharacteristic::handleGATTServerEvent(
|
||||
case ESP_GATTS_EXEC_WRITE_EVT: {
|
||||
if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) {
|
||||
m_value.commit();
|
||||
if (m_pCallbacks != nullptr) {
|
||||
m_pCallbacks->onWrite(this); // Invoke the onWrite callback handler.
|
||||
}
|
||||
m_pCallbacks->onWrite(this); // Invoke the onWrite callback handler.
|
||||
} else {
|
||||
m_value.cancel();
|
||||
}
|
||||
@ -238,7 +231,7 @@ void BLECharacteristic::handleGATTServerEvent(
|
||||
param->write.conn_id,
|
||||
param->write.trans_id, ESP_GATT_OK, nullptr);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
break;
|
||||
} // ESP_GATTS_EXEC_WRITE_EVT
|
||||
@ -288,11 +281,11 @@ void BLECharacteristic::handleGATTServerEvent(
|
||||
setValue(param->write.value, param->write.len);
|
||||
}
|
||||
|
||||
ESP_LOGD(LOG_TAG, " - Response to write event: New value: handle: %.2x, uuid: %s",
|
||||
log_d(" - Response to write event: New value: handle: %.2x, uuid: %s",
|
||||
getHandle(), getUUID().toString().c_str());
|
||||
|
||||
char* pHexData = BLEUtils::buildHexData(nullptr, param->write.value, param->write.len);
|
||||
ESP_LOGD(LOG_TAG, " - Data: length: %d, data: %s", param->write.len, pHexData);
|
||||
log_d(" - Data: length: %d, data: %s", param->write.len, pHexData);
|
||||
free(pHexData);
|
||||
|
||||
if (param->write.need_rsp) {
|
||||
@ -309,11 +302,11 @@ void BLECharacteristic::handleGATTServerEvent(
|
||||
param->write.conn_id,
|
||||
param->write.trans_id, ESP_GATT_OK, &rsp);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
} // Response needed
|
||||
|
||||
if (m_pCallbacks != nullptr && param->write.is_prep != true) {
|
||||
if (param->write.is_prep != true) {
|
||||
m_pCallbacks->onWrite(this); // Invoke the onWrite callback handler.
|
||||
}
|
||||
} // Match on handles.
|
||||
@ -361,9 +354,9 @@ void BLECharacteristic::handleGATTServerEvent(
|
||||
|
||||
// get mtu for peer device that we are sending read request to
|
||||
uint16_t maxOffset = getService()->getServer()->getPeerMTU(param->read.conn_id) - 1;
|
||||
ESP_LOGD(LOG_TAG, "mtu value: %d", maxOffset);
|
||||
log_d("mtu value: %d", maxOffset);
|
||||
if (param->read.need_rsp) {
|
||||
ESP_LOGD(LOG_TAG, "Sending a response (esp_ble_gatts_send_response)");
|
||||
log_d("Sending a response (esp_ble_gatts_send_response)");
|
||||
esp_gatt_rsp_t rsp;
|
||||
|
||||
if (param->read.is_long) {
|
||||
@ -384,6 +377,10 @@ void BLECharacteristic::handleGATTServerEvent(
|
||||
}
|
||||
} else { // read.is_long == false
|
||||
|
||||
// If is.long is false then this is the first (or only) request to read data, so invoke the callback
|
||||
// Invoke the read callback.
|
||||
m_pCallbacks->onRead(this);
|
||||
|
||||
std::string value = m_value.getValue();
|
||||
|
||||
if (value.length() + 1 > maxOffset) {
|
||||
@ -398,16 +395,12 @@ void BLECharacteristic::handleGATTServerEvent(
|
||||
rsp.attr_value.offset = 0;
|
||||
memcpy(rsp.attr_value.value, value.data(), rsp.attr_value.len);
|
||||
}
|
||||
|
||||
if (m_pCallbacks != nullptr) { // If is.long is false then this is the first (or only) request to read data, so invoke the callback
|
||||
m_pCallbacks->onRead(this); // Invoke the read callback.
|
||||
}
|
||||
}
|
||||
rsp.attr_value.handle = param->read.handle;
|
||||
rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE;
|
||||
|
||||
char *pHexData = BLEUtils::buildHexData(nullptr, rsp.attr_value.value, rsp.attr_value.len);
|
||||
ESP_LOGD(LOG_TAG, " - Data: length=%d, data=%s, offset=%d", rsp.attr_value.len, pHexData, rsp.attr_value.offset);
|
||||
log_d(" - Data: length=%d, data=%s, offset=%d", rsp.attr_value.len, pHexData, rsp.attr_value.offset);
|
||||
free(pHexData);
|
||||
|
||||
esp_err_t errRc = ::esp_ble_gatts_send_response(
|
||||
@ -416,7 +409,7 @@ void BLECharacteristic::handleGATTServerEvent(
|
||||
ESP_GATT_OK,
|
||||
&rsp);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
} // Response needed
|
||||
} // Handle matches this characteristic.
|
||||
@ -431,7 +424,7 @@ void BLECharacteristic::handleGATTServerEvent(
|
||||
// - uint16_t conn_id – The connection used.
|
||||
//
|
||||
case ESP_GATTS_CONF_EVT: {
|
||||
// ESP_LOGD(LOG_TAG, "m_handle = %d, conf->handle = %d", m_handle, param->conf.handle);
|
||||
// log_d("m_handle = %d, conf->handle = %d", m_handle, param->conf.handle);
|
||||
if(param->conf.conn_id == getService()->getServer()->getConnId()) // && param->conf.handle == m_handle) // bug in esp-idf and not implemented in arduino yet
|
||||
m_semaphoreConfEvt.give(param->conf.status);
|
||||
break;
|
||||
@ -456,7 +449,7 @@ void BLECharacteristic::handleGATTServerEvent(
|
||||
// event.
|
||||
|
||||
m_descriptorMap.handleGATTServerEvent(event, gatts_if, param);
|
||||
ESP_LOGD(LOG_TAG, "<< handleGATTServerEvent");
|
||||
log_v("<< handleGATTServerEvent");
|
||||
} // handleGATTServerEvent
|
||||
|
||||
|
||||
@ -468,9 +461,9 @@ void BLECharacteristic::handleGATTServerEvent(
|
||||
*/
|
||||
void BLECharacteristic::indicate() {
|
||||
|
||||
ESP_LOGD(LOG_TAG, ">> indicate: length: %d", m_value.getValue().length());
|
||||
log_v(">> indicate: length: %d", m_value.getValue().length());
|
||||
notify(false);
|
||||
ESP_LOGD(LOG_TAG, "<< indicate");
|
||||
log_v("<< indicate");
|
||||
} // indicate
|
||||
|
||||
|
||||
@ -481,15 +474,18 @@ void BLECharacteristic::indicate() {
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLECharacteristic::notify(bool is_notification) {
|
||||
ESP_LOGD(LOG_TAG, ">> notify: length: %d", m_value.getValue().length());
|
||||
log_v(">> notify: length: %d", m_value.getValue().length());
|
||||
|
||||
assert(getService() != nullptr);
|
||||
assert(getService()->getServer() != nullptr);
|
||||
|
||||
m_pCallbacks->onNotify(this); // Invoke the notify callback.
|
||||
|
||||
GeneralUtils::hexDump((uint8_t*)m_value.getValue().data(), m_value.getValue().length());
|
||||
|
||||
if (getService()->getServer()->getConnectedCount() == 0) {
|
||||
ESP_LOGD(LOG_TAG, "<< notify: No connected clients.");
|
||||
log_v("<< notify: No connected clients.");
|
||||
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_NO_CLIENT, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -499,38 +495,53 @@ void BLECharacteristic::notify(bool is_notification) {
|
||||
BLE2902 *p2902 = (BLE2902*)getDescriptorByUUID((uint16_t)0x2902);
|
||||
if(is_notification) {
|
||||
if (p2902 != nullptr && !p2902->getNotifications()) {
|
||||
ESP_LOGD(LOG_TAG, "<< notifications disabled; ignoring");
|
||||
log_v("<< notifications disabled; ignoring");
|
||||
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_NOTIFY_DISABLED, 0); // Invoke the notify callback.
|
||||
return;
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (p2902 != nullptr && !p2902->getIndications()) {
|
||||
ESP_LOGD(LOG_TAG, "<< indications disabled; ignoring");
|
||||
log_v("<< indications disabled; ignoring");
|
||||
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_INDICATE_DISABLED, 0); // Invoke the notify callback.
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (auto &myPair : getService()->getServer()->getPeerDevices(false)) {
|
||||
uint16_t _mtu = (myPair.second.mtu);
|
||||
if (m_value.getValue().length() > _mtu - 3) {
|
||||
ESP_LOGW(LOG_TAG, "- Truncating to %d bytes (maximum notify size)", _mtu - 3);
|
||||
log_w("- Truncating to %d bytes (maximum notify size)", _mtu - 3);
|
||||
}
|
||||
|
||||
size_t length = m_value.getValue().length();
|
||||
if(!is_notification)
|
||||
if(!is_notification) // is indication
|
||||
m_semaphoreConfEvt.take("indicate");
|
||||
esp_err_t errRc = ::esp_ble_gatts_send_indicate(
|
||||
getService()->getServer()->getGattsIf(),
|
||||
myPair.first,
|
||||
getHandle(), length, (uint8_t*)m_value.getValue().data(), !is_notification); // The need_confirm = false makes this a notify.
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_send_ %s: rc=%d %s",is_notification?"notify":"indicate", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("<< esp_ble_gatts_send_ %s: rc=%d %s",is_notification?"notify":"indicate", errRc, GeneralUtils::errorToString(errRc));
|
||||
m_semaphoreConfEvt.give();
|
||||
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_GATT, errRc); // Invoke the notify callback.
|
||||
return;
|
||||
}
|
||||
if(!is_notification)
|
||||
m_semaphoreConfEvt.wait("indicate");
|
||||
if(!is_notification){ // is indication
|
||||
if(!m_semaphoreConfEvt.timedWait("indicate", indicationTimeout)){
|
||||
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_INDICATE_TIMEOUT, 0); // Invoke the notify callback.
|
||||
} else {
|
||||
auto code = (esp_gatt_status_t) m_semaphoreConfEvt.value();
|
||||
if(code == ESP_GATT_OK) {
|
||||
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::SUCCESS_INDICATE, code); // Invoke the notify callback.
|
||||
} else {
|
||||
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::ERROR_INDICATE_FAILURE, code);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
m_pCallbacks->onStatus(this, BLECharacteristicCallbacks::Status::SUCCESS_NOTIFY, 0); // Invoke the notify callback.
|
||||
}
|
||||
}
|
||||
ESP_LOGD(LOG_TAG, "<< notify");
|
||||
log_v("<< notify");
|
||||
} // Notify
|
||||
|
||||
|
||||
@ -542,7 +553,7 @@ void BLECharacteristic::notify(bool is_notification) {
|
||||
* @return N/A
|
||||
*/
|
||||
void BLECharacteristic::setBroadcastProperty(bool value) {
|
||||
//ESP_LOGD(LOG_TAG, "setBroadcastProperty(%d)", value);
|
||||
//log_d("setBroadcastProperty(%d)", value);
|
||||
if (value) {
|
||||
m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_BROADCAST);
|
||||
} else {
|
||||
@ -556,9 +567,13 @@ void BLECharacteristic::setBroadcastProperty(bool value) {
|
||||
* @param [in] pCallbacks An instance of a callbacks structure used to define any callbacks for the characteristic.
|
||||
*/
|
||||
void BLECharacteristic::setCallbacks(BLECharacteristicCallbacks* pCallbacks) {
|
||||
ESP_LOGD(LOG_TAG, ">> setCallbacks: 0x%x", (uint32_t)pCallbacks);
|
||||
m_pCallbacks = pCallbacks;
|
||||
ESP_LOGD(LOG_TAG, "<< setCallbacks");
|
||||
log_v(">> setCallbacks: 0x%x", (uint32_t)pCallbacks);
|
||||
if (pCallbacks != nullptr){
|
||||
m_pCallbacks = pCallbacks;
|
||||
} else {
|
||||
m_pCallbacks = &defaultCallback;
|
||||
}
|
||||
log_v("<< setCallbacks");
|
||||
} // setCallbacks
|
||||
|
||||
|
||||
@ -573,9 +588,9 @@ void BLECharacteristic::setCallbacks(BLECharacteristicCallbacks* pCallbacks) {
|
||||
* @param [in] handle The handle associated with this characteristic.
|
||||
*/
|
||||
void BLECharacteristic::setHandle(uint16_t handle) {
|
||||
ESP_LOGD(LOG_TAG, ">> setHandle: handle=0x%.2x, characteristic uuid=%s", handle, getUUID().toString().c_str());
|
||||
log_v(">> setHandle: handle=0x%.2x, characteristic uuid=%s", handle, getUUID().toString().c_str());
|
||||
m_handle = handle;
|
||||
ESP_LOGD(LOG_TAG, "<< setHandle");
|
||||
log_v("<< setHandle");
|
||||
} // setHandle
|
||||
|
||||
|
||||
@ -584,7 +599,7 @@ void BLECharacteristic::setHandle(uint16_t handle) {
|
||||
* @param [in] value Set to true if we are to allow indicate messages.
|
||||
*/
|
||||
void BLECharacteristic::setIndicateProperty(bool value) {
|
||||
//ESP_LOGD(LOG_TAG, "setIndicateProperty(%d)", value);
|
||||
//log_d("setIndicateProperty(%d)", value);
|
||||
if (value) {
|
||||
m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_INDICATE);
|
||||
} else {
|
||||
@ -598,7 +613,7 @@ void BLECharacteristic::setIndicateProperty(bool value) {
|
||||
* @param [in] value Set to true if we are to allow notification messages.
|
||||
*/
|
||||
void BLECharacteristic::setNotifyProperty(bool value) {
|
||||
//ESP_LOGD(LOG_TAG, "setNotifyProperty(%d)", value);
|
||||
//log_d("setNotifyProperty(%d)", value);
|
||||
if (value) {
|
||||
m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_NOTIFY);
|
||||
} else {
|
||||
@ -612,7 +627,7 @@ void BLECharacteristic::setNotifyProperty(bool value) {
|
||||
* @param [in] value Set to true if we are to allow reads.
|
||||
*/
|
||||
void BLECharacteristic::setReadProperty(bool value) {
|
||||
//ESP_LOGD(LOG_TAG, "setReadProperty(%d)", value);
|
||||
//log_d("setReadProperty(%d)", value);
|
||||
if (value) {
|
||||
m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_READ);
|
||||
} else {
|
||||
@ -628,14 +643,16 @@ void BLECharacteristic::setReadProperty(bool value) {
|
||||
*/
|
||||
void BLECharacteristic::setValue(uint8_t* data, size_t length) {
|
||||
char* pHex = BLEUtils::buildHexData(nullptr, data, length);
|
||||
ESP_LOGD(LOG_TAG, ">> setValue: length=%d, data=%s, characteristic UUID=%s", length, pHex, getUUID().toString().c_str());
|
||||
log_v(">> setValue: length=%d, data=%s, characteristic UUID=%s", length, pHex, getUUID().toString().c_str());
|
||||
free(pHex);
|
||||
if (length > ESP_GATT_MAX_ATTR_LEN) {
|
||||
ESP_LOGE(LOG_TAG, "Size %d too large, must be no bigger than %d", length, ESP_GATT_MAX_ATTR_LEN);
|
||||
log_e("Size %d too large, must be no bigger than %d", length, ESP_GATT_MAX_ATTR_LEN);
|
||||
return;
|
||||
}
|
||||
m_semaphoreSetValue.take();
|
||||
m_value.setValue(data, length);
|
||||
ESP_LOGD(LOG_TAG, "<< setValue");
|
||||
m_semaphoreSetValue.give();
|
||||
log_v("<< setValue");
|
||||
} // setValue
|
||||
|
||||
|
||||
@ -676,15 +693,13 @@ void BLECharacteristic::setValue(int& data32) {
|
||||
} // setValue
|
||||
|
||||
void BLECharacteristic::setValue(float& data32) {
|
||||
uint8_t temp[4];
|
||||
*((float*)temp) = data32;
|
||||
setValue(temp, 4);
|
||||
float temp = data32;
|
||||
setValue((uint8_t*)&temp, 4);
|
||||
} // setValue
|
||||
|
||||
void BLECharacteristic::setValue(double& data64) {
|
||||
uint8_t temp[8];
|
||||
*((double*)temp) = data64;
|
||||
setValue(temp, 8);
|
||||
double temp = data64;
|
||||
setValue((uint8_t*)&temp, 8);
|
||||
} // setValue
|
||||
|
||||
|
||||
@ -693,7 +708,7 @@ void BLECharacteristic::setValue(double& data64) {
|
||||
* @param [in] value Set to true if we are to allow writes with no response.
|
||||
*/
|
||||
void BLECharacteristic::setWriteNoResponseProperty(bool value) {
|
||||
//ESP_LOGD(LOG_TAG, "setWriteNoResponseProperty(%d)", value);
|
||||
//log_d("setWriteNoResponseProperty(%d)", value);
|
||||
if (value) {
|
||||
m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_WRITE_NR);
|
||||
} else {
|
||||
@ -707,7 +722,7 @@ void BLECharacteristic::setWriteNoResponseProperty(bool value) {
|
||||
* @param [in] value Set to true if we are to allow writes.
|
||||
*/
|
||||
void BLECharacteristic::setWriteProperty(bool value) {
|
||||
//ESP_LOGD(LOG_TAG, "setWriteProperty(%d)", value);
|
||||
//log_d("setWriteProperty(%d)", value);
|
||||
if (value) {
|
||||
m_properties = (esp_gatt_char_prop_t)(m_properties | ESP_GATT_CHAR_PROP_BIT_WRITE);
|
||||
} else {
|
||||
@ -721,17 +736,18 @@ void BLECharacteristic::setWriteProperty(bool value) {
|
||||
* @return A string representation of the characteristic.
|
||||
*/
|
||||
std::string BLECharacteristic::toString() {
|
||||
std::stringstream stringstream;
|
||||
stringstream << std::hex << std::setfill('0');
|
||||
stringstream << "UUID: " << m_bleUUID.toString() + ", handle: 0x" << std::setw(2) << m_handle;
|
||||
stringstream << " " <<
|
||||
((m_properties & ESP_GATT_CHAR_PROP_BIT_READ) ? "Read " : "") <<
|
||||
((m_properties & ESP_GATT_CHAR_PROP_BIT_WRITE) ? "Write " : "") <<
|
||||
((m_properties & ESP_GATT_CHAR_PROP_BIT_WRITE_NR) ? "WriteNoResponse " : "") <<
|
||||
((m_properties & ESP_GATT_CHAR_PROP_BIT_BROADCAST) ? "Broadcast " : "") <<
|
||||
((m_properties & ESP_GATT_CHAR_PROP_BIT_NOTIFY) ? "Notify " : "") <<
|
||||
((m_properties & ESP_GATT_CHAR_PROP_BIT_INDICATE) ? "Indicate " : "");
|
||||
return stringstream.str();
|
||||
std::string res = "UUID: " + m_bleUUID.toString() + ", handle : 0x";
|
||||
char hex[5];
|
||||
snprintf(hex, sizeof(hex), "%04x", m_handle);
|
||||
res += hex;
|
||||
res += " ";
|
||||
if (m_properties & ESP_GATT_CHAR_PROP_BIT_READ) res += "Read ";
|
||||
if (m_properties & ESP_GATT_CHAR_PROP_BIT_WRITE) res += "Write ";
|
||||
if (m_properties & ESP_GATT_CHAR_PROP_BIT_WRITE_NR) res += "WriteNoResponse ";
|
||||
if (m_properties & ESP_GATT_CHAR_PROP_BIT_BROADCAST) res += "Broadcast ";
|
||||
if (m_properties & ESP_GATT_CHAR_PROP_BIT_NOTIFY) res += "Notify ";
|
||||
if (m_properties & ESP_GATT_CHAR_PROP_BIT_INDICATE) res += "Indicate ";
|
||||
return res;
|
||||
} // toString
|
||||
|
||||
|
||||
@ -743,8 +759,8 @@ BLECharacteristicCallbacks::~BLECharacteristicCallbacks() {}
|
||||
* @param [in] pCharacteristic The characteristic that is the source of the event.
|
||||
*/
|
||||
void BLECharacteristicCallbacks::onRead(BLECharacteristic* pCharacteristic) {
|
||||
ESP_LOGD("BLECharacteristicCallbacks", ">> onRead: default");
|
||||
ESP_LOGD("BLECharacteristicCallbacks", "<< onRead");
|
||||
log_d("BLECharacteristicCallbacks", ">> onRead: default");
|
||||
log_d("BLECharacteristicCallbacks", "<< onRead");
|
||||
} // onRead
|
||||
|
||||
|
||||
@ -753,8 +769,31 @@ void BLECharacteristicCallbacks::onRead(BLECharacteristic* pCharacteristic) {
|
||||
* @param [in] pCharacteristic The characteristic that is the source of the event.
|
||||
*/
|
||||
void BLECharacteristicCallbacks::onWrite(BLECharacteristic* pCharacteristic) {
|
||||
ESP_LOGD("BLECharacteristicCallbacks", ">> onWrite: default");
|
||||
ESP_LOGD("BLECharacteristicCallbacks", "<< onWrite");
|
||||
log_d("BLECharacteristicCallbacks", ">> onWrite: default");
|
||||
log_d("BLECharacteristicCallbacks", "<< onWrite");
|
||||
} // onWrite
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callback function to support a Notify request.
|
||||
* @param [in] pCharacteristic The characteristic that is the source of the event.
|
||||
*/
|
||||
void BLECharacteristicCallbacks::onNotify(BLECharacteristic* pCharacteristic) {
|
||||
log_d("BLECharacteristicCallbacks", ">> onNotify: default");
|
||||
log_d("BLECharacteristicCallbacks", "<< onNotify");
|
||||
} // onNotify
|
||||
|
||||
|
||||
/**
|
||||
* @brief Callback function to support a Notify/Indicate Status report.
|
||||
* @param [in] pCharacteristic The characteristic that is the source of the event.
|
||||
* @param [in] s Status of the notification/indication
|
||||
* @param [in] code Additional code of underlying errors
|
||||
*/
|
||||
void BLECharacteristicCallbacks::onStatus(BLECharacteristic* pCharacteristic, Status s, uint32_t code) {
|
||||
log_d("BLECharacteristicCallbacks", ">> onStatus: default");
|
||||
log_d("BLECharacteristicCallbacks", "<< onStatus");
|
||||
} // onStatus
|
||||
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include <esp_gap_ble_api.h>
|
||||
#include "BLEDescriptor.h"
|
||||
#include "BLEValue.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "RTOS.h"
|
||||
|
||||
class BLEService;
|
||||
class BLEDescriptor;
|
||||
@ -90,6 +90,8 @@ public:
|
||||
static const uint32_t PROPERTY_INDICATE = 1<<4;
|
||||
static const uint32_t PROPERTY_WRITE_NR = 1<<5;
|
||||
|
||||
static const uint32_t indicationTimeout = 1000;
|
||||
|
||||
private:
|
||||
|
||||
friend class BLEServer;
|
||||
@ -117,6 +119,7 @@ private:
|
||||
void setHandle(uint16_t handle);
|
||||
FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt");
|
||||
FreeRTOS::Semaphore m_semaphoreConfEvt = FreeRTOS::Semaphore("ConfEvt");
|
||||
FreeRTOS::Semaphore m_semaphoreSetValue = FreeRTOS::Semaphore("SetValue");
|
||||
}; // BLECharacteristic
|
||||
|
||||
|
||||
@ -129,9 +132,22 @@ private:
|
||||
*/
|
||||
class BLECharacteristicCallbacks {
|
||||
public:
|
||||
typedef enum {
|
||||
SUCCESS_INDICATE,
|
||||
SUCCESS_NOTIFY,
|
||||
ERROR_INDICATE_DISABLED,
|
||||
ERROR_NOTIFY_DISABLED,
|
||||
ERROR_GATT,
|
||||
ERROR_NO_CLIENT,
|
||||
ERROR_INDICATE_TIMEOUT,
|
||||
ERROR_INDICATE_FAILURE
|
||||
}Status;
|
||||
|
||||
virtual ~BLECharacteristicCallbacks();
|
||||
virtual void onRead(BLECharacteristic* pCharacteristic);
|
||||
virtual void onWrite(BLECharacteristic* pCharacteristic);
|
||||
virtual void onNotify(BLECharacteristic* pCharacteristic);
|
||||
virtual void onStatus(BLECharacteristic* pCharacteristic, Status s, uint32_t code);
|
||||
};
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
#endif /* COMPONENTS_CPP_UTILS_BLECHARACTERISTIC_H_ */
|
||||
|
@ -116,17 +116,18 @@ void BLECharacteristicMap::setByUUID(BLECharacteristic* pCharacteristic, BLEUUID
|
||||
* @return A string representation of the characteristic map.
|
||||
*/
|
||||
std::string BLECharacteristicMap::toString() {
|
||||
std::stringstream stringStream;
|
||||
stringStream << std::hex << std::setfill('0');
|
||||
std::string res;
|
||||
int count = 0;
|
||||
char hex[5];
|
||||
for (auto &myPair: m_uuidMap) {
|
||||
if (count > 0) {
|
||||
stringStream << "\n";
|
||||
}
|
||||
if (count > 0) {res += "\n";}
|
||||
snprintf(hex, sizeof(hex), "%04x", myPair.first->getHandle());
|
||||
count++;
|
||||
stringStream << "handle: 0x" << std::setw(2) << myPair.first->getHandle() << ", uuid: " + myPair.first->getUUID().toString();
|
||||
res += "handle: 0x";
|
||||
res += hex;
|
||||
res += ", uuid: " + myPair.first->getUUID().toString();
|
||||
}
|
||||
return stringStream.str();
|
||||
return res;
|
||||
} // toString
|
||||
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user