forked from espressif/arduino-esp32
Compare commits
470 Commits
Author | SHA1 | Date | |
---|---|---|---|
46d5afb17f | |||
66746750a4 | |||
e7a2759b65 | |||
2ee66b54f0 | |||
2d3c57635d | |||
a299ddc99e | |||
93bcf5f250 | |||
bd41334265 | |||
9a0762ad2a | |||
a451c9ef0d | |||
d362e1ee1a | |||
33d9f4aa19 | |||
63c51d51fb | |||
5b845272ed | |||
5da4a47bdf | |||
3253de8792 | |||
a31f30529d | |||
35643bdd9b | |||
8dc70e0add | |||
b42739dfa4 | |||
93d5b8c672 | |||
f815a7c636 | |||
23f6e81d52 | |||
e8311b00ae | |||
4d95e3a7ea | |||
7dc769d81c | |||
4204d1e60a | |||
d7fda910fb | |||
f7fc8ab377 | |||
dd834b3372 | |||
0e55f775d3 | |||
22a488cf23 | |||
6e7cc5210d | |||
7a6900a1f2 | |||
0e0a7565e8 | |||
bd3addeb8e | |||
1cf1c8eb79 | |||
3fe7c2e8cd | |||
5d00b6eb16 | |||
419ba32432 | |||
a0ddd8a16e | |||
b8dab5ed1a | |||
2141313148 | |||
44aaf13225 | |||
560c0f45f5 | |||
4b3f5c8ed4 | |||
c282cd8f5f | |||
7e59971d2f | |||
f4b17b3033 | |||
1ab550f6f2 | |||
9be784f69b | |||
7cdfb8bc7c | |||
8134a42162 | |||
f13ff65691 | |||
e831680a41 | |||
d964873840 | |||
7e8993fc83 | |||
15bae92a72 | |||
6f23cd5988 | |||
ad4cf1461b | |||
5de03a3918 | |||
4b385690bc | |||
dd513df124 | |||
cee659563d | |||
55442a05a4 | |||
c9b3e512dd | |||
8d0e68db4f | |||
d2530850a3 | |||
7ecbb483da | |||
b0e896e9ae | |||
08f4665775 | |||
2452c1fb53 | |||
5f98370707 | |||
81b9130d8d | |||
434d02c49f | |||
15db297130 | |||
fe093a5e35 | |||
a0ef17a9dd | |||
be77bd4e27 | |||
ef99cd7fe7 | |||
b05bdf6904 | |||
442c63a4c6 | |||
d1a4b3b822 | |||
7d5bf9e385 | |||
aac26a4d1e | |||
804c221499 | |||
3236358ded | |||
82e71f9b50 | |||
2e12392721 | |||
6b0114366b | |||
18832bb418 | |||
97dcea2b99 | |||
dcff2e9774 | |||
6d256b6454 | |||
f6bf0f7aa2 | |||
a59eb5d51e | |||
adafd9d7c0 | |||
ac9fdeffe4 | |||
cee7b4237c | |||
954df2fc3e | |||
e41fb08b2a | |||
d8b1fc81c0 | |||
378b6ac032 | |||
cecef8e930 | |||
a8e99baeab | |||
b6cc108d49 | |||
8816bb5505 | |||
3274602eb0 | |||
534f0810a6 | |||
28a8073069 | |||
7494c4e76d | |||
486a4c66c4 | |||
c1951670d1 | |||
ad07d36932 | |||
c6a8da61f7 | |||
dd1a15478f | |||
bcb7012a32 | |||
3968821834 | |||
90f869e772 | |||
be4d3b6cb8 | |||
60606e5ad0 | |||
22b427df0f | |||
6e5be78838 | |||
e2452c0dfc | |||
56a7ae8712 | |||
e4b008e712 | |||
76afaf2d6b | |||
dccb4e8608 | |||
c2346c37da | |||
3491ca7845 | |||
0e341a6192 | |||
76cd2e2375 | |||
9f7ff009c6 | |||
704b71dabe | |||
7c0572172c | |||
f57c36782f | |||
3054bdf5a5 | |||
1014ba40af | |||
d6b91872cb | |||
d6b383f84b | |||
cadbad8850 | |||
3cbfa2ffef | |||
360e04fa36 | |||
57145ade6f | |||
f39024675c | |||
f7fb00632e | |||
7e40de226f | |||
ae240a3902 | |||
1287c52933 | |||
25bd585c25 | |||
d79a1f3d10 | |||
831f0ac29a | |||
ee3bb16c77 | |||
d8dca9c73b | |||
c3f3497048 | |||
18c3345451 | |||
b07f1c11fe | |||
2685a5dd7b | |||
675a40b257 | |||
3570d48eb9 | |||
f76ec4f50b | |||
fb6d5ad234 | |||
219ff3005b | |||
ccab428e4d | |||
d2d24a14e0 | |||
af11921535 | |||
82112384ca | |||
99aa866477 | |||
82670b96f8 | |||
9e7b13e46d | |||
2243081f85 | |||
1f4491f4ee | |||
aa529eb5a0 | |||
a9cb7c6d6f | |||
45d47e2be0 | |||
99c94bb482 | |||
f98fc7ee9f | |||
0957776855 | |||
d93245d0f5 | |||
c917ed2504 | |||
ee88c42c3b | |||
837cc3d271 | |||
9b2ae12fb7 | |||
86e221d087 | |||
663effa00e | |||
6f237a8415 | |||
c3c38a8eb5 | |||
8fcc914853 | |||
d03f8f1277 | |||
882b12c44e | |||
93d850f783 | |||
4f48caca2c | |||
80e9e42c3b | |||
494061af26 | |||
2fd3d042b2 | |||
b551310c37 | |||
f30edd040e | |||
b7c5e502e7 | |||
fa8a1c38d5 | |||
d56267bd8c | |||
1f6b0b35f8 | |||
342b9cf2d8 | |||
11d071b1c8 | |||
f48d9016fd | |||
a55265f74b | |||
c1a7198e7d | |||
4d4a1fde36 | |||
d219e56872 | |||
19ccc479c3 | |||
c18d50cb91 | |||
80418fadcf | |||
8b6d020352 | |||
5197916983 | |||
7e9d42da68 | |||
e34e0b45de | |||
ef2b54547e | |||
9856f0cc28 | |||
daa8c55667 | |||
af7ec4ead1 | |||
9e65ed1af1 | |||
7a92f89d12 | |||
5871ca9ce9 | |||
0dfa5babc2 | |||
e4b2ce4e81 | |||
7af4490fcc | |||
4204869ec9 | |||
ab23e8a656 | |||
5999b7ba46 | |||
7b613c1238 | |||
cee2359e33 | |||
37a7fb3d6a | |||
9d547a8a44 | |||
1fd5cd79c5 | |||
4d98cea085 | |||
b92c58d74b | |||
35d9759fa6 | |||
09bff5027d | |||
79f77afc98 | |||
594ee6d249 | |||
934841e236 | |||
49b76649f1 | |||
5d9bb5cf50 | |||
c8215315ae | |||
4d118b36a2 | |||
2c9b648502 | |||
5508689ea3 | |||
0f772270fb | |||
13e02063d6 | |||
9b75c65fc7 | |||
109ba7a3b4 | |||
b2c678877c | |||
ed220bd042 | |||
80f9f9aeec | |||
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?
|
||||
|
@ -8,10 +8,10 @@
|
||||
|
||||
set -e
|
||||
|
||||
cd "`dirname $0`/.." # cd to arduino-esp32 root
|
||||
# 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 'main.cpp' -prune -o -name '*.c' -print -o -name '*.cpp' -print | sort`
|
||||
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
|
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
|
226
.github/scripts/install-arduino-ide.sh
vendored
Executable file
226
.github/scripts/install-arduino-ide.sh
vendored
Executable file
@ -0,0 +1,226 @@
|
||||
#!/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>
|
||||
{
|
||||
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_sketches() # build_sketches <fqbn> <examples-path> <chunk> <total-chunks> [extra-options]
|
||||
{
|
||||
local fqbn=$1
|
||||
local examples=$2
|
||||
local chunk_idex=$3
|
||||
local chunks_num=$4
|
||||
local xtra_opts=$5
|
||||
|
||||
if [ "$#" -lt 2 ]; then
|
||||
echo "ERROR: Illegal number of parameters"
|
||||
echo "USAGE: build_sketches <fqbn> <examples-path> [<chunk> <total-chunks>] [extra-options]"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$#" -lt 4 ]; then
|
||||
chunk_idex="0"
|
||||
chunks_num="1"
|
||||
xtra_opts=$3
|
||||
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_sketch "$fqbn" "$sketch" "$xtra_opts"
|
||||
local result=$?
|
||||
if [ $result -ne 0 ]; then
|
||||
return $result
|
||||
fi
|
||||
done
|
||||
return 0
|
||||
}
|
148
.github/scripts/install-platformio-esp32.sh
vendored
Executable file
148
.github/scripts/install-platformio-esp32.sh
vendored
Executable file
@ -0,0 +1,148 @@
|
||||
#!/bin/bash
|
||||
|
||||
export PLATFORMIO_ESP32_PATH="$HOME/.platformio/packages/framework-arduinoespressif32"
|
||||
|
||||
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 https://github.com/platformio/platform-espressif32.git > /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> <path-to-ino>
|
||||
if [ "$#" -lt 2 ]; then
|
||||
echo "ERROR: Illegal number of parameters"
|
||||
echo "USAGE: build_pio_sketch <board> <path-to-ino>"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local board="$1"
|
||||
local sketch="$2"
|
||||
local sketch_dir=$(dirname "$sketch")
|
||||
echo ""
|
||||
echo "Compiling '"$(basename "$sketch")"' ..."
|
||||
python -m platformio ci --board "$board" "$sketch_dir" --project-option="board_build.partitions = huge_app.csv"
|
||||
}
|
||||
|
||||
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> <examples-path> <chunk> <total-chunks>
|
||||
{
|
||||
if [ "$#" -lt 2 ]; then
|
||||
echo "ERROR: Illegal number of parameters"
|
||||
echo "USAGE: build_pio_sketches <board> <examples-path> [<chunk> <total-chunks>]"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local board=$1
|
||||
local examples=$2
|
||||
local chunk_idex=$3
|
||||
local chunks_num=$4
|
||||
|
||||
if [ "$#" -lt 4 ]; 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" "$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)
|
||||
|
137
.github/scripts/on-pages.sh
vendored
Normal file
137
.github/scripts/on-pages.sh
vendored
Normal file
@ -0,0 +1,137 @@
|
||||
#/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`
|
||||
|
||||
echo "GITHUB_EVENT_PATH: $GITHUB_EVENT_PATH"
|
||||
echo "EVENT_JSON: $EVENT_JSON"
|
||||
|
||||
pages_added=`echo "$EVENT_JSON" | jq -r '.commits[].added[]'`
|
||||
echo "added: $pages_added"
|
||||
pages_modified=`echo "$EVENT_JSON" | jq -r '.commits[].modified[]'`
|
||||
echo "modified: $pages_modified"
|
||||
pages_removed=`echo "$EVENT_JSON" | jq -r '.commits[].removed[]'`
|
||||
echo "removed: $pages_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!"
|
71
.github/scripts/on-push.sh
vendored
Executable file
71
.github/scripts/on-push.sh
vendored
Executable file
@ -0,0 +1,71 @@
|
||||
#!/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 Test
|
||||
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/AzureIoT/examples/GetStarted/GetStarted.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/AzureIoT/examples/GetStarted/GetStarted.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" "$ARDUINO_ESP32_PATH/libraries" "$CHUNK_INDEX" "$CHUNKS_CNT"
|
||||
fi
|
||||
else
|
||||
# PlatformIO Test
|
||||
source ./.github/scripts/install-platformio-esp32.sh
|
||||
BOARD="esp32dev"
|
||||
build_pio_sketch "$BOARD" "$PLATFORMIO_ESP32_PATH/libraries/WiFi/examples/WiFiClient/WiFiClient.ino" && \
|
||||
build_pio_sketch "$BOARD" "$PLATFORMIO_ESP32_PATH/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino" && \
|
||||
build_pio_sketch "$BOARD" "$PLATFORMIO_ESP32_PATH/libraries/BluetoothSerial/examples/SerialToSerialBT/SerialToSerialBT.ino" && \
|
||||
build_pio_sketch "$BOARD" "$PLATFORMIO_ESP32_PATH/libraries/BLE/examples/BLE_server/BLE_server.ino" && \
|
||||
build_pio_sketch "$BOARD" "$PLATFORMIO_ESP32_PATH/libraries/AzureIoT/examples/GetStarted/GetStarted.ino" && \
|
||||
build_pio_sketch "$BOARD" "$PLATFORMIO_ESP32_PATH/libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino"
|
||||
#build_pio_sketches esp32dev "$PLATFORMIO_ESP32_PATH/libraries"
|
||||
fi
|
403
.github/scripts/on-release.sh
vendored
Executable file
403
.github/scripts/on-release.sh
vendored
Executable file
@ -0,0 +1,403 @@
|
||||
#!/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/"
|
||||
cp -f "$GITHUB_WORKSPACE/tools/platformio-build.py" "$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(.published_at | - fromdateiso8601) | .[0].tag_name")
|
||||
prev_any_release=$(echo "$releasesJson" | jq -e -r ". | map(select(.draft == false)) | sort_by(.published_at | - fromdateiso8601) | .[0].tag_name")
|
||||
prev_branch_release=$(echo "$releasesJson" | jq -e -r ". | map(select(.draft == false and .prerelease == false and .target_commitish == \"$RELEASE_BRANCH\")) | sort_by(.published_at | - fromdateiso8601) | .[0].tag_name")
|
||||
prev_branch_any_release=$(echo "$releasesJson" | jq -e -r ". | map(select(.draft == false and .target_commitish == \"$RELEASE_BRANCH\")) | sort_by(.published_at | - fromdateiso8601) | .[0].tag_name")
|
||||
shopt -s nocasematch
|
||||
if [ "$prev_release" == "$RELEASE_TAG" ]; then
|
||||
prev_release=$(echo "$releasesJson" | jq -e -r ". | map(select(.draft == false and .prerelease == false)) | sort_by(.published_at | - fromdateiso8601) | .[1].tag_name")
|
||||
fi
|
||||
if [ "$prev_any_release" == "$RELEASE_TAG" ]; then
|
||||
prev_any_release=$(echo "$releasesJson" | jq -e -r ". | map(select(.draft == false)) | sort_by(.published_at | - fromdateiso8601) | .[1].tag_name")
|
||||
fi
|
||||
if [ "$prev_branch_release" == "$RELEASE_TAG" ]; then
|
||||
prev_branch_release=$(echo "$releasesJson" | jq -e -r ". | map(select(.draft == false and .prerelease == false and .target_commitish == \"$RELEASE_BRANCH\")) | sort_by(.published_at | - fromdateiso8601) | .[1].tag_name")
|
||||
fi
|
||||
if [ "$prev_branch_any_release" == "$RELEASE_TAG" ]; then
|
||||
prev_branch_any_release=$(echo "$releasesJson" | jq -e -r ". | map(select(.draft == false and .target_commitish == \"$RELEASE_BRANCH\")) | sort_by(.published_at | - fromdateiso8601) | .[1].tag_name")
|
||||
fi
|
||||
shopt -u nocasematch
|
||||
set -e
|
||||
|
||||
echo "Previous Release: $prev_release"
|
||||
echo "Previous (any)release: $prev_any_release"
|
||||
echo
|
||||
|
||||
# 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
|
||||
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
|
||||
|
||||
# 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
|
||||
echo
|
||||
echo "Previous Branch Release: $prev_branch_release"
|
||||
echo "Previous Branch (any)release: $prev_branch_any_release"
|
||||
echo
|
||||
commitFile="$OUTPUT_DIR/commits.txt"
|
||||
COMMITS_SINCE_RELEASE="$prev_branch_any_release"
|
||||
if [ "$RELEASE_PRE" == "false" ]; then
|
||||
COMMITS_SINCE_RELEASE="$prev_branch_release"
|
||||
fi
|
||||
if [ ! -z "$COMMITS_SINCE_RELEASE" ] && [ "$COMMITS_SINCE_RELEASE" != "null" ]; then
|
||||
echo "Getting commits since $COMMITS_SINCE_RELEASE ..."
|
||||
git -C "$GITHUB_WORKSPACE" log --oneline -n 500 "$COMMITS_SINCE_RELEASE..HEAD" > "$commitFile"
|
||||
elif [ "$RELEASE_BRANCH" != "master" ]; then
|
||||
echo "Getting all commits on branch '$RELEASE_BRANCH' ..."
|
||||
git -C "$GITHUB_WORKSPACE" log --oneline -n 500 --cherry-pick --left-only --no-merges HEAD...origin/master > "$commitFile"
|
||||
else
|
||||
echo "Getting all commits on master ..."
|
||||
git -C "$GITHUB_WORKSPACE" log --oneline -n 500 --no-merges > "$commitFile"
|
||||
fi
|
||||
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
|
||||
|
||||
# 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!"
|
61
.github/stale.yml
vendored
Normal file
61
.github/stale.yml
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
# 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:
|
||||
- "Type: For reference"
|
||||
- "Type: To be implemented"
|
||||
- "Type: Feature request"
|
||||
|
||||
# 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: Status: 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
|
24
.github/workflows/gh-pages.yml
vendored
Normal file
24
.github/workflows/gh-pages.yml
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
name: GitHub Pages CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- pages
|
||||
paths:
|
||||
- 'README.md'
|
||||
- 'docs/**'
|
||||
- '.github/scripts/on-pages.sh'
|
||||
- '.github/workflows/gh-pages.yml'
|
||||
|
||||
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
|
22
.github/workflows/release.yml
vendored
Normal file
22
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
name: ESP32 Arduino Release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: published
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Publish Release
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- 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
|
13
.gitignore
vendored
13
.gitignore
vendored
@ -1,7 +1,16 @@
|
||||
tools/xtensa-esp32-elf
|
||||
tools/xtensa-esp32s2-elf
|
||||
tools/dist
|
||||
tools/esptool
|
||||
tools/esptool.exe
|
||||
tools/mkspiffs/mkspiffs
|
||||
tools/mkspiffs/mkspiffs.exe
|
||||
tools/mkspiffs
|
||||
tools/mklittlefs
|
||||
.DS_Store
|
||||
|
||||
#Ignore files built by Visual Studio/Visual Micro
|
||||
[Dd]ebug*/
|
||||
[Rr]elease*/
|
||||
.vs/
|
||||
__vm/
|
||||
*.vcxproj*
|
||||
.vscode/
|
||||
|
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:
|
||||
|
@ -7,6 +7,7 @@ set(CORE_SRCS
|
||||
cores/esp32/esp32-hal-dac.c
|
||||
cores/esp32/esp32-hal-gpio.c
|
||||
cores/esp32/esp32-hal-i2c.c
|
||||
cores/esp32/esp32-hal-log.c
|
||||
cores/esp32/esp32-hal-ledc.c
|
||||
cores/esp32/esp32-hal-matrix.c
|
||||
cores/esp32/esp32-hal-misc.c
|
||||
@ -60,6 +61,7 @@ set(LIBRARY_SRCS
|
||||
libraries/SPI/src/SPI.cpp
|
||||
libraries/Ticker/src/Ticker.cpp
|
||||
libraries/Update/src/Updater.cpp
|
||||
libraries/Update/src/HttpsOTAUpdate.cpp
|
||||
libraries/WebServer/src/WebServer.cpp
|
||||
libraries/WebServer/src/Parsing.cpp
|
||||
libraries/WebServer/src/detail/mimetable.cpp
|
||||
@ -75,6 +77,7 @@ set(LIBRARY_SRCS
|
||||
libraries/WiFi/src/WiFiServer.cpp
|
||||
libraries/WiFi/src/WiFiSTA.cpp
|
||||
libraries/WiFi/src/WiFiUdp.cpp
|
||||
libraries/WiFiProv/src/WiFiProv.cpp
|
||||
libraries/Wire/src/Wire.cpp
|
||||
)
|
||||
|
||||
@ -200,12 +203,18 @@ set(COMPONENT_ADD_INCLUDEDIRS
|
||||
libraries/WebServer/src
|
||||
libraries/WiFiClientSecure/src
|
||||
libraries/WiFi/src
|
||||
libraries/WiFiProv/src
|
||||
libraries/Wire/src
|
||||
)
|
||||
|
||||
set(COMPONENT_PRIV_INCLUDEDIRS cores/esp32/libb64)
|
||||
|
||||
set(COMPONENT_REQUIRES spi_flash mbedtls mdns ethernet)
|
||||
set(COMPONENT_PRIV_REQUIRES fatfs nvs_flash app_update spiffs bootloader_support openssl bt)
|
||||
set(COMPONENT_REQUIRES spi_flash mbedtls mdns ethernet esp_adc_cal wifi_provisioning)
|
||||
set(COMPONENT_PRIV_REQUIRES fatfs nvs_flash app_update spiffs bootloader_support openssl bt esp_http_client esp_https_ota)
|
||||
|
||||
register_component()
|
||||
|
||||
set_source_files_properties(libraries/AzureIoT/src/az_iot/iothub_client/src/iothubtransport_mqtt_common.c
|
||||
PROPERTIES COMPILE_FLAGS
|
||||
-Wno-maybe-uninitialized
|
||||
)
|
||||
|
@ -19,6 +19,81 @@ 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
|
||||
|
||||
config ARDUINO_LOOP_STACK_SIZE
|
||||
int "Loop thread stack size"
|
||||
default 8192
|
||||
help
|
||||
Amount of stack available for the Arduino task.
|
||||
|
||||
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_TASK_PRIORITY
|
||||
int "Priority of the UDP task"
|
||||
default 3
|
||||
help
|
||||
Select at what priority you want the UDP task to run.
|
||||
|
||||
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 DISABLE_HAL_LOCKS
|
||||
bool "Disable mutex locks for HAL"
|
||||
default "n"
|
||||
@ -168,6 +243,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!
|
27
README.md
27
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,14 @@
|
||||
- [Issue/Bug report template](#issuebug-report-template)
|
||||
- [ESP32Dev Board PINMAP](#esp32dev-board-pinmap)
|
||||
|
||||
## Development Status
|
||||
[Latest stable release  ](https://github.com/espressif/arduino-esp32/releases/latest/) 
|
||||
### Development Status
|
||||
|
||||
[Latest development release  ](https://github.com/espressif/arduino-esp32/releases/latest/) 
|
||||
Latest Stable Release [](https://github.com/espressif/arduino-esp32/releases/latest/) [](https://github.com/espressif/arduino-esp32/releases/latest/) [](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
|
||||
Latest Development Release [](https://github.com/espressif/arduino-esp32/releases/latest/) [](https://github.com/espressif/arduino-esp32/releases/latest/) [](https://github.com/espressif/arduino-esp32/releases/latest/)
|
||||
|
||||
## 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 +31,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
|
3279
boards.txt
3279
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)
|
||||
@ -84,7 +78,7 @@
|
||||
#define interrupts() sei()
|
||||
#define noInterrupts() cli()
|
||||
|
||||
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
|
||||
#define clockCyclesPerMicrosecond() ( (long int)getCpuFrequencyMhz() )
|
||||
#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
|
||||
#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )
|
||||
|
||||
@ -94,7 +88,7 @@
|
||||
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
|
||||
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
|
||||
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
|
||||
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
|
||||
#define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet(value, bit) : bitClear(value, bit))
|
||||
|
||||
// avr-libc defines _NOP() since 1.6.2
|
||||
#ifndef _NOP
|
||||
@ -160,6 +154,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;
|
||||
|
@ -92,13 +92,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();
|
||||
@ -225,6 +218,33 @@ uint8_t EspClass::getChipRevision(void)
|
||||
return chip_info.revision;
|
||||
}
|
||||
|
||||
const char * EspClass::getChipModel(void)
|
||||
{
|
||||
uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_PKG);
|
||||
uint32_t pkg_ver = chip_ver & 0x7;
|
||||
switch (pkg_ver) {
|
||||
case EFUSE_RD_CHIP_VER_PKG_ESP32D0WDQ6 :
|
||||
return "ESP32-D0WDQ6";
|
||||
case EFUSE_RD_CHIP_VER_PKG_ESP32D0WDQ5 :
|
||||
return "ESP32-D0WDQ5";
|
||||
case EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 :
|
||||
return "ESP32-D2WDQ5";
|
||||
case EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2 :
|
||||
return "ESP32-PICO-D2";
|
||||
case EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4 :
|
||||
return "ESP32-PICO-D4";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t EspClass::getChipCores(void)
|
||||
{
|
||||
esp_chip_info_t chip_info;
|
||||
esp_chip_info(&chip_info);
|
||||
return chip_info.cores;
|
||||
}
|
||||
|
||||
const char * EspClass::getSdkVersion(void)
|
||||
{
|
||||
return esp_get_idf_version();
|
||||
@ -316,6 +336,20 @@ bool EspClass::flashRead(uint32_t offset, uint32_t *data, size_t size)
|
||||
return spi_flash_read(offset, (uint32_t*) data, size) == ESP_OK;
|
||||
}
|
||||
|
||||
bool EspClass::partitionEraseRange(const esp_partition_t *partition, uint32_t offset, size_t size)
|
||||
{
|
||||
return esp_partition_erase_range(partition, offset, size) == ESP_OK;
|
||||
}
|
||||
|
||||
bool EspClass::partitionWrite(const esp_partition_t *partition, uint32_t offset, uint32_t *data, size_t size)
|
||||
{
|
||||
return esp_partition_write(partition, offset, data, size) == ESP_OK;
|
||||
}
|
||||
|
||||
bool EspClass::partitionRead(const esp_partition_t *partition, uint32_t offset, uint32_t *data, size_t size)
|
||||
{
|
||||
return esp_partition_read(partition, offset, data, size) == ESP_OK;
|
||||
}
|
||||
|
||||
uint64_t EspClass::getEfuseMac(void)
|
||||
{
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define ESP_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <esp_partition.h>
|
||||
|
||||
/**
|
||||
* AVR macros for WDT managment
|
||||
@ -75,8 +76,10 @@ public:
|
||||
uint32_t getMaxAllocPsram();
|
||||
|
||||
uint8_t getChipRevision();
|
||||
uint8_t getCpuFreqMHz(){ return CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ; }
|
||||
uint32_t getCycleCount();
|
||||
const char * getChipModel();
|
||||
uint8_t getChipCores();
|
||||
uint32_t getCpuFreqMHz(){ return getCpuFrequencyMhz(); }
|
||||
inline uint32_t getCycleCount() __attribute__((always_inline));
|
||||
const char * getSdkVersion();
|
||||
|
||||
void deepSleep(uint32_t time_us);
|
||||
@ -97,10 +100,21 @@ public:
|
||||
bool flashWrite(uint32_t offset, uint32_t *data, size_t size);
|
||||
bool flashRead(uint32_t offset, uint32_t *data, size_t size);
|
||||
|
||||
bool partitionEraseRange(const esp_partition_t *partition, uint32_t offset, size_t size);
|
||||
bool partitionWrite(const esp_partition_t *partition, uint32_t offset, uint32_t *data, size_t size);
|
||||
bool partitionRead(const esp_partition_t *partition, uint32_t offset, uint32_t *data, size_t size);
|
||||
|
||||
uint64_t getEfuseMac();
|
||||
|
||||
};
|
||||
|
||||
uint32_t IRAM_ATTR EspClass::getCycleCount()
|
||||
{
|
||||
uint32_t ccount;
|
||||
__asm__ __volatile__("esync; rsr %0,ccount":"=a" (ccount));
|
||||
return ccount;
|
||||
}
|
||||
|
||||
extern EspClass ESP;
|
||||
|
||||
#endif //ESP_H
|
||||
|
@ -53,8 +53,11 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
|
||||
}
|
||||
|
||||
_uart = uartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, 256, invert);
|
||||
_tx_pin = txPin;
|
||||
_rx_pin = rxPin;
|
||||
|
||||
if(!baud) {
|
||||
uartStartDetectBaudrate(_uart);
|
||||
time_t startMillis = millis();
|
||||
unsigned long detectedBaudRate = 0;
|
||||
while(millis() - startMillis < timeout_ms && !(detectedBaudRate = uartDetectBaudrate(_uart))) {
|
||||
@ -69,6 +72,8 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
|
||||
} else {
|
||||
log_e("Could not detect baudrate. Serial data at the port must be present within the timeout for detection to be possible");
|
||||
_uart = NULL;
|
||||
_tx_pin = 255;
|
||||
_rx_pin = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -83,7 +88,8 @@ void HardwareSerial::end()
|
||||
if(uartGetDebug() == _uart_nr) {
|
||||
uartSetDebug(0);
|
||||
}
|
||||
uartEnd(_uart);
|
||||
log_v("pins %d %d",_tx_pin, _rx_pin);
|
||||
uartEnd(_uart, _tx_pin, _rx_pin);
|
||||
_uart = 0;
|
||||
}
|
||||
|
||||
@ -130,11 +136,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);
|
||||
@ -155,3 +184,8 @@ HardwareSerial::operator bool() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void HardwareSerial::setRxInvert(bool invert)
|
||||
{
|
||||
uartSetRxInvert(_uart, invert);
|
||||
}
|
||||
|
@ -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));
|
||||
@ -91,16 +100,22 @@ public:
|
||||
|
||||
size_t setRxBufferSize(size_t);
|
||||
void setDebugOutput(bool);
|
||||
|
||||
void setRxInvert(bool);
|
||||
|
||||
protected:
|
||||
int _uart_nr;
|
||||
uart_t* _uart;
|
||||
uint8_t _tx_pin;
|
||||
uint8_t _rx_pin;
|
||||
};
|
||||
|
||||
extern void serialEventRun(void) __attribute__((weak));
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
|
||||
extern HardwareSerial Serial;
|
||||
extern HardwareSerial Serial1;
|
||||
extern HardwareSerial Serial2;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif // HardwareSerial_h
|
||||
|
@ -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;
|
||||
}
|
||||
@ -106,18 +111,12 @@ size_t Print::print(unsigned int n, int base)
|
||||
|
||||
size_t Print::print(long n, int base)
|
||||
{
|
||||
if(base == 0) {
|
||||
return write(n);
|
||||
} else if(base == 10) {
|
||||
if(n < 0) {
|
||||
int t = print('-');
|
||||
n = -n;
|
||||
return printNumber(n, 10) + t;
|
||||
}
|
||||
return printNumber(n, 10);
|
||||
} else {
|
||||
return printNumber(n, base);
|
||||
int t = 0;
|
||||
if (base == 10 && n < 0) {
|
||||
t = print('-');
|
||||
n = -n;
|
||||
}
|
||||
return printNumber(static_cast<unsigned long>(n), base) + t;
|
||||
}
|
||||
|
||||
size_t Print::print(unsigned long n, int base)
|
||||
@ -129,6 +128,25 @@ size_t Print::print(unsigned long n, int base)
|
||||
}
|
||||
}
|
||||
|
||||
size_t Print::print(long long n, int base)
|
||||
{
|
||||
int t = 0;
|
||||
if (base == 10 && n < 0) {
|
||||
t = print('-');
|
||||
n = -n;
|
||||
}
|
||||
return printNumber(static_cast<unsigned long long>(n), base) + t;
|
||||
}
|
||||
|
||||
size_t Print::print(unsigned long long n, int base)
|
||||
{
|
||||
if (base == 0) {
|
||||
return write(n);
|
||||
} else {
|
||||
return printNumber(n, base);
|
||||
}
|
||||
}
|
||||
|
||||
size_t Print::print(double n, int digits)
|
||||
{
|
||||
return printFloat(n, digits);
|
||||
@ -154,8 +172,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)
|
||||
@ -219,6 +239,20 @@ size_t Print::println(unsigned long num, int base)
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(long long num, int base)
|
||||
{
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(unsigned long long num, int base)
|
||||
{
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(double num, int digits)
|
||||
{
|
||||
size_t n = print(num, digits);
|
||||
@ -244,7 +278,7 @@ size_t Print::println(struct tm * timeinfo, const char * format)
|
||||
|
||||
size_t Print::printNumber(unsigned long n, uint8_t base)
|
||||
{
|
||||
char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
|
||||
char buf[8 * sizeof(n) + 1]; // Assumes 8-bit chars plus zero byte.
|
||||
char *str = &buf[sizeof(buf) - 1];
|
||||
|
||||
*str = '\0';
|
||||
@ -255,11 +289,34 @@ size_t Print::printNumber(unsigned long n, uint8_t base)
|
||||
}
|
||||
|
||||
do {
|
||||
unsigned long m = n;
|
||||
char c = n % base;
|
||||
n /= base;
|
||||
|
||||
*--str = c < 10 ? c + '0' : c + 'A' - 10;
|
||||
} while (n);
|
||||
|
||||
return write(str);
|
||||
}
|
||||
|
||||
size_t Print::printNumber(unsigned long long n, uint8_t base)
|
||||
{
|
||||
char buf[8 * sizeof(n) + 1]; // Assumes 8-bit chars plus zero byte.
|
||||
char* str = &buf[sizeof(buf) - 1];
|
||||
|
||||
*str = '\0';
|
||||
|
||||
// prevent crash if called with base == 1
|
||||
if (base < 2) {
|
||||
base = 10;
|
||||
}
|
||||
|
||||
do {
|
||||
auto m = n;
|
||||
n /= base;
|
||||
char c = m - base * n;
|
||||
|
||||
*--str = c < 10 ? c + '0' : c + 'A' - 10;
|
||||
} while(n);
|
||||
} while (n);
|
||||
|
||||
return write(str);
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ class Print
|
||||
private:
|
||||
int write_error;
|
||||
size_t printNumber(unsigned long, uint8_t);
|
||||
size_t printNumber(unsigned long long, uint8_t);
|
||||
size_t printFloat(double, uint8_t);
|
||||
protected:
|
||||
void setWriteError(int err = 1)
|
||||
@ -72,6 +73,11 @@ public:
|
||||
}
|
||||
|
||||
size_t printf(const char * format, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
|
||||
// add availableForWrite to make compatible with Arduino Print.h
|
||||
// default to zero, meaning "a single write may block"
|
||||
// should be overriden by subclasses with buffering
|
||||
virtual int availableForWrite() { return 0; }
|
||||
size_t print(const __FlashStringHelper *);
|
||||
size_t print(const String &);
|
||||
size_t print(const char[]);
|
||||
@ -81,6 +87,8 @@ public:
|
||||
size_t print(unsigned int, int = DEC);
|
||||
size_t print(long, int = DEC);
|
||||
size_t print(unsigned long, int = DEC);
|
||||
size_t print(long long, int = DEC);
|
||||
size_t print(unsigned long long, int = DEC);
|
||||
size_t print(double, int = 2);
|
||||
size_t print(const Printable&);
|
||||
size_t print(struct tm * timeinfo, const char * format = NULL);
|
||||
@ -94,6 +102,8 @@ public:
|
||||
size_t println(unsigned int, int = DEC);
|
||||
size_t println(long, int = DEC);
|
||||
size_t println(unsigned long, int = DEC);
|
||||
size_t println(long long, int = DEC);
|
||||
size_t println(unsigned long long, int = DEC);
|
||||
size_t println(double, int = 2);
|
||||
size_t println(const Printable&);
|
||||
size_t println(struct tm * timeinfo, const char * format = NULL);
|
||||
|
@ -87,22 +87,22 @@ unsigned long Stream::getTimeout(void) {
|
||||
}
|
||||
|
||||
// find returns true if the target string is found
|
||||
bool Stream::find(const char *target)
|
||||
bool Stream::find(const char *target)
|
||||
{
|
||||
return findUntil(target, (char*) "");
|
||||
return findUntil(target, strlen(target), NULL, 0);
|
||||
}
|
||||
|
||||
// reads data from the stream until the target string of given length is found
|
||||
// returns true if target string is found, false if timed out
|
||||
bool Stream::find(const char *target, size_t length)
|
||||
{
|
||||
return findUntil(target, length, NULL, 0);
|
||||
return findUntil(target, length, NULL, 0);
|
||||
}
|
||||
|
||||
// as find but search ends if the terminator string is found
|
||||
bool Stream::findUntil(const char *target, const char *terminator)
|
||||
bool Stream::findUntil(const char *target, const char *terminator)
|
||||
{
|
||||
return findUntil(target, strlen(target), terminator, strlen(terminator));
|
||||
return findUntil(target, strlen(target), terminator, strlen(terminator));
|
||||
}
|
||||
|
||||
// reads data from the stream until the target string of the given length is found
|
||||
@ -110,35 +110,78 @@ bool Stream::findUntil(const char *target, const char *terminator)
|
||||
// returns true if target string is found, false if terminated or timed out
|
||||
bool Stream::findUntil(const char *target, size_t targetLen, const char *terminator, size_t termLen)
|
||||
{
|
||||
size_t index = 0; // maximum target string length is 64k bytes!
|
||||
size_t termIndex = 0;
|
||||
int c;
|
||||
if (terminator == NULL) {
|
||||
MultiTarget t[1] = {{target, targetLen, 0}};
|
||||
return findMulti(t, 1) == 0 ? true : false;
|
||||
} else {
|
||||
MultiTarget t[2] = {{target, targetLen, 0}, {terminator, termLen, 0}};
|
||||
return findMulti(t, 2) == 0 ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
if(*target == 0) {
|
||||
return true; // return true if target is a null string
|
||||
int Stream::findMulti( struct Stream::MultiTarget *targets, int tCount) {
|
||||
// any zero length target string automatically matches and would make
|
||||
// a mess of the rest of the algorithm.
|
||||
for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
|
||||
if (t->len <= 0)
|
||||
return t - targets;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
int c = timedRead();
|
||||
if (c < 0)
|
||||
return -1;
|
||||
|
||||
for (struct MultiTarget *t = targets; t < targets+tCount; ++t) {
|
||||
// the simple case is if we match, deal with that first.
|
||||
if (c == t->str[t->index]) {
|
||||
if (++t->index == t->len)
|
||||
return t - targets;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
// if not we need to walk back and see if we could have matched further
|
||||
// down the stream (ie '1112' doesn't match the first position in '11112'
|
||||
// but it will match the second position so we can't just reset the current
|
||||
// index to 0 when we find a mismatch.
|
||||
if (t->index == 0)
|
||||
continue;
|
||||
|
||||
int origIndex = t->index;
|
||||
do {
|
||||
--t->index;
|
||||
// first check if current char works against the new current index
|
||||
if (c != t->str[t->index])
|
||||
continue;
|
||||
|
||||
// if it's the only char then we're good, nothing more to check
|
||||
if (t->index == 0) {
|
||||
t->index++;
|
||||
break;
|
||||
}
|
||||
|
||||
// otherwise we need to check the rest of the found string
|
||||
int diff = origIndex - t->index;
|
||||
size_t i;
|
||||
for (i = 0; i < t->index; ++i) {
|
||||
if (t->str[i] != t->str[i + diff])
|
||||
break;
|
||||
}
|
||||
|
||||
// if we successfully got through the previous loop then our current
|
||||
// index is good.
|
||||
if (i == t->index) {
|
||||
t->index++;
|
||||
break;
|
||||
}
|
||||
|
||||
// otherwise we just try the next index
|
||||
} while (t->index);
|
||||
}
|
||||
while((c = timedRead()) > 0) {
|
||||
|
||||
if(c != target[index]) {
|
||||
index = 0; // reset index if any char does not match
|
||||
}
|
||||
|
||||
if(c == target[index]) {
|
||||
//////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1);
|
||||
if(++index >= targetLen) { // return true if all chars in the target match
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(termLen > 0 && c == terminator[termIndex]) {
|
||||
if(++termIndex >= termLen) {
|
||||
return false; // return false if terminate string found before target string
|
||||
}
|
||||
} else {
|
||||
termIndex = 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// unreachable
|
||||
return -1;
|
||||
}
|
||||
|
||||
// returns the first valid (long) integer value from the current position.
|
||||
|
@ -60,6 +60,7 @@ public:
|
||||
|
||||
void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second
|
||||
unsigned long getTimeout(void);
|
||||
|
||||
bool find(const char *target); // reads data from the stream until the target string is found
|
||||
bool find(uint8_t *target)
|
||||
{
|
||||
@ -97,8 +98,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 +115,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:
|
||||
@ -123,6 +124,17 @@ protected:
|
||||
// this allows format characters (typically commas) in values to be ignored
|
||||
|
||||
float parseFloat(char skipChar); // as above but the given skipChar is ignored
|
||||
|
||||
struct MultiTarget {
|
||||
const char *str; // string you're searching for
|
||||
size_t len; // length of string you're searching for
|
||||
size_t index; // index used by the search routine.
|
||||
};
|
||||
|
||||
// This allows you to search for an arbitrary number of strings.
|
||||
// Returns index of the target that is found first or -1 if timeout occurs.
|
||||
int findMulti(struct MultiTarget *targets, int tCount);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -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() {
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,7 @@ class UDP: public Stream
|
||||
|
||||
public:
|
||||
virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use
|
||||
virtual uint8_t beginMulticast(IPAddress, uint16_t) { return 0; } // initialize, start listening on specified multicast IP address and port. Returns 1 if successful, 0 on failure
|
||||
virtual void stop() =0; // Finish with the UDP socket
|
||||
|
||||
// Sending UDP packets
|
||||
|
@ -27,6 +27,7 @@ extern "C" {
|
||||
#include <stdlib.h>
|
||||
#include "esp_system.h"
|
||||
}
|
||||
#include "esp32-hal-log.h"
|
||||
|
||||
void randomSeed(unsigned long seed)
|
||||
{
|
||||
@ -44,7 +45,7 @@ long random(long howbig)
|
||||
uint32_t t = -howbig;
|
||||
if (t >= howbig) {
|
||||
t -= howbig;
|
||||
if (t >= howbig)
|
||||
if (t >= howbig)
|
||||
t %= howbig;
|
||||
}
|
||||
while (l < t) {
|
||||
@ -65,9 +66,15 @@ 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) {
|
||||
const long dividend = out_max - out_min;
|
||||
const long divisor = in_max - in_min;
|
||||
const long delta = x - in_min;
|
||||
if(divisor == 0){
|
||||
log_e("Invalid map input range, min == max");
|
||||
return -1; //AVR returns -1, SAM returns 0
|
||||
}
|
||||
return (delta * dividend + (divisor / 2)) / 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,337 @@ 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;
|
||||
sso.buff[len] = 0;
|
||||
} else {
|
||||
ptr.len = len;
|
||||
if (ptr.buff) {
|
||||
ptr.buff[len] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
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:
|
||||
};
|
||||
|
||||
|
@ -22,14 +22,16 @@
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/sens_reg.h"
|
||||
|
||||
#include "driver/adc.h"
|
||||
#include "esp_adc_cal.h"
|
||||
|
||||
#define DEFAULT_VREF 1100
|
||||
static esp_adc_cal_characteristics_t *__analogCharacteristics[2] = {NULL, NULL};
|
||||
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;
|
||||
static uint16_t __analogVRef = 0;
|
||||
static uint8_t __analogVRefPin = 0;
|
||||
|
||||
void __analogSetWidth(uint8_t bits){
|
||||
if(bits < 9){
|
||||
@ -37,81 +39,31 @@ void __analogSetWidth(uint8_t bits){
|
||||
} 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);
|
||||
}
|
||||
|
||||
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);
|
||||
adc1_config_width(__analogWidth);
|
||||
}
|
||||
|
||||
void __analogSetClockDiv(uint8_t clockDiv){
|
||||
if(!clockDiv){
|
||||
return;
|
||||
clockDiv = 1;
|
||||
}
|
||||
__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);
|
||||
adc_set_clk_div(__analogClockDiv);
|
||||
}
|
||||
|
||||
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
|
||||
initialized = true;
|
||||
__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;
|
||||
}
|
||||
|
||||
void __analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation)
|
||||
@ -120,21 +72,20 @@ 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){
|
||||
uint32_t touch = READ_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG);
|
||||
@ -151,86 +102,103 @@ 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;
|
||||
}
|
||||
__analogSetWidth(bits); // hadware from 9 to 12
|
||||
__analogReturnedWidth = bits; // software from 1 to 16
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void __analogSetVRefPin(uint8_t pin){
|
||||
if(pin <25 || pin > 27){
|
||||
pin = 0;
|
||||
}
|
||||
__analogVRefPin = pin;
|
||||
}
|
||||
|
||||
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(!__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]);
|
||||
}
|
||||
|
||||
int __hallRead() //hall sensor without LNA
|
||||
@ -260,14 +228,12 @@ int __hallRead() //hall sensor without LNA
|
||||
extern uint16_t analogRead(uint8_t pin) __attribute__ ((weak, alias("__analogRead")));
|
||||
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")));
|
||||
|
||||
extern void analogSetVRefPin(uint8_t pin) __attribute__ ((weak, alias("__analogSetVRefPin")));
|
||||
extern uint32_t analogReadMilliVolts(uint8_t pin) __attribute__ ((weak, alias("__analogReadMilliVolts")));
|
||||
|
@ -54,24 +54,6 @@ void analogReadResolution(uint8_t bits);
|
||||
* */
|
||||
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
|
||||
@ -97,34 +79,20 @@ void analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation);
|
||||
* */
|
||||
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);
|
||||
|
||||
/*
|
||||
* Start ADC conversion on attached pin's bus
|
||||
* Set pin to use for ADC calibration if the esp is not already calibrated (25, 26 or 27)
|
||||
* */
|
||||
bool adcStart(uint8_t pin);
|
||||
void analogSetVRefPin(uint8_t pin);
|
||||
|
||||
/*
|
||||
* Check if conversion on the pin's ADC bus is currently running
|
||||
* Get MilliVolts value for pin
|
||||
* */
|
||||
bool adcBusy(uint8_t pin);
|
||||
|
||||
/*
|
||||
* Get the result of the conversion (will wait if it have not finished)
|
||||
* */
|
||||
uint16_t adcEnd(uint8_t pin);
|
||||
uint32_t analogReadMilliVolts(uint8_t pin);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -18,11 +18,12 @@
|
||||
|
||||
bool btInUse(){ return true; }
|
||||
|
||||
#ifdef CONFIG_BLUEDROID_ENABLED
|
||||
#include "esp_bt.h"
|
||||
|
||||
#ifdef CONFIG_CLASSIC_BT_ENABLED
|
||||
#ifdef CONFIG_BTDM_CONTROLLER_MODE_BTDM
|
||||
#define BT_MODE ESP_BT_MODE_BTDM
|
||||
#elif defined(CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY)
|
||||
#define BT_MODE ESP_BT_MODE_CLASSIC_BT
|
||||
#else
|
||||
#define BT_MODE ESP_BT_MODE_BLE
|
||||
#endif
|
||||
@ -65,13 +66,21 @@ 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");
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
#else // CONFIG_BT_ENABLED
|
||||
bool btStarted()
|
||||
{
|
||||
return false;
|
||||
@ -86,6 +95,6 @@ bool btStop()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_BT_ENABLED
|
||||
|
||||
|
@ -23,10 +23,12 @@
|
||||
#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"
|
||||
|
||||
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;
|
||||
@ -52,9 +54,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 +79,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 +87,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 +109,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;
|
||||
@ -150,6 +162,15 @@ bool setCpuFrequencyMhz(uint32_t cpu_freq_mhz){
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//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;
|
||||
}
|
||||
}
|
||||
//Get current CPU clock configuration
|
||||
rtc_clk_cpu_freq_get_config(&cconf);
|
||||
//return if frequency has not changed
|
||||
@ -176,7 +197,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
|
||||
|
@ -59,8 +59,8 @@ 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},
|
||||
|
@ -945,6 +945,14 @@ static void IRAM_ATTR i2c_isr_handler_default(void* arg)
|
||||
activeInt &=~I2C_RXFIFO_FULL_INT_ST;
|
||||
}
|
||||
|
||||
if(activeInt & I2C_RXFIFO_OVF_INT_ST) {
|
||||
emptyRxFifo(p_i2c);
|
||||
p_i2c->dev->int_clr.rx_fifo_full=1;
|
||||
p_i2c->dev->int_ena.rx_fifo_full=1; //why?
|
||||
|
||||
activeInt &=~I2C_RXFIFO_OVF_INT_ST;
|
||||
}
|
||||
|
||||
if (activeInt & I2C_ACK_ERR_INT_ST_M) {//fatal error, abort i2c service
|
||||
if (p_i2c->mode == I2C_MASTER) {
|
||||
i2c_update_error_byte_cnt(p_i2c); // calc which byte caused ack Error, check if address or data
|
||||
@ -1270,7 +1278,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 +1286,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
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
#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 +55,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 +93,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
|
||||
@ -105,8 +116,7 @@ static void _ledcSetupTimer(uint8_t chan, uint32_t div_num, uint8_t bit_num, boo
|
||||
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)
|
||||
|
19
cores/esp32/esp32-hal-log.c
Normal file
19
cores/esp32/esp32-hal-log.c
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef __MY_LOG__
|
||||
#define __MY_LOG__
|
||||
#include "stdio.h"
|
||||
#include "esp32-hal-log.h"
|
||||
void log_to_esp(char* tag, esp_log_level_t level, const char *format, ...)
|
||||
{
|
||||
va_list va_args;
|
||||
va_start(va_args, format);
|
||||
|
||||
char log_buffer[512];
|
||||
int len = vsnprintf(log_buffer, sizeof(log_buffer), format, va_args);
|
||||
if (len > 0)
|
||||
{
|
||||
ESP_LOG_LEVEL_LOCAL(level, tag, "%s", log_buffer);
|
||||
}
|
||||
|
||||
va_end(va_args);
|
||||
}
|
||||
#endif
|
@ -36,6 +36,9 @@ extern "C"
|
||||
#define ARDUHAL_LOG_LEVEL CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL
|
||||
#else
|
||||
#define ARDUHAL_LOG_LEVEL CORE_DEBUG_LEVEL
|
||||
#ifdef USE_ESP_IDF_LOG
|
||||
#define LOG_LOCAL_LEVEL CORE_DEBUG_LEVEL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_ARDUHAL_LOG_COLORS
|
||||
@ -71,6 +74,8 @@ extern "C"
|
||||
#define ARDUHAL_LOG_RESET_COLOR
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
const char * pathToFileName(const char * path);
|
||||
int log_printf(const char *fmt, ...);
|
||||
|
||||
@ -78,55 +83,92 @@ int log_printf(const char *fmt, ...);
|
||||
#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__
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
|
||||
#ifndef USE_ESP_IDF_LOG
|
||||
#define log_v(format, ...) log_printf(ARDUHAL_LOG_FORMAT(V, format), ##__VA_ARGS__)
|
||||
#define isr_log_v(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(V, format), ##__VA_ARGS__)
|
||||
#else
|
||||
#define log_v(format, ...) do {log_to_esp(TAG, ESP_LOG_VERBOSE, format, ##__VA_ARGS__);}while(0)
|
||||
#define isr_log_v(format, ...) do {ets_printf(LOG_FORMAT(V, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
|
||||
#endif
|
||||
#else
|
||||
#define log_v(format, ...)
|
||||
#define isr_log_v(format, ...)
|
||||
#endif
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
|
||||
#ifndef USE_ESP_IDF_LOG
|
||||
#define log_d(format, ...) log_printf(ARDUHAL_LOG_FORMAT(D, format), ##__VA_ARGS__)
|
||||
#define isr_log_d(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(D, format), ##__VA_ARGS__)
|
||||
#else
|
||||
#define log_d(format, ...) do {log_to_esp(TAG, ESP_LOG_DEBUG, format, ##__VA_ARGS__);}while(0)
|
||||
#define isr_log_d(format, ...) do {ets_printf(LOG_FORMAT(D, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
|
||||
#endif
|
||||
#else
|
||||
#define log_d(format, ...)
|
||||
#define isr_log_d(format, ...)
|
||||
#endif
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
#ifndef USE_ESP_IDF_LOG
|
||||
#define log_i(format, ...) log_printf(ARDUHAL_LOG_FORMAT(I, format), ##__VA_ARGS__)
|
||||
#define isr_log_i(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(I, format), ##__VA_ARGS__)
|
||||
#else
|
||||
#define log_i(format, ...) do {log_to_esp(TAG, ESP_LOG_INFO, format, ##__VA_ARGS__);}while(0)
|
||||
#define isr_log_i(format, ...) do {ets_printf(LOG_FORMAT(I, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
|
||||
#endif
|
||||
#else
|
||||
#define log_i(format, ...)
|
||||
#define isr_log_i(format, ...)
|
||||
#endif
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_WARN
|
||||
#ifndef USE_ESP_IDF_LOG
|
||||
#define log_w(format, ...) log_printf(ARDUHAL_LOG_FORMAT(W, format), ##__VA_ARGS__)
|
||||
#define isr_log_w(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(W, format), ##__VA_ARGS__)
|
||||
#else
|
||||
#define log_w(format, ...) do {log_to_esp(TAG, ESP_LOG_WARN, format, ##__VA_ARGS__);}while(0)
|
||||
#define isr_log_w(format, ...) do {ets_printf(LOG_FORMAT(W, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
|
||||
#endif
|
||||
#else
|
||||
#define log_w(format, ...)
|
||||
#define isr_log_w(format, ...)
|
||||
#endif
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
|
||||
#ifndef USE_ESP_IDF_LOG
|
||||
#define log_e(format, ...) log_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__)
|
||||
#define isr_log_e(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__)
|
||||
#else
|
||||
#define log_e(format, ...) do {log_to_esp(TAG, ESP_LOG_ERROR, format, ##__VA_ARGS__);}while(0)
|
||||
#define isr_log_e(format, ...) do {ets_printf(LOG_FORMAT(E, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
|
||||
#endif
|
||||
#else
|
||||
#define log_e(format, ...)
|
||||
#define isr_log_e(format, ...)
|
||||
#endif
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_NONE
|
||||
#ifndef USE_ESP_IDF_LOG
|
||||
#define log_n(format, ...) log_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__)
|
||||
#define isr_log_n(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__)
|
||||
#else
|
||||
#define log_n(format, ...) do {log_to_esp(TAG, ESP_LOG_ERROR, format, ##__VA_ARGS__);}while(0)
|
||||
#define isr_log_n(format, ...) do {ets_printf(LOG_FORMAT(E, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
|
||||
#endif
|
||||
#else
|
||||
#define log_n(format, ...)
|
||||
#define isr_log_n(format, ...)
|
||||
#endif
|
||||
|
||||
#include "esp_log.h"
|
||||
|
||||
#ifdef USE_ESP_IDF_LOG
|
||||
#ifndef TAG
|
||||
#define TAG "ARDUINO"
|
||||
#endif
|
||||
void log_to_esp(char* tag, esp_log_level_t level, const char* format, ...);
|
||||
//#define log_n(format, ...) myLog(ESP_LOG_NONE, format, ##__VA_ARGS__)
|
||||
#else
|
||||
#ifdef CONFIG_ARDUHAL_ESP_LOG
|
||||
#undef ESP_LOGE
|
||||
#undef ESP_LOGW
|
||||
@ -150,6 +192,7 @@ int log_printf(const char *fmt, ...);
|
||||
#define ESP_EARLY_LOGD(tag, ...) isr_log_d(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGV(tag, ...) isr_log_v(__VA_ARGS__)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -44,11 +44,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,6 +113,24 @@ void disableCore1WDT(){
|
||||
}
|
||||
#endif
|
||||
|
||||
BaseType_t xTaskCreateUniversal( TaskFunction_t pxTaskCode,
|
||||
const char * const pcName,
|
||||
const uint32_t usStackDepth,
|
||||
void * const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t * const pxCreatedTask,
|
||||
const BaseType_t xCoreID ){
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
if(xCoreID >= 0 && xCoreID < 2) {
|
||||
return xTaskCreatePinnedToCore(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask, xCoreID);
|
||||
} else {
|
||||
#endif
|
||||
return xTaskCreate(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask);
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned long IRAM_ATTR micros()
|
||||
{
|
||||
return (unsigned long) (esp_timer_get_time());
|
||||
|
@ -94,6 +94,7 @@ struct rmt_obj_s
|
||||
transaction_state_t tx_state;
|
||||
rmt_rx_data_cb_t cb;
|
||||
bool data_alloc;
|
||||
void * arg;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -104,14 +105,14 @@ static xSemaphoreHandle g_rmt_objlocks[MAX_CHANNELS] = {
|
||||
};
|
||||
|
||||
static rmt_obj_t g_rmt_objects[MAX_CHANNELS] = {
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false},
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false},
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false},
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false},
|
||||
{ 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},
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
|
||||
{ false, NULL, 0, 0, 0, 0, 0, NULL, E_NO_INTR, E_INACTIVE, NULL, false, NULL},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -128,7 +129,7 @@ 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);
|
||||
|
||||
@ -234,6 +235,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) {
|
||||
@ -282,10 +297,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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -309,6 +324,7 @@ bool rmtReadData(rmt_obj_t* rmt, uint32_t* data, size_t size)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool rmtBeginReceive(rmt_obj_t* rmt)
|
||||
{
|
||||
if (!rmt) {
|
||||
@ -342,7 +358,7 @@ bool rmtReceiveCompleted(rmt_obj_t* rmt)
|
||||
}
|
||||
}
|
||||
|
||||
bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb)
|
||||
bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb, void * arg)
|
||||
{
|
||||
if (!rmt && !cb) {
|
||||
return false;
|
||||
@ -350,6 +366,7 @@ bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb)
|
||||
int channel = rmt->channel;
|
||||
|
||||
RMT_MUTEX_LOCK(channel);
|
||||
rmt->arg = arg;
|
||||
rmt->intr_mode = E_RX_INTR;
|
||||
rmt->tx_state = E_FIRST_HALF;
|
||||
rmt->cb = cb;
|
||||
@ -376,6 +393,19 @@ bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rmtEnd(rmt_obj_t* rmt) {
|
||||
if (!rmt) {
|
||||
return false;
|
||||
}
|
||||
int channel = rmt->channel;
|
||||
|
||||
RMT_MUTEX_LOCK(channel);
|
||||
RMT.conf_ch[channel].conf1.rx_en = 1;
|
||||
RMT_MUTEX_UNLOCK(channel);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rmtReadAsync(rmt_obj_t* rmt, rmt_data_t* data, size_t size, void* eventFlag, bool waitForData, uint32_t timeout)
|
||||
{
|
||||
if (!rmt) {
|
||||
@ -483,7 +513,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;
|
||||
}
|
||||
@ -508,6 +538,8 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize)
|
||||
rmt->tx_not_rx = tx_not_rx;
|
||||
rmt->buffers =buffers;
|
||||
rmt->channel = channel;
|
||||
rmt->arg = NULL;
|
||||
|
||||
_initPin(pin, channel, tx_not_rx);
|
||||
|
||||
// Initialize the registers in default mode:
|
||||
@ -529,6 +561,7 @@ rmt_obj_t* rmtInit(int pin, bool tx_not_rx, rmt_reserve_memsize_t memsize)
|
||||
RMT.conf_ch[channel].conf1.idle_out_lv = 0; // signal level for idle
|
||||
RMT.conf_ch[channel].conf1.idle_out_en = 1; // enable idle
|
||||
RMT.conf_ch[channel].conf1.ref_always_on = 0; // base clock
|
||||
|
||||
RMT.apb_conf.fifo_mask = 1;
|
||||
|
||||
if (tx_not_rx) {
|
||||
@ -553,7 +586,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 +604,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);
|
||||
@ -643,7 +677,7 @@ static void IRAM_ATTR _rmt_isr(void* arg)
|
||||
}
|
||||
if (g_rmt_objects[ch].cb) {
|
||||
// actually received data ptr
|
||||
(g_rmt_objects[ch].cb)(data_received, _rmt_get_mem_len(ch));
|
||||
(g_rmt_objects[ch].cb)(data_received, _rmt_get_mem_len(ch), g_rmt_objects[ch].arg);
|
||||
|
||||
// restart the reception
|
||||
RMT.conf_ch[ch].conf1.mem_owner = 1;
|
||||
@ -665,7 +699,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);
|
||||
|
@ -40,7 +40,7 @@ typedef enum {
|
||||
|
||||
typedef struct rmt_obj_s rmt_obj_t;
|
||||
|
||||
typedef void (*rmt_rx_data_cb_t)(uint32_t *data, size_t len);
|
||||
typedef void (*rmt_rx_data_cb_t)(uint32_t *data, size_t len, void *arg);
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
@ -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
|
||||
*
|
||||
@ -84,8 +90,13 @@ bool rmtReadAsync(rmt_obj_t* rmt, rmt_data_t* data, size_t size, void* eventFlag
|
||||
* and callback with data from ISR
|
||||
*
|
||||
*/
|
||||
bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb);
|
||||
bool rmtRead(rmt_obj_t* rmt, rmt_rx_data_cb_t cb, void * arg);
|
||||
|
||||
/***
|
||||
* Ends async receive started with rmtRead(); but does not
|
||||
* rmtDeInit().
|
||||
*/
|
||||
bool rmtEnd(rmt_obj_t* rmt);
|
||||
|
||||
/* Additional interface */
|
||||
|
||||
|
@ -384,12 +384,8 @@ 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;
|
||||
spi->dev->pin.val = 0;
|
||||
@ -399,8 +395,19 @@ void spiStopBus(spi_t * spi)
|
||||
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)
|
||||
@ -421,22 +428,18 @@ 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);
|
||||
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_SPI_CLK_EN_2);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_2);
|
||||
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);
|
||||
|
||||
SPI_MUTEX_LOCK();
|
||||
spiInitBus(spi);
|
||||
spi->dev->user.usr_mosi = 1;
|
||||
spi->dev->user.usr_miso = 1;
|
||||
spi->dev->user.doutdin = 1;
|
||||
@ -447,6 +450,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 +466,7 @@ void spiWaitReady(spi_t * spi)
|
||||
while(spi->dev->cmd.usr);
|
||||
}
|
||||
|
||||
void spiWrite(spi_t * spi, uint32_t *data, uint8_t len)
|
||||
void spiWrite(spi_t * spi, const uint32_t *data, uint8_t len)
|
||||
{
|
||||
if(!spi) {
|
||||
return;
|
||||
@ -532,17 +539,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 +627,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 +668,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;
|
||||
@ -861,7 +858,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 +884,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;
|
||||
}
|
||||
@ -917,8 +914,20 @@ void spiTransferBytesNL(spi_t * spi, const void * data_in, uint8_t * data_out, s
|
||||
spi->dev->cmd.usr = 1;
|
||||
while(spi->dev->cmd.usr);
|
||||
if(result){
|
||||
for (int i=0; i<c_longs; i++) {
|
||||
result[i] = spi->dev->data_buf[i];
|
||||
if(c_len & 3){
|
||||
for (int i=0; i<(c_longs-1); i++) {
|
||||
result[i] = spi->dev->data_buf[i];
|
||||
}
|
||||
uint32_t last_data = spi->dev->data_buf[c_longs-1];
|
||||
uint8_t * last_out8 = &result[c_longs-1];
|
||||
uint8_t * last_data8 = &last_data;
|
||||
for (int i=0; i<(c_len & 3); i++) {
|
||||
last_out8[i] = last_data8[i];
|
||||
}
|
||||
} else {
|
||||
for (int i=0; i<c_longs; i++) {
|
||||
result[i] = spi->dev->data_buf[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
if(data){
|
||||
@ -974,7 +983,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 IRAM_ATTR spiWritePixelsNL(spi_t * spi, const void * data_in, uint32_t len){
|
||||
size_t longs = len >> 2;
|
||||
if(len & 3){
|
||||
longs++;
|
||||
|
@ -54,7 +54,7 @@ extern "C" {
|
||||
struct spi_struct_t;
|
||||
typedef struct spi_struct_t spi_t;
|
||||
|
||||
spi_t * spiStartBus(uint8_t spi_num, uint32_t freq, uint8_t dataMode, uint8_t bitOrder);
|
||||
spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_t bitOrder);
|
||||
void spiStopBus(spi_t * spi);
|
||||
|
||||
//Attach/Detach Signal Pins
|
||||
@ -96,7 +96,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 +105,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 +115,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,7 @@
|
||||
|
||||
#include "esp32-hal.h"
|
||||
#include "lwip/apps/sntp.h"
|
||||
#include "tcpip_adapter.h"
|
||||
|
||||
static void setTimeZone(long offset, int daylight)
|
||||
{
|
||||
@ -45,6 +46,7 @@ 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
|
||||
if(sntp_enabled()){
|
||||
sntp_stop();
|
||||
}
|
||||
@ -62,6 +64,7 @@ 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
|
||||
if(sntp_enabled()){
|
||||
sntp_stop();
|
||||
}
|
||||
|
@ -90,56 +90,56 @@ void IRAM_ATTR __timerISR(void * arg){
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t timerRead(hw_timer_t *timer){
|
||||
uint64_t IRAM_ATTR timerRead(hw_timer_t *timer){
|
||||
timer->dev->update = 1;
|
||||
uint64_t h = timer->dev->cnt_high;
|
||||
uint64_t l = timer->dev->cnt_low;
|
||||
return (h << 32) | l;
|
||||
}
|
||||
|
||||
uint64_t timerAlarmRead(hw_timer_t *timer){
|
||||
uint64_t IRAM_ATTR timerAlarmRead(hw_timer_t *timer){
|
||||
uint64_t h = timer->dev->alarm_high;
|
||||
uint64_t l = timer->dev->alarm_low;
|
||||
return (h << 32) | l;
|
||||
}
|
||||
|
||||
void timerWrite(hw_timer_t *timer, uint64_t val){
|
||||
void IRAM_ATTR timerWrite(hw_timer_t *timer, uint64_t val){
|
||||
timer->dev->load_high = (uint32_t) (val >> 32);
|
||||
timer->dev->load_low = (uint32_t) (val);
|
||||
timer->dev->reload = 1;
|
||||
}
|
||||
|
||||
void timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload){
|
||||
void IRAM_ATTR timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload){
|
||||
timer->dev->alarm_high = (uint32_t) (alarm_value >> 32);
|
||||
timer->dev->alarm_low = (uint32_t) alarm_value;
|
||||
timer->dev->config.autoreload = autoreload;
|
||||
}
|
||||
|
||||
void timerSetConfig(hw_timer_t *timer, uint32_t config){
|
||||
void IRAM_ATTR timerSetConfig(hw_timer_t *timer, uint32_t config){
|
||||
timer->dev->config.val = config;
|
||||
}
|
||||
|
||||
uint32_t timerGetConfig(hw_timer_t *timer){
|
||||
uint32_t IRAM_ATTR timerGetConfig(hw_timer_t *timer){
|
||||
return timer->dev->config.val;
|
||||
}
|
||||
|
||||
void timerSetCountUp(hw_timer_t *timer, bool countUp){
|
||||
void IRAM_ATTR timerSetCountUp(hw_timer_t *timer, bool countUp){
|
||||
timer->dev->config.increase = countUp;
|
||||
}
|
||||
|
||||
bool timerGetCountUp(hw_timer_t *timer){
|
||||
bool IRAM_ATTR timerGetCountUp(hw_timer_t *timer){
|
||||
return timer->dev->config.increase;
|
||||
}
|
||||
|
||||
void timerSetAutoReload(hw_timer_t *timer, bool autoreload){
|
||||
void IRAM_ATTR timerSetAutoReload(hw_timer_t *timer, bool autoreload){
|
||||
timer->dev->config.autoreload = autoreload;
|
||||
}
|
||||
|
||||
bool timerGetAutoReload(hw_timer_t *timer){
|
||||
bool IRAM_ATTR timerGetAutoReload(hw_timer_t *timer){
|
||||
return timer->dev->config.autoreload;
|
||||
}
|
||||
|
||||
void timerSetDivider(hw_timer_t *timer, uint16_t divider){//2 to 65536
|
||||
void IRAM_ATTR timerSetDivider(hw_timer_t *timer, uint16_t divider){//2 to 65536
|
||||
if(!divider){
|
||||
divider = 0xFFFF;
|
||||
} else if(divider == 1){
|
||||
@ -151,40 +151,41 @@ void timerSetDivider(hw_timer_t *timer, uint16_t divider){//2 to 65536
|
||||
timer->dev->config.enable = timer_en;
|
||||
}
|
||||
|
||||
uint16_t timerGetDivider(hw_timer_t *timer){
|
||||
uint16_t IRAM_ATTR timerGetDivider(hw_timer_t *timer){
|
||||
return timer->dev->config.divider;
|
||||
}
|
||||
|
||||
void timerStart(hw_timer_t *timer){
|
||||
void IRAM_ATTR timerStart(hw_timer_t *timer){
|
||||
timer->dev->config.enable = 1;
|
||||
}
|
||||
|
||||
void timerStop(hw_timer_t *timer){
|
||||
void IRAM_ATTR timerStop(hw_timer_t *timer){
|
||||
timer->dev->config.enable = 0;
|
||||
}
|
||||
|
||||
void timerRestart(hw_timer_t *timer){
|
||||
void IRAM_ATTR timerRestart(hw_timer_t *timer){
|
||||
timer->dev->config.enable = 0;
|
||||
timer->dev->reload = 1;
|
||||
timer->dev->config.enable = 1;
|
||||
}
|
||||
|
||||
bool timerStarted(hw_timer_t *timer){
|
||||
bool IRAM_ATTR timerStarted(hw_timer_t *timer){
|
||||
return timer->dev->config.enable;
|
||||
}
|
||||
|
||||
void timerAlarmEnable(hw_timer_t *timer){
|
||||
void IRAM_ATTR timerAlarmEnable(hw_timer_t *timer){
|
||||
timer->dev->config.alarm_en = 1;
|
||||
}
|
||||
|
||||
void timerAlarmDisable(hw_timer_t *timer){
|
||||
void IRAM_ATTR timerAlarmDisable(hw_timer_t *timer){
|
||||
timer->dev->config.alarm_en = 0;
|
||||
}
|
||||
|
||||
bool timerAlarmEnabled(hw_timer_t *timer){
|
||||
bool IRAM_ATTR timerAlarmEnabled(hw_timer_t *timer){
|
||||
return timer->dev->config.alarm_en;
|
||||
}
|
||||
|
||||
static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){
|
||||
static void IRAM_ATTR _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){
|
||||
hw_timer_t * timer = (hw_timer_t *)arg;
|
||||
if(ev_type == APB_BEFORE_CHANGE){
|
||||
timer->dev->config.enable = 0;
|
||||
@ -196,7 +197,7 @@ static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb
|
||||
}
|
||||
}
|
||||
|
||||
hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){
|
||||
hw_timer_t * IRAM_ATTR timerBegin(uint8_t num, uint16_t divider, bool countUp){
|
||||
if(num > 3){
|
||||
return NULL;
|
||||
}
|
||||
@ -221,13 +222,13 @@ hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){
|
||||
return timer;
|
||||
}
|
||||
|
||||
void timerEnd(hw_timer_t *timer){
|
||||
void IRAM_ATTR timerEnd(hw_timer_t *timer){
|
||||
timer->dev->config.enable = 0;
|
||||
timerAttachInterrupt(timer, NULL, false);
|
||||
removeApbChangeCallback(timer, _on_apb_change);
|
||||
}
|
||||
|
||||
void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){
|
||||
void IRAM_ATTR timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){
|
||||
static bool initialized = false;
|
||||
static intr_handle_t intr_handle = NULL;
|
||||
if(intr_handle){
|
||||
@ -278,29 +279,29 @@ void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){
|
||||
}
|
||||
}
|
||||
|
||||
void timerDetachInterrupt(hw_timer_t *timer){
|
||||
void IRAM_ATTR timerDetachInterrupt(hw_timer_t *timer){
|
||||
timerAttachInterrupt(timer, NULL, false);
|
||||
}
|
||||
|
||||
uint64_t timerReadMicros(hw_timer_t *timer){
|
||||
uint64_t IRAM_ATTR timerReadMicros(hw_timer_t *timer){
|
||||
uint64_t timer_val = timerRead(timer);
|
||||
uint16_t div = timerGetDivider(timer);
|
||||
return timer_val * div / (getApbFrequency() / 1000000);
|
||||
}
|
||||
|
||||
double timerReadSeconds(hw_timer_t *timer){
|
||||
double IRAM_ATTR timerReadSeconds(hw_timer_t *timer){
|
||||
uint64_t timer_val = timerRead(timer);
|
||||
uint16_t div = timerGetDivider(timer);
|
||||
return (double)timer_val * div / getApbFrequency();
|
||||
}
|
||||
|
||||
uint64_t timerAlarmReadMicros(hw_timer_t *timer){
|
||||
uint64_t IRAM_ATTR timerAlarmReadMicros(hw_timer_t *timer){
|
||||
uint64_t timer_val = timerAlarmRead(timer);
|
||||
uint16_t div = timerGetDivider(timer);
|
||||
return timer_val * div / (getApbFrequency() / 1000000);
|
||||
}
|
||||
|
||||
double timerAlarmReadSeconds(hw_timer_t *timer){
|
||||
double IRAM_ATTR timerAlarmReadSeconds(hw_timer_t *timer){
|
||||
uint64_t timer_val = timerAlarmRead(timer);
|
||||
uint16_t div = timerGetDivider(timer);
|
||||
return (double)timer_val * div / getApbFrequency();
|
||||
|
@ -85,7 +85,7 @@ static void IRAM_ATTR _uart_isr(void *arg)
|
||||
uart->dev->int_clr.rxfifo_tout = 1;
|
||||
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)) {
|
||||
if(uart->queue != NULL) {
|
||||
xQueueSendFromISR(uart->queue, &c, &xHigherPriorityTaskWoken);
|
||||
}
|
||||
}
|
||||
@ -124,21 +124,21 @@ void uartDisableInterrupt(uart_t* uart)
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
void uartDetachRx(uart_t* uart)
|
||||
void uartDetachRx(uart_t* uart, uint8_t rxPin)
|
||||
{
|
||||
if(uart == NULL) {
|
||||
return;
|
||||
}
|
||||
pinMatrixInDetach(UART_RXD_IDX(uart->num), false, false);
|
||||
pinMatrixInDetach(rxPin, false, false);
|
||||
uartDisableInterrupt(uart);
|
||||
}
|
||||
|
||||
void uartDetachTx(uart_t* uart)
|
||||
void uartDetachTx(uart_t* uart, uint8_t txPin)
|
||||
{
|
||||
if(uart == NULL) {
|
||||
return;
|
||||
}
|
||||
pinMatrixOutDetach(UART_TXD_IDX(uart->num), false, false);
|
||||
pinMatrixOutDetach(txPin, false, false);
|
||||
}
|
||||
|
||||
void uartAttachRx(uart_t* uart, uint8_t rxPin, bool inverted)
|
||||
@ -208,6 +208,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,12 +222,11 @@ 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;
|
||||
}
|
||||
|
||||
void uartEnd(uart_t* uart)
|
||||
void uartEnd(uart_t* uart, uint8_t txPin, uint8_t rxPin)
|
||||
{
|
||||
if(uart == NULL) {
|
||||
return;
|
||||
@ -239,8 +243,8 @@ void uartEnd(uart_t* uart)
|
||||
|
||||
UART_MUTEX_UNLOCK();
|
||||
|
||||
uartDetachRx(uart);
|
||||
uartDetachTx(uart);
|
||||
uartDetachRx(uart, rxPin);
|
||||
uartDetachTx(uart, txPin);
|
||||
}
|
||||
|
||||
size_t uartResizeRxBuffer(uart_t * uart, size_t new_size) {
|
||||
@ -253,6 +257,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) {
|
||||
UART_MUTEX_UNLOCK();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@ -261,12 +266,23 @@ size_t uartResizeRxBuffer(uart_t * uart, size_t new_size) {
|
||||
return new_size;
|
||||
}
|
||||
|
||||
void uartSetRxInvert(uart_t* uart, bool invert)
|
||||
{
|
||||
if (uart == NULL)
|
||||
return;
|
||||
|
||||
if (invert)
|
||||
uart->dev->conf0.rxd_inv = 1;
|
||||
else
|
||||
uart->dev->conf0.rxd_inv = 0;
|
||||
}
|
||||
|
||||
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 +293,35 @@ 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;
|
||||
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;
|
||||
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 +334,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;
|
||||
}
|
||||
@ -327,6 +370,11 @@ void uartWriteBuf(uart_t* uart, const uint8_t * data, size_t len)
|
||||
}
|
||||
|
||||
void uartFlush(uart_t* uart)
|
||||
{
|
||||
uartFlushTxOnly(uart,true);
|
||||
}
|
||||
|
||||
void uartFlushTxOnly(uart_t* uart, bool txOnly)
|
||||
{
|
||||
if(uart == NULL) {
|
||||
return;
|
||||
@ -334,15 +382,19 @@ void uartFlush(uart_t* uart)
|
||||
|
||||
UART_MUTEX_LOCK();
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
@ -368,18 +420,21 @@ 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;
|
||||
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);
|
||||
if(uart->queue != NULL ) {
|
||||
xQueueSend(uart->queue, &c, 1); //&xHigherPriorityTaskWoken);
|
||||
}
|
||||
}
|
||||
UART_MUTEX_UNLOCK();
|
||||
|
||||
// wait TX empty
|
||||
while(uart->dev->status.txfifo_cnt || uart->dev->status.st_utx_out);
|
||||
} 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,7 +454,12 @@ 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);
|
||||
}
|
||||
|
||||
@ -520,6 +580,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)
|
||||
{
|
||||
|
@ -52,7 +52,7 @@ struct uart_struct_t;
|
||||
typedef struct uart_struct_t uart_t;
|
||||
|
||||
uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t queueLen, bool inverted);
|
||||
void uartEnd(uart_t* uart);
|
||||
void uartEnd(uart_t* uart, uint8_t rxPin, uint8_t txPin);
|
||||
|
||||
uint32_t uartAvailable(uart_t* uart);
|
||||
uint32_t uartAvailableForWrite(uart_t* uart);
|
||||
@ -63,15 +63,19 @@ void uartWrite(uart_t* uart, uint8_t c);
|
||||
void uartWriteBuf(uart_t* uart, const uint8_t * data, size_t len);
|
||||
|
||||
void uartFlush(uart_t* uart);
|
||||
void uartFlushTxOnly(uart_t* uart, bool txOnly );
|
||||
|
||||
void uartSetBaudRate(uart_t* uart, uint32_t baud_rate);
|
||||
uint32_t uartGetBaudRate(uart_t* uart);
|
||||
|
||||
size_t uartResizeRxBuffer(uart_t* uart, size_t new_size);
|
||||
|
||||
void uartSetRxInvert(uart_t* uart, bool invert);
|
||||
|
||||
void uartSetDebug(uart_t* uart);
|
||||
int uartGetDebug();
|
||||
|
||||
void uartStartDetectBaudrate(uart_t *uart);
|
||||
unsigned long uartDetectBaudrate(uart_t *uart);
|
||||
|
||||
bool uartRxActive(uart_t* uart);
|
||||
|
@ -90,6 +90,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);
|
||||
|
@ -3,16 +3,14 @@
|
||||
#include "esp_task_wdt.h"
|
||||
#include "Arduino.h"
|
||||
|
||||
#ifndef CONFIG_ARDUINO_LOOP_STACK_SIZE
|
||||
#define CONFIG_ARDUINO_LOOP_STACK_SIZE 8192
|
||||
#endif
|
||||
|
||||
TaskHandle_t loopTaskHandle = NULL;
|
||||
|
||||
#if CONFIG_AUTOSTART_ARDUINO
|
||||
|
||||
#if CONFIG_FREERTOS_UNICORE
|
||||
#define ARDUINO_RUNNING_CORE 0
|
||||
#else
|
||||
#define ARDUINO_RUNNING_CORE 1
|
||||
#endif
|
||||
|
||||
bool loopTaskWDTEnabled;
|
||||
|
||||
void loopTask(void *pvParameters)
|
||||
@ -23,6 +21,7 @@ void loopTask(void *pvParameters)
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
loop();
|
||||
if (serialEventRun) serialEventRun();
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,7 +29,7 @@ extern "C" void app_main()
|
||||
{
|
||||
loopTaskWDTEnabled = false;
|
||||
initArduino();
|
||||
xTaskCreatePinnedToCore(loopTask, "loopTask", 8192, NULL, 1, &loopTaskHandle, ARDUINO_RUNNING_CORE);
|
||||
xTaskCreateUniversal(loopTask, "loopTask", CONFIG_ARDUINO_LOOP_STACK_SIZE, NULL, 1, &loopTaskHandle, CONFIG_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)
|
||||
|
||||
@ -54,6 +53,8 @@ typedef unsigned long prog_uint32_t;
|
||||
*(void * const *)(_addr); \
|
||||
})
|
||||
|
||||
#define pgm_get_far_address(x) ((uint32_t)(&(x)))
|
||||
|
||||
#define pgm_read_byte_near(addr) pgm_read_byte(addr)
|
||||
#define pgm_read_word_near(addr) pgm_read_word(addr)
|
||||
#define pgm_read_dword_near(addr) pgm_read_dword(addr)
|
||||
|
@ -16,7 +16,7 @@
|
||||
Boston, MA 02111-1307 USA
|
||||
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
|
||||
*/
|
||||
|
||||
|
||||
#include "esp32-hal.h"
|
||||
#include "wiring_private.h"
|
||||
|
||||
|
@ -1,26 +1,28 @@
|
||||
Make your question, not a Statement, inclusive. Include all pertinent information:
|
||||
|
||||
What you are trying to do.
|
||||
Describe your system( Hardware, computer, O/S, core version, environment)
|
||||
Describe what is failing
|
||||
Show the shortest possible code that will duplicate the error
|
||||
Show the EXACT error message(it doesn't work is not enough)
|
||||
What you are trying to do
|
||||
Describe your system (Hardware, computer, O/S, core version, environment)
|
||||
Describe what is failing
|
||||
Show the shortest possible code that will duplicate the error
|
||||
Show the EXACT error message (it doesn't work is not enough)
|
||||
Then if someone is interested and knowledgeable you might get a answer. All of this work on your part shows us that you have worked to solve YOUR problem. The more complete your issue posting is, the more likely someone will volunteer their time to help you.
|
||||
|
||||
If you have a Guru Meditation Error or Backtrace, ***please decode it***:
|
||||
https://github.com/me-no-dev/EspExceptionDecoder
|
||||
[ExceptionDecoder](https://github.com/me-no-dev/EspExceptionDecoder)
|
||||
|
||||
----------------------------- Remove above -----------------------------
|
||||
|
||||
|
||||
### Hardware:
|
||||
Board: ?ESP32 Dev Module? ?node32? ?ttgo_lora?
|
||||
Core Installation/update date: ?11/jul/2017?
|
||||
IDE name: ?Arduino IDE? ?Platform.io? ?IDF component?
|
||||
Flash Frequency: ?40Mhz?
|
||||
PSRAM enabled: ?no?
|
||||
Upload Speed: ?115200?
|
||||
Computer OS: ?Windows 10? ?Mac OSX? ?Ubuntu?
|
||||
|||||||
|
||||
|:---|---|---|---|---|---|
|
||||
|<B>Board</B>|ESP32 Dev Module|node32|ttgo_lora|ESP32-S2-Saola|Custom w/ ESP32-S2-WROVER 16MB|
|
||||
|<B>Version/Date</B>|1.0.4|2.0.0|0badbeef|11/jul/2017|today's master|
|
||||
|<B>IDE name</B>|Arduino IDE|Atom + Platform.io|IDF component|VSCode|
|
||||
|<B>Flash Frequency</B>|40Mhz|80Mhz|
|
||||
|<B>PSRAM enabled</B>|yes|no|
|
||||
|<B>Upload Speed</B>|115200|
|
||||
|<B>Computer OS</B>|Windows 10|Mac OSX|Ubuntu|
|
||||
|
||||
### Description:
|
||||
Describe your problem here
|
||||
|
@ -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 (x86, amd64, armhf and arm64).
|
||||
|
||||
- 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`
|
||||
|
@ -8,8 +8,8 @@ Installation instructions for Debian / Ubuntu OS
|
||||
sudo usermod -a -G dialout $USER && \
|
||||
sudo apt-get install git && \
|
||||
wget https://bootstrap.pypa.io/get-pip.py && \
|
||||
sudo python get-pip.py && \
|
||||
sudo pip install pyserial && \
|
||||
sudo python3 get-pip.py && \
|
||||
sudo pip3 install pyserial && \
|
||||
mkdir -p ~/Arduino/hardware/espressif && \
|
||||
cd ~/Arduino/hardware/espressif && \
|
||||
git clone https://github.com/espressif/arduino-esp32.git esp32 && \
|
||||
|
@ -7,9 +7,9 @@ Installation instructions for Mac OS
|
||||
```bash
|
||||
mkdir -p ~/Documents/Arduino/hardware/espressif && \
|
||||
cd ~/Documents/Arduino/hardware/espressif && \
|
||||
git clone https://github.com/espressif/arduino-esp32.git esp32 && \
|
||||
git clone https://github.com/espressif/arduino-esp32.git esp32 --depth 1 && \
|
||||
cd esp32 && \
|
||||
git submodule update --init --recursive && \
|
||||
git submodule update --init --recursive --depth 1 && \
|
||||
cd tools && \
|
||||
python get.py
|
||||
```
|
||||
@ -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)
|
||||
@ -68,6 +72,11 @@ If you are writing code that does not require Arduino to compile and you want yo
|
||||
#endif
|
||||
```
|
||||
|
||||
## FreeRTOS Tick Rate (Hz)
|
||||
|
||||
You might notice that Arduino-esp32's `delay()` function will only work in multiples of 10ms. That is because, by default, esp-idf handles task events 100 times per second.
|
||||
To fix that behavior you need to set FreeRTOS tick rate to 1000Hz in `make menuconfig` -> `Component config` -> `FreeRTOS` -> `Tick rate`.
|
||||
|
||||
## Compilation Errors
|
||||
|
||||
As commits are made to esp-idf and submodules, the codebases can develop incompatibilities which cause compilation errors. If you have problems compiling, follow the instructions in [Issue #1142](https://github.com/espressif/arduino-esp32/issues/1142) to roll esp-idf back to a known good version.
|
||||
|
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)
|
||||
|
@ -14,7 +14,7 @@ WebServer server(80);
|
||||
* Login page
|
||||
*/
|
||||
|
||||
const char* loginIndex =
|
||||
const char* loginIndex =
|
||||
"<form name='loginForm'>"
|
||||
"<table width='20%' bgcolor='A09F9F' align='center'>"
|
||||
"<tr>"
|
||||
@ -25,8 +25,9 @@ const char* loginIndex =
|
||||
"<br>"
|
||||
"<br>"
|
||||
"</tr>"
|
||||
"<td>Username:</td>"
|
||||
"<td><input type='text' size=25 name='userid'><br></td>"
|
||||
"<tr>"
|
||||
"<td>Username:</td>"
|
||||
"<td><input type='text' size=25 name='userid'><br></td>"
|
||||
"</tr>"
|
||||
"<br>"
|
||||
"<br>"
|
||||
@ -54,12 +55,12 @@ const char* loginIndex =
|
||||
"}"
|
||||
"}"
|
||||
"</script>";
|
||||
|
||||
|
||||
/*
|
||||
* Server Index Page
|
||||
*/
|
||||
|
||||
const char* serverIndex =
|
||||
|
||||
const char* serverIndex =
|
||||
"<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>"
|
||||
"<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>"
|
||||
"<input type='file' name='update'>"
|
||||
@ -88,7 +89,7 @@ const char* serverIndex =
|
||||
"return xhr;"
|
||||
"},"
|
||||
"success:function(d, s) {"
|
||||
"console.log('success!')"
|
||||
"console.log('success!')"
|
||||
"},"
|
||||
"error: function (a, b, c) {"
|
||||
"}"
|
||||
|
@ -88,6 +88,17 @@ ArduinoOTAClass& ArduinoOTAClass::setPasswordHash(const char * password) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
ArduinoOTAClass& ArduinoOTAClass::setPartitionLabel(const char * partition_label) {
|
||||
if (!_initialized && !_partition_label.length() && partition_label) {
|
||||
_partition_label = partition_label;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
String ArduinoOTAClass::getPartitionLabel() {
|
||||
return _partition_label;
|
||||
}
|
||||
|
||||
ArduinoOTAClass& ArduinoOTAClass::setRebootOnSuccess(bool reboot){
|
||||
_rebootOnSuccess = reboot;
|
||||
return *this;
|
||||
@ -127,9 +138,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 +182,7 @@ void ArduinoOTAClass::_onRx(){
|
||||
_md5 = readStringUntil('\n');
|
||||
_md5.trim();
|
||||
if(_md5.length() != 32){
|
||||
log_e("bad md5 length");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -198,6 +208,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 +216,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 +237,7 @@ void ArduinoOTAClass::_onRx(){
|
||||
} else {
|
||||
_udp_ota.beginPacket(_udp_ota.remoteIP(), _udp_ota.remotePort());
|
||||
_udp_ota.print("Authentication Failed");
|
||||
log_w("Authentication Failed");
|
||||
_udp_ota.endPacket();
|
||||
if (_error_callback) _error_callback(OTA_AUTH_ERROR);
|
||||
_state = OTA_IDLE;
|
||||
@ -233,10 +246,11 @@ void ArduinoOTAClass::_onRx(){
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::_runUpdate() {
|
||||
if (!Update.begin(_size, _cmd)) {
|
||||
#ifdef OTA_DEBUG
|
||||
Update.printError(OTA_DEBUG);
|
||||
#endif
|
||||
const char *partition_label = _partition_label.length() ? _partition_label.c_str() : NULL;
|
||||
if (!Update.begin(_size, _cmd, -1, LOW, partition_label)) {
|
||||
|
||||
log_e("Begin ERROR: %s", Update.errorString());
|
||||
|
||||
if (_error_callback) {
|
||||
_error_callback(OTA_BEGIN_ERROR);
|
||||
}
|
||||
@ -272,21 +286,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 +303,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 +323,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 +353,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,14 +365,12 @@ 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() {
|
||||
if (!_initialized) {
|
||||
return;
|
||||
return;
|
||||
}
|
||||
if (_state == OTA_RUNUPDATE) {
|
||||
_runUpdate();
|
||||
@ -395,4 +392,4 @@ void ArduinoOTAClass::setTimeout(int timeoutInMillis) {
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_ARDUINOOTA)
|
||||
ArduinoOTAClass ArduinoOTA;
|
||||
#endif
|
||||
#endif
|
||||
|
@ -44,6 +44,10 @@ class ArduinoOTAClass
|
||||
//Sets the password as above but in the form MD5(password). Default NULL
|
||||
ArduinoOTAClass& setPasswordHash(const char *password);
|
||||
|
||||
//Sets the partition label to write to when updating SPIFFS. Default NULL
|
||||
ArduinoOTAClass &setPartitionLabel(const char *partition_label);
|
||||
String getPartitionLabel();
|
||||
|
||||
//Sets if the device should be rebooted after successful update. Default true
|
||||
ArduinoOTAClass& setRebootOnSuccess(bool reboot);
|
||||
|
||||
@ -80,6 +84,7 @@ class ArduinoOTAClass
|
||||
int _port;
|
||||
String _password;
|
||||
String _hostname;
|
||||
String _partition_label;
|
||||
String _nonce;
|
||||
WiFiUDP _udp_ota;
|
||||
bool _initialized;
|
||||
|
@ -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, CONFIG_ARDUINO_UDP_TASK_PRIORITY, (TaskHandle_t*)&_udp_task_handle, CONFIG_ARDUINO_UDP_RUNNING_CORE);
|
||||
if(!_udp_task_handle){
|
||||
return false;
|
||||
}
|
||||
@ -277,6 +277,22 @@ void AsyncUDPMessage::flush()
|
||||
_index = 0;
|
||||
}
|
||||
|
||||
AsyncUDPPacket::AsyncUDPPacket(AsyncUDPPacket &packet){
|
||||
_udp = packet._udp;
|
||||
_pb = packet._pb;
|
||||
_if = packet._if;
|
||||
_data = packet._data;
|
||||
_len = packet._len;
|
||||
_index = 0;
|
||||
|
||||
memcpy(&_remoteIp, &packet._remoteIp, sizeof(ip_addr_t));
|
||||
memcpy(&_localIp, &packet._localIp, sizeof(ip_addr_t));
|
||||
_localPort = packet._localPort;
|
||||
_remotePort = packet._remotePort;
|
||||
memcpy(_remoteMac, packet._remoteMac, 6);
|
||||
|
||||
pbuf_ref(_pb);
|
||||
}
|
||||
|
||||
AsyncUDPPacket::AsyncUDPPacket(AsyncUDP *udp, pbuf *pb, const ip_addr_t *raddr, uint16_t rport, struct netif * ntif)
|
||||
{
|
||||
@ -294,18 +310,18 @@ AsyncUDPPacket::AsyncUDPPacket(AsyncUDP *udp, pbuf *pb, const ip_addr_t *raddr,
|
||||
_localIp.type = _remoteIp.type;
|
||||
|
||||
eth_hdr* eth = NULL;
|
||||
udp_hdr* udphdr = reinterpret_cast<udp_hdr*>(_data - UDP_HLEN);
|
||||
udp_hdr* udphdr = (udp_hdr *)(_data - UDP_HLEN);
|
||||
_localPort = ntohs(udphdr->dest);
|
||||
_remotePort = ntohs(udphdr->src);
|
||||
|
||||
if (_remoteIp.type == IPADDR_TYPE_V4) {
|
||||
eth = (eth_hdr *)(((uint8_t *)(pb->payload)) - UDP_HLEN - IP_HLEN - SIZEOF_ETH_HDR);
|
||||
struct ip_hdr * iphdr = (struct ip_hdr *)(((uint8_t *)(pb->payload)) - UDP_HLEN - IP_HLEN);
|
||||
eth = (eth_hdr *)(_data - UDP_HLEN - IP_HLEN - SIZEOF_ETH_HDR);
|
||||
struct ip_hdr * iphdr = (struct ip_hdr *)(_data - UDP_HLEN - IP_HLEN);
|
||||
_localIp.u_addr.ip4.addr = iphdr->dest.addr;
|
||||
_remoteIp.u_addr.ip4.addr = iphdr->src.addr;
|
||||
} else {
|
||||
eth = (eth_hdr *)(((uint8_t *)(pb->payload)) - UDP_HLEN - IP6_HLEN - SIZEOF_ETH_HDR);
|
||||
struct ip6_hdr * ip6hdr = (struct ip6_hdr *)(((uint8_t *)(pb->payload)) - UDP_HLEN - IP6_HLEN);
|
||||
eth = (eth_hdr *)(_data - UDP_HLEN - IP6_HLEN - SIZEOF_ETH_HDR);
|
||||
struct ip6_hdr * ip6hdr = (struct ip6_hdr *)(_data - UDP_HLEN - IP6_HLEN);
|
||||
memcpy(&_localIp.u_addr.ip6.addr, (uint8_t *)ip6hdr->dest.addr, 16);
|
||||
memcpy(&_remoteIp.u_addr.ip6.addr, (uint8_t *)ip6hdr->src.addr, 16);
|
||||
}
|
||||
@ -479,6 +495,7 @@ AsyncUDP::AsyncUDP()
|
||||
{
|
||||
_pcb = NULL;
|
||||
_connected = false;
|
||||
_lastErr = ERR_OK;
|
||||
_handler = NULL;
|
||||
}
|
||||
|
||||
@ -517,8 +534,8 @@ bool AsyncUDP::connect(const ip_addr_t *addr, uint16_t port)
|
||||
}
|
||||
close();
|
||||
UDP_MUTEX_LOCK();
|
||||
err_t err = _udp_connect(_pcb, addr, port);
|
||||
if(err != ERR_OK) {
|
||||
_lastErr = _udp_connect(_pcb, addr, port);
|
||||
if(_lastErr != ERR_OK) {
|
||||
UDP_MUTEX_UNLOCK();
|
||||
return false;
|
||||
}
|
||||
@ -646,7 +663,7 @@ size_t AsyncUDP::writeTo(const uint8_t * data, size_t len, const ip_addr_t * add
|
||||
if(len > CONFIG_TCP_MSS) {
|
||||
len = CONFIG_TCP_MSS;
|
||||
}
|
||||
err_t err = ERR_OK;
|
||||
_lastErr = ERR_OK;
|
||||
pbuf* pbt = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
|
||||
if(pbt != NULL) {
|
||||
uint8_t* dst = reinterpret_cast<uint8_t*>(pbt->payload);
|
||||
@ -656,16 +673,16 @@ size_t AsyncUDP::writeTo(const uint8_t * data, size_t len, const ip_addr_t * add
|
||||
void * nif = NULL;
|
||||
tcpip_adapter_get_netif((tcpip_adapter_if_t)tcpip_if, &nif);
|
||||
if(!nif){
|
||||
err = _udp_sendto(_pcb, pbt, addr, port);
|
||||
_lastErr = _udp_sendto(_pcb, pbt, addr, port);
|
||||
} else {
|
||||
err = _udp_sendto_if(_pcb, pbt, addr, port, (struct netif *)nif);
|
||||
_lastErr = _udp_sendto_if(_pcb, pbt, addr, port, (struct netif *)nif);
|
||||
}
|
||||
} else {
|
||||
err = _udp_sendto(_pcb, pbt, addr, port);
|
||||
_lastErr = _udp_sendto(_pcb, pbt, addr, port);
|
||||
}
|
||||
UDP_MUTEX_UNLOCK();
|
||||
pbuf_free(pbt);
|
||||
if(err < ERR_OK) {
|
||||
if(_lastErr < ERR_OK) {
|
||||
return 0;
|
||||
}
|
||||
return len;
|
||||
@ -869,6 +886,10 @@ bool AsyncUDP::connected()
|
||||
return _connected;
|
||||
}
|
||||
|
||||
esp_err_t AsyncUDP::lastErr() {
|
||||
return _lastErr;
|
||||
}
|
||||
|
||||
void AsyncUDP::onPacket(AuPacketHandlerFunctionWithArg cb, void * arg)
|
||||
{
|
||||
onPacket(std::bind(cb, arg, std::placeholders::_1));
|
||||
|
@ -58,6 +58,7 @@ protected:
|
||||
size_t _len;
|
||||
size_t _index;
|
||||
public:
|
||||
AsyncUDPPacket(AsyncUDPPacket &packet);
|
||||
AsyncUDPPacket(AsyncUDP *udp, pbuf *pb, const ip_addr_t *addr, uint16_t port, struct netif * netif);
|
||||
virtual ~AsyncUDPPacket();
|
||||
|
||||
@ -95,6 +96,7 @@ protected:
|
||||
udp_pcb *_pcb;
|
||||
//xSemaphoreHandle _lock;
|
||||
bool _connected;
|
||||
esp_err_t _lastErr;
|
||||
AuPacketHandlerFunction _handler;
|
||||
|
||||
bool _init();
|
||||
@ -144,6 +146,7 @@ public:
|
||||
IPAddress listenIP();
|
||||
IPv6Address listenIPv6();
|
||||
bool connected();
|
||||
esp_err_t lastErr();
|
||||
operator bool();
|
||||
|
||||
static void _s_recv(void *arg, udp_pcb *upcb, pbuf *p, const ip_addr_t *addr, uint16_t port, struct netif * netif);
|
||||
|
Submodule libraries/AzureIoT updated: 67dfa4f31e...5e8ffb2111
153
libraries/BLE/examples/BLE_Beacon_Scanner/BLE_Beacon_Scanner.ino
Normal file
153
libraries/BLE/examples/BLE_Beacon_Scanner/BLE_Beacon_Scanner.ino
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
|
||||
Ported to Arduino ESP32 by Evandro Copercini
|
||||
Changed to a beacon scanner to report iBeacon, EddystoneURL and EddystoneTLM beacons by beegee-tokyo
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <BLEDevice.h>
|
||||
#include <BLEUtils.h>
|
||||
#include <BLEScan.h>
|
||||
#include <BLEAdvertisedDevice.h>
|
||||
#include <BLEEddystoneURL.h>
|
||||
#include <BLEEddystoneTLM.h>
|
||||
#include <BLEBeacon.h>
|
||||
|
||||
#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00) >> 8) + (((x)&0xFF) << 8))
|
||||
|
||||
int scanTime = 5; //In seconds
|
||||
BLEScan *pBLEScan;
|
||||
|
||||
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
|
||||
{
|
||||
void onResult(BLEAdvertisedDevice advertisedDevice)
|
||||
{
|
||||
if (advertisedDevice.haveName())
|
||||
{
|
||||
Serial.print("Device name: ");
|
||||
Serial.println(advertisedDevice.getName().c_str());
|
||||
Serial.println("");
|
||||
}
|
||||
|
||||
if (advertisedDevice.haveServiceUUID())
|
||||
{
|
||||
BLEUUID devUUID = advertisedDevice.getServiceUUID();
|
||||
Serial.print("Found ServiceUUID: ");
|
||||
Serial.println(devUUID.toString().c_str());
|
||||
Serial.println("");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (advertisedDevice.haveManufacturerData() == true)
|
||||
{
|
||||
std::string strManufacturerData = advertisedDevice.getManufacturerData();
|
||||
|
||||
uint8_t cManufacturerData[100];
|
||||
strManufacturerData.copy((char *)cManufacturerData, strManufacturerData.length(), 0);
|
||||
|
||||
if (strManufacturerData.length() == 25 && cManufacturerData[0] == 0x4C && cManufacturerData[1] == 0x00)
|
||||
{
|
||||
Serial.println("Found an iBeacon!");
|
||||
BLEBeacon oBeacon = BLEBeacon();
|
||||
oBeacon.setData(strManufacturerData);
|
||||
Serial.printf("iBeacon Frame\n");
|
||||
Serial.printf("ID: %04X Major: %d Minor: %d UUID: %s Power: %d\n", oBeacon.getManufacturerId(), ENDIAN_CHANGE_U16(oBeacon.getMajor()), ENDIAN_CHANGE_U16(oBeacon.getMinor()), oBeacon.getProximityUUID().toString().c_str(), oBeacon.getSignalPower());
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Found another manufacturers beacon!");
|
||||
Serial.printf("strManufacturerData: %d ", strManufacturerData.length());
|
||||
for (int i = 0; i < strManufacturerData.length(); i++)
|
||||
{
|
||||
Serial.printf("[%X]", cManufacturerData[i]);
|
||||
}
|
||||
Serial.printf("\n");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *payLoad = advertisedDevice.getPayload();
|
||||
|
||||
BLEUUID checkUrlUUID = (uint16_t)0xfeaa;
|
||||
|
||||
if (advertisedDevice.getServiceUUID().equals(checkUrlUUID))
|
||||
{
|
||||
if (payLoad[11] == 0x10)
|
||||
{
|
||||
Serial.println("Found an EddystoneURL beacon!");
|
||||
BLEEddystoneURL foundEddyURL = BLEEddystoneURL();
|
||||
std::string eddyContent((char *)&payLoad[11]); // incomplete EddystoneURL struct!
|
||||
|
||||
foundEddyURL.setData(eddyContent);
|
||||
std::string bareURL = foundEddyURL.getURL();
|
||||
if (bareURL[0] == 0x00)
|
||||
{
|
||||
size_t payLoadLen = advertisedDevice.getPayloadLength();
|
||||
Serial.println("DATA-->");
|
||||
for (int idx = 0; idx < payLoadLen; idx++)
|
||||
{
|
||||
Serial.printf("0x%08X ", payLoad[idx]);
|
||||
}
|
||||
Serial.println("\nInvalid Data");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.printf("Found URL: %s\n", foundEddyURL.getURL().c_str());
|
||||
Serial.printf("Decoded URL: %s\n", foundEddyURL.getDecodedURL().c_str());
|
||||
Serial.printf("TX power %d\n", foundEddyURL.getPower());
|
||||
Serial.println("\n");
|
||||
}
|
||||
else if (payLoad[11] == 0x20)
|
||||
{
|
||||
Serial.println("Found an EddystoneTLM beacon!");
|
||||
BLEEddystoneTLM foundEddyURL = BLEEddystoneTLM();
|
||||
std::string eddyContent((char *)&payLoad[11]); // incomplete EddystoneURL struct!
|
||||
|
||||
eddyContent = "01234567890123";
|
||||
|
||||
for (int idx = 0; idx < 14; idx++)
|
||||
{
|
||||
eddyContent[idx] = payLoad[idx + 11];
|
||||
}
|
||||
|
||||
foundEddyURL.setData(eddyContent);
|
||||
Serial.printf("Reported battery voltage: %dmV\n", foundEddyURL.getVolt());
|
||||
Serial.printf("Reported temperature from TLM class: %.2fC\n", (double)foundEddyURL.getTemp());
|
||||
int temp = (int)payLoad[16] + (int)(payLoad[15] << 8);
|
||||
float calcTemp = temp / 256.0f;
|
||||
Serial.printf("Reported temperature from data: %.2fC\n", calcTemp);
|
||||
Serial.printf("Reported advertise count: %d\n", foundEddyURL.getCount());
|
||||
Serial.printf("Reported time since last reboot: %ds\n", foundEddyURL.getTime());
|
||||
Serial.println("\n");
|
||||
Serial.print(foundEddyURL.toString().c_str());
|
||||
Serial.println("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println("Scanning...");
|
||||
|
||||
BLEDevice::init("");
|
||||
pBLEScan = BLEDevice::getScan(); //create new scan
|
||||
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
|
||||
pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
|
||||
pBLEScan->setInterval(100);
|
||||
pBLEScan->setWindow(99); // less or equal setInterval value
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// put your main code here, to run repeatedly:
|
||||
BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
|
||||
Serial.print("Devices found: ");
|
||||
Serial.println(foundDevices.getCount());
|
||||
Serial.println("Scan done!");
|
||||
pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory
|
||||
delay(2000);
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
## BLE Beacon Scanner
|
||||
|
||||
Initiates a BLE device scan.
|
||||
Checks if the discovered devices are
|
||||
- an iBeacon
|
||||
- an Eddystone TLM beacon
|
||||
- an Eddystone URL beacon
|
||||
|
||||
and sends the decoded beacon information over Serial log
|
@ -0,0 +1,116 @@
|
||||
/*
|
||||
EddystoneTLM beacon by BeeGee based on https://github.com/pcbreflux/espressif/blob/master/esp32/arduino/sketchbook/ESP32_Eddystone_TLM_deepsleep/ESP32_Eddystone_TLM_deepsleep.ino
|
||||
EddystoneTLM frame specification https://github.com/google/eddystone/blob/master/eddystone-tlm/tlm-plain.md
|
||||
*/
|
||||
|
||||
/*
|
||||
Create a BLE server that will send periodic Eddystone URL frames.
|
||||
The design of creating the BLE server is:
|
||||
1. Create a BLE Server
|
||||
2. Create advertising data
|
||||
3. Start advertising.
|
||||
4. wait
|
||||
5. Stop advertising.
|
||||
6. deep sleep
|
||||
|
||||
*/
|
||||
#include "sys/time.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "BLEDevice.h"
|
||||
#include "BLEUtils.h"
|
||||
#include "BLEBeacon.h"
|
||||
#include "BLEAdvertising.h"
|
||||
#include "BLEEddystoneURL.h"
|
||||
|
||||
#include "esp_sleep.h"
|
||||
|
||||
#define GPIO_DEEP_SLEEP_DURATION 10 // sleep x seconds and then wake up
|
||||
RTC_DATA_ATTR static time_t last; // remember last boot in RTC Memory
|
||||
RTC_DATA_ATTR static uint32_t bootcount; // remember number of boots in RTC Memory
|
||||
|
||||
// See the following for generating UUIDs:
|
||||
// https://www.uuidgenerator.net/
|
||||
BLEAdvertising *pAdvertising;
|
||||
struct timeval nowTimeStruct;
|
||||
|
||||
time_t lastTenth;
|
||||
|
||||
#define BEACON_UUID "8ec76ea3-6668-48da-9866-75be8bc86f4d" // UUID 1 128-Bit (may use linux tool uuidgen or random numbers via https://www.uuidgenerator.net/)
|
||||
|
||||
// Check
|
||||
// https://github.com/google/eddystone/blob/master/eddystone-tlm/tlm-plain.md
|
||||
// and http://www.hugi.scene.org/online/coding/hugi%2015%20-%20cmtadfix.htm
|
||||
// for the temperature value. It is a 8.8 fixed-point notation
|
||||
void setBeacon()
|
||||
{
|
||||
char beacon_data[25];
|
||||
uint16_t beconUUID = 0xFEAA;
|
||||
uint16_t volt = random(2800, 3700); // 3300mV = 3.3V
|
||||
float tempFloat = random(2000, 3100) / 100.0f;
|
||||
Serial.printf("Random temperature is %.2fC\n", tempFloat);
|
||||
int temp = (int)(tempFloat * 256); //(uint16_t)((float)23.00);
|
||||
Serial.printf("Converted to 8.8 format %0X%0X\n", (temp >> 8), (temp & 0xFF));
|
||||
|
||||
BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
|
||||
BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
|
||||
|
||||
oScanResponseData.setFlags(0x06); // GENERAL_DISC_MODE 0x02 | BR_EDR_NOT_SUPPORTED 0x04
|
||||
oScanResponseData.setCompleteServices(BLEUUID(beconUUID));
|
||||
|
||||
beacon_data[0] = 0x20; // Eddystone Frame Type (Unencrypted Eddystone-TLM)
|
||||
beacon_data[1] = 0x00; // TLM version
|
||||
beacon_data[2] = (volt >> 8); // Battery voltage, 1 mV/bit i.e. 0xCE4 = 3300mV = 3.3V
|
||||
beacon_data[3] = (volt & 0xFF); //
|
||||
beacon_data[4] = (temp >> 8); // Beacon temperature
|
||||
beacon_data[5] = (temp & 0xFF); //
|
||||
beacon_data[6] = ((bootcount & 0xFF000000) >> 24); // Advertising PDU count
|
||||
beacon_data[7] = ((bootcount & 0xFF0000) >> 16); //
|
||||
beacon_data[8] = ((bootcount & 0xFF00) >> 8); //
|
||||
beacon_data[9] = (bootcount & 0xFF); //
|
||||
beacon_data[10] = ((lastTenth & 0xFF000000) >> 24); // Time since power-on or reboot as 0.1 second resolution counter
|
||||
beacon_data[11] = ((lastTenth & 0xFF0000) >> 16); //
|
||||
beacon_data[12] = ((lastTenth & 0xFF00) >> 8); //
|
||||
beacon_data[13] = (lastTenth & 0xFF); //
|
||||
|
||||
oScanResponseData.setServiceData(BLEUUID(beconUUID), std::string(beacon_data, 14));
|
||||
oAdvertisementData.setName("TLMBeacon");
|
||||
pAdvertising->setAdvertisementData(oAdvertisementData);
|
||||
pAdvertising->setScanResponseData(oScanResponseData);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
|
||||
Serial.begin(115200);
|
||||
gettimeofday(&nowTimeStruct, NULL);
|
||||
|
||||
Serial.printf("start ESP32 %d\n", bootcount++);
|
||||
|
||||
Serial.printf("deep sleep (%lds since last reset, %lds since last boot)\n", nowTimeStruct.tv_sec, nowTimeStruct.tv_sec - last);
|
||||
|
||||
last = nowTimeStruct.tv_sec;
|
||||
lastTenth = nowTimeStruct.tv_sec * 10; // Time since last reset as 0.1 second resolution counter
|
||||
|
||||
// Create the BLE Device
|
||||
BLEDevice::init("TLMBeacon");
|
||||
|
||||
BLEDevice::setPower(ESP_PWR_LVL_N12);
|
||||
|
||||
pAdvertising = BLEDevice::getAdvertising();
|
||||
|
||||
setBeacon();
|
||||
// Start advertising
|
||||
pAdvertising->start();
|
||||
Serial.println("Advertizing started for 10s ...");
|
||||
delay(10000);
|
||||
pAdvertising->stop();
|
||||
Serial.printf("enter deep sleep for 10s\n");
|
||||
esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION);
|
||||
Serial.printf("in deep sleep\n");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
## Eddystone TLM beacon
|
||||
EddystoneTLM beacon by BeeGee based on
|
||||
[pcbreflux ESP32 Eddystone TLM deepsleep](https://github.com/pcbreflux/espressif/blob/master/esp32/arduino/sketchbook/ESP32_Eddystone_TLM_deepsleep/ESP32_Eddystone_TLM_deepsleep.ino)
|
||||
|
||||
[EddystoneTLM frame specification](https://github.com/google/eddystone/blob/master/eddystone-tlm/tlm-plain.md)
|
||||
|
||||
Create a BLE server that will send periodic Eddystone TLM frames.
|
||||
The design of creating the BLE server is:
|
||||
1. Create a BLE Server
|
||||
2. Create advertising data
|
||||
3. Start advertising.
|
||||
4. wait
|
||||
5. Stop advertising.
|
||||
6. deep sleep
|
@ -0,0 +1,192 @@
|
||||
/*
|
||||
EddystoneURL beacon by BeeGee
|
||||
EddystoneURL frame specification https://github.com/google/eddystone/blob/master/eddystone-url/README.md
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
Create a BLE server that will send periodic Eddystone URL frames.
|
||||
The design of creating the BLE server is:
|
||||
1. Create a BLE Server
|
||||
2. Create advertising data
|
||||
3. Start advertising.
|
||||
4. wait
|
||||
5. Stop advertising.
|
||||
6. deep sleep
|
||||
|
||||
*/
|
||||
#include "sys/time.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "BLEDevice.h"
|
||||
#include "BLEUtils.h"
|
||||
#include "BLEBeacon.h"
|
||||
#include "BLEAdvertising.h"
|
||||
#include "BLEEddystoneURL.h"
|
||||
|
||||
#include "esp_sleep.h"
|
||||
|
||||
#define GPIO_DEEP_SLEEP_DURATION 10 // sleep x seconds and then wake up
|
||||
RTC_DATA_ATTR static time_t last; // remember last boot in RTC Memory
|
||||
RTC_DATA_ATTR static uint32_t bootcount; // remember number of boots in RTC Memory
|
||||
|
||||
// See the following for generating UUIDs:
|
||||
// https://www.uuidgenerator.net/
|
||||
BLEAdvertising *pAdvertising;
|
||||
struct timeval now;
|
||||
|
||||
#define BEACON_UUID "8ec76ea3-6668-48da-9866-75be8bc86f4d" // UUID 1 128-Bit (may use linux tool uuidgen or random numbers via https://www.uuidgenerator.net/)
|
||||
|
||||
static const char *eddystone_url_prefix_subs[] = {
|
||||
"http://www.",
|
||||
"https://www.",
|
||||
"http://",
|
||||
"https://",
|
||||
"urn:uuid:",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *eddystone_url_suffix_subs[] = {
|
||||
".com/",
|
||||
".org/",
|
||||
".edu/",
|
||||
".net/",
|
||||
".info/",
|
||||
".biz/",
|
||||
".gov/",
|
||||
".com",
|
||||
".org",
|
||||
".edu",
|
||||
".net",
|
||||
".info",
|
||||
".biz",
|
||||
".gov",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int string_begin_with(const char *str, const char *prefix)
|
||||
{
|
||||
int prefix_len = strlen(prefix);
|
||||
if (strncmp(prefix, str, prefix_len) == 0)
|
||||
{
|
||||
return prefix_len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setBeacon()
|
||||
{
|
||||
BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
|
||||
BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
|
||||
|
||||
const char url[] = "https://d.giesecke.tk";
|
||||
|
||||
int scheme_len, ext_len = 1, i, idx, url_idx;
|
||||
char *ret_data;
|
||||
int url_len = strlen(url);
|
||||
|
||||
ret_data = (char *)calloc(1, url_len + 13);
|
||||
|
||||
ret_data[0] = 2; // Len
|
||||
ret_data[1] = 0x01; // Type Flags
|
||||
ret_data[2] = 0x06; // GENERAL_DISC_MODE 0x02 | BR_EDR_NOT_SUPPORTED 0x04
|
||||
ret_data[3] = 3; // Len
|
||||
ret_data[4] = 0x03; // Type 16-Bit UUID
|
||||
ret_data[5] = 0xAA; // Eddystone UUID 2 -> 0xFEAA LSB
|
||||
ret_data[6] = 0xFE; // Eddystone UUID 1 MSB
|
||||
ret_data[7] = 19; // Length of Beacon Data
|
||||
ret_data[8] = 0x16; // Type Service Data
|
||||
ret_data[9] = 0xAA; // Eddystone UUID 2 -> 0xFEAA LSB
|
||||
ret_data[10] = 0xFE; // Eddystone UUID 1 MSB
|
||||
ret_data[11] = 0x10; // Eddystone Frame Type
|
||||
ret_data[12] = 0xF4; // Beacons TX power at 0m
|
||||
|
||||
i = 0, idx = 13, url_idx = 0;
|
||||
|
||||
//replace prefix
|
||||
scheme_len = 0;
|
||||
while (eddystone_url_prefix_subs[i] != NULL)
|
||||
{
|
||||
if ((scheme_len = string_begin_with(url, eddystone_url_prefix_subs[i])) > 0)
|
||||
{
|
||||
ret_data[idx] = i;
|
||||
idx++;
|
||||
url_idx += scheme_len;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
while (url_idx < url_len)
|
||||
{
|
||||
i = 0;
|
||||
ret_data[idx] = url[url_idx];
|
||||
ext_len = 1;
|
||||
while (eddystone_url_suffix_subs[i] != NULL)
|
||||
{
|
||||
if ((ext_len = string_begin_with(&url[url_idx], eddystone_url_suffix_subs[i])) > 0)
|
||||
{
|
||||
ret_data[idx] = i;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
ext_len = 1; //inc 1
|
||||
}
|
||||
i++;
|
||||
}
|
||||
url_idx += ext_len;
|
||||
idx++;
|
||||
}
|
||||
ret_data[7] = idx - 8;
|
||||
|
||||
Serial.printf("struct size %d url size %d reported len %d\n",
|
||||
url_len + 13,
|
||||
url_len, ret_data[7]);
|
||||
|
||||
Serial.printf("URL in data %s\n", &ret_data[13]);
|
||||
|
||||
std::string eddyStoneData(ret_data);
|
||||
|
||||
oAdvertisementData.addData(eddyStoneData);
|
||||
oScanResponseData.setName("URLBeacon");
|
||||
pAdvertising->setAdvertisementData(oAdvertisementData);
|
||||
pAdvertising->setScanResponseData(oScanResponseData);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
|
||||
Serial.begin(115200);
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
Serial.printf("start ESP32 %d\n", bootcount++);
|
||||
|
||||
Serial.printf("deep sleep (%lds since last reset, %lds since last boot)\n", now.tv_sec, now.tv_sec - last);
|
||||
|
||||
last = now.tv_sec;
|
||||
|
||||
// Create the BLE Device
|
||||
BLEDevice::init("URLBeacon");
|
||||
|
||||
BLEDevice::setPower(ESP_PWR_LVL_N12);
|
||||
|
||||
// Create the BLE Server
|
||||
// BLEServer *pServer = BLEDevice::createServer(); // <-- no longer required to instantiate BLEServer, less flash and ram usage
|
||||
|
||||
pAdvertising = BLEDevice::getAdvertising();
|
||||
|
||||
setBeacon();
|
||||
// Start advertising
|
||||
pAdvertising->start();
|
||||
Serial.println("Advertizing started...");
|
||||
delay(10000);
|
||||
pAdvertising->stop();
|
||||
Serial.printf("enter deep sleep\n");
|
||||
esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION);
|
||||
Serial.printf("in deep sleep\n");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
## Eddystone URL beacon
|
||||
EddystoneURL beacon by BeeGee based on
|
||||
[pcbreflux ESP32 Eddystone URL deepsleep](https://github.com/pcbreflux/espressif/tree/master/esp32/arduino/sketchbook/ESP32_Eddystone_URL_deepsleep)
|
||||
|
||||
[EddystoneURL frame specification](https://github.com/google/eddystone/blob/master/eddystone-url/README.md)
|
||||
|
||||
Create a BLE server that will send periodic Eddystone URL frames.
|
||||
The design of creating the BLE server is:
|
||||
1. Create a BLE Server
|
||||
2. Create advertising data
|
||||
3. Start advertising.
|
||||
4. wait
|
||||
5. Stop advertising.
|
||||
6. deep sleep
|
@ -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.
|
||||
|
@ -65,6 +65,7 @@ void setBeacon() {
|
||||
|
||||
pAdvertising->setAdvertisementData(oAdvertisementData);
|
||||
pAdvertising->setScanResponseData(oScanResponseData);
|
||||
pAdvertising->setAdvertisementType(ADV_TYPE_NONCONN_IND);
|
||||
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
@ -58,14 +59,37 @@ BLEAddress::BLEAddress(std::string stringAddress) {
|
||||
* @return True if the addresses are equal.
|
||||
*/
|
||||
bool BLEAddress::equals(BLEAddress otherAddress) {
|
||||
return memcmp(otherAddress.getNative(), m_address, 6) == 0;
|
||||
return memcmp(otherAddress.getNative(), m_address, ESP_BD_ADDR_LEN) == 0;
|
||||
} // equals
|
||||
|
||||
bool BLEAddress::operator==(const BLEAddress& otherAddress) const {
|
||||
return memcmp(otherAddress.m_address, m_address, ESP_BD_ADDR_LEN) == 0;
|
||||
}
|
||||
|
||||
bool BLEAddress::operator!=(const BLEAddress& otherAddress) const {
|
||||
return !(*this == otherAddress);
|
||||
}
|
||||
|
||||
bool BLEAddress::operator<(const BLEAddress& otherAddress) const {
|
||||
return memcmp(otherAddress.m_address, m_address, ESP_BD_ADDR_LEN) < 0;
|
||||
}
|
||||
|
||||
bool BLEAddress::operator<=(const BLEAddress& otherAddress) const {
|
||||
return !(*this > otherAddress);
|
||||
}
|
||||
|
||||
bool BLEAddress::operator>=(const BLEAddress& otherAddress) const {
|
||||
return !(*this < otherAddress);
|
||||
}
|
||||
|
||||
bool BLEAddress::operator>(const BLEAddress& otherAddress) const {
|
||||
return memcmp(otherAddress.m_address, m_address, ESP_BD_ADDR_LEN) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the native representation of the address.
|
||||
* @return The native representation of the address.
|
||||
*/
|
||||
*/
|
||||
esp_bd_addr_t *BLEAddress::getNative() {
|
||||
return &m_address;
|
||||
} // getNative
|
||||
@ -83,13 +107,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
|
||||
|
@ -23,6 +23,12 @@ public:
|
||||
BLEAddress(esp_bd_addr_t address);
|
||||
BLEAddress(std::string stringAddress);
|
||||
bool equals(BLEAddress otherAddress);
|
||||
bool operator==(const BLEAddress& otherAddress) const;
|
||||
bool operator!=(const BLEAddress& otherAddress) const;
|
||||
bool operator<(const BLEAddress& otherAddress) const;
|
||||
bool operator<=(const BLEAddress& otherAddress) const;
|
||||
bool operator>(const BLEAddress& otherAddress) const;
|
||||
bool operator>=(const BLEAddress& otherAddress) const;
|
||||
esp_bd_addr_t* getNative();
|
||||
std::string toString();
|
||||
|
||||
|
@ -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,9 @@ BLEAdvertisedDevice::BLEAdvertisedDevice() {
|
||||
m_manufacturerData = "";
|
||||
m_name = "";
|
||||
m_rssi = -9999;
|
||||
m_serviceData = "";
|
||||
m_serviceUUIDs = {};
|
||||
m_serviceData = {};
|
||||
m_serviceDataUUIDs = {};
|
||||
m_txPower = 0;
|
||||
m_pScan = nullptr;
|
||||
|
||||
@ -39,8 +35,6 @@ BLEAdvertisedDevice::BLEAdvertisedDevice() {
|
||||
m_haveManufacturerData = false;
|
||||
m_haveName = false;
|
||||
m_haveRSSI = false;
|
||||
m_haveServiceData = false;
|
||||
m_haveServiceUUID = false;
|
||||
m_haveTXPower = false;
|
||||
|
||||
} // BLEAdvertisedDevice
|
||||
@ -107,31 +101,76 @@ BLEScan* BLEAdvertisedDevice::getScan() {
|
||||
return m_pScan;
|
||||
} // getScan
|
||||
|
||||
/**
|
||||
* @brief Get the number of service data.
|
||||
* @return Number of service data discovered.
|
||||
*/
|
||||
int BLEAdvertisedDevice::getServiceDataCount() {
|
||||
return m_serviceData.size();
|
||||
} //getServiceDataCount
|
||||
|
||||
/**
|
||||
* @brief Get the service data.
|
||||
* @return The ServiceData of the advertised device.
|
||||
*/
|
||||
std::string BLEAdvertisedDevice::getServiceData() {
|
||||
return m_serviceData;
|
||||
return m_serviceData.empty() ? std::string() : m_serviceData.front();
|
||||
} //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 number of service data UUIDs.
|
||||
* @return Number of service data UUIDs discovered.
|
||||
*/
|
||||
int BLEAdvertisedDevice::getServiceDataUUIDCount() {
|
||||
return m_serviceDataUUIDs.size();
|
||||
} //getServiceDataUUIDCount
|
||||
|
||||
/**
|
||||
* @brief Get the service data UUID.
|
||||
* @return The service data UUID.
|
||||
*/
|
||||
BLEUUID BLEAdvertisedDevice::getServiceDataUUID() {
|
||||
return m_serviceDataUUID;
|
||||
return m_serviceDataUUIDs.empty() ? BLEUUID() : m_serviceDataUUIDs.front();
|
||||
} // 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 number of service UUIDs.
|
||||
* @return Number of service UUIDs discovered.
|
||||
*/
|
||||
int BLEAdvertisedDevice::getServiceUUIDCount() {
|
||||
return m_serviceUUIDs.size();
|
||||
} //getServiceUUIDCount
|
||||
|
||||
/**
|
||||
* @brief Get the Service UUID.
|
||||
* @return The Service UUID of the advertised device.
|
||||
*/
|
||||
BLEUUID BLEAdvertisedDevice::getServiceUUID() { //TODO Remove it eventually, is no longer useful
|
||||
return m_serviceUUIDs[0];
|
||||
BLEUUID BLEAdvertisedDevice::getServiceUUID() {
|
||||
return m_serviceUUIDs.empty() ? BLEUUID() : m_serviceUUIDs.front();
|
||||
} // getServiceUUID
|
||||
|
||||
/**
|
||||
* @brief Get the Service UUID.
|
||||
* @return The Service UUID of the advertised device.
|
||||
*/
|
||||
BLEUUID BLEAdvertisedDevice::getServiceUUID(int i) {
|
||||
return m_serviceUUIDs[i];
|
||||
} // getServiceUUID
|
||||
|
||||
/**
|
||||
@ -139,7 +178,7 @@ BLEUUID BLEAdvertisedDevice::getServiceUUID() { //TODO Remove it eventually, is
|
||||
* @return Return true if service is advertised
|
||||
*/
|
||||
bool BLEAdvertisedDevice::isAdvertisingService(BLEUUID uuid){
|
||||
for (int i = 0; i < m_serviceUUIDs.size(); i++) {
|
||||
for (int i = 0; i < getServiceUUIDCount(); i++) {
|
||||
if (m_serviceUUIDs[i].equals(uuid)) return true;
|
||||
}
|
||||
return false;
|
||||
@ -196,7 +235,7 @@ bool BLEAdvertisedDevice::haveRSSI() {
|
||||
* @return True if there is a service data value present.
|
||||
*/
|
||||
bool BLEAdvertisedDevice::haveServiceData() {
|
||||
return m_haveServiceData;
|
||||
return !m_serviceData.empty();
|
||||
} // haveServiceData
|
||||
|
||||
|
||||
@ -205,7 +244,7 @@ bool BLEAdvertisedDevice::haveServiceData() {
|
||||
* @return True if there is a service UUID value present.
|
||||
*/
|
||||
bool BLEAdvertisedDevice::haveServiceUUID() {
|
||||
return m_haveServiceUUID;
|
||||
return !m_serviceUUIDs.empty();
|
||||
} // haveServiceUUID
|
||||
|
||||
|
||||
@ -249,7 +288,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 +347,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 +360,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 +373,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 +385,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
|
||||
@ -360,6 +399,15 @@ void BLEAdvertisedDevice::parseAdvertisement(uint8_t* payload, size_t total_len)
|
||||
} // !finished
|
||||
} // parseAdvertisement
|
||||
|
||||
/**
|
||||
* @brief Parse the advertising payload.
|
||||
* @param [in] payload The payload of the advertised device.
|
||||
* @param [in] total_len The length of payload
|
||||
*/
|
||||
void BLEAdvertisedDevice::setPayload(uint8_t* payload, size_t total_len) {
|
||||
m_payload = payload;
|
||||
m_payloadLength = total_len;
|
||||
} // setPayload
|
||||
|
||||
/**
|
||||
* @brief Set the address of the advertised device.
|
||||
@ -386,7 +434,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 +446,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 +458,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 +469,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
|
||||
|
||||
|
||||
@ -449,8 +497,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
|
||||
|
||||
|
||||
@ -459,8 +506,7 @@ void BLEAdvertisedDevice::setServiceUUID(BLEUUID serviceUUID) {
|
||||
* @param [in] data ServiceData value.
|
||||
*/
|
||||
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
|
||||
|
||||
|
||||
@ -469,8 +515,8 @@ void BLEAdvertisedDevice::setServiceData(std::string serviceData) {
|
||||
* @param [in] data ServiceDataUUID value.
|
||||
*/
|
||||
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 +527,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 +536,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 < getServiceUUIDCount(); i++) {
|
||||
res += ", serviceUUID: " + getServiceUUID(i).toString();
|
||||
}
|
||||
}
|
||||
if (haveTXPower()) {
|
||||
ss << ", txPower: " << (int)getTXPower();
|
||||
char val[4];
|
||||
snprintf(val, sizeof(val), "%d", getTXPower());
|
||||
res += ", txPower: ";
|
||||
res += val;
|
||||
}
|
||||
return ss.str();
|
||||
return res;
|
||||
} // toString
|
||||
|
||||
uint8_t* BLEAdvertisedDevice::getPayload() {
|
||||
|
@ -36,8 +36,14 @@ 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();
|
||||
int getServiceDataUUIDCount();
|
||||
int getServiceUUIDCount();
|
||||
int8_t getTXPower();
|
||||
uint8_t* getPayload();
|
||||
size_t getPayloadLength();
|
||||
@ -60,6 +66,7 @@ private:
|
||||
friend class BLEScan;
|
||||
|
||||
void parseAdvertisement(uint8_t* payload, size_t total_len=62);
|
||||
void setPayload(uint8_t* payload, size_t total_len=62);
|
||||
void setAddress(BLEAddress address);
|
||||
void setAdFlag(uint8_t adFlag);
|
||||
void setAdvertizementResult(uint8_t* payload);
|
||||
@ -78,8 +85,6 @@ private:
|
||||
bool m_haveManufacturerData;
|
||||
bool m_haveName;
|
||||
bool m_haveRSSI;
|
||||
bool m_haveServiceData;
|
||||
bool m_haveServiceUUID;
|
||||
bool m_haveTXPower;
|
||||
|
||||
|
||||
@ -93,8 +98,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,22 +22,15 @@
|
||||
#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.
|
||||
*
|
||||
*/
|
||||
BLEAdvertising::BLEAdvertising() {
|
||||
BLEAdvertising::BLEAdvertising()
|
||||
: m_scanRespData{}
|
||||
{
|
||||
m_advData.set_scan_rsp = false;
|
||||
m_advData.include_name = true;
|
||||
m_advData.include_txpower = true;
|
||||
@ -94,6 +87,14 @@ 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::setAdvertisementChannelMap(esp_ble_adv_channel_t channel_map) {
|
||||
m_advParams.channel_map = channel_map;
|
||||
} // setAdvertisementChannelMap
|
||||
|
||||
void BLEAdvertising::setMinInterval(uint16_t mininterval) {
|
||||
m_advParams.adv_int_min = mininterval;
|
||||
} // setMinInterval
|
||||
@ -120,25 +121,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 +150,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 +167,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 +184,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 +196,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,18 +215,23 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_customScanResponseData && m_scanResp) {
|
||||
m_advData.set_scan_rsp = true;
|
||||
m_advData.include_name = m_scanResp;
|
||||
m_advData.include_txpower = m_scanResp;
|
||||
errRc = ::esp_ble_gap_config_adv_data(&m_advData);
|
||||
// Set the configuration for scan response.
|
||||
memcpy(&m_scanRespData, &m_advData, sizeof(esp_ble_adv_data_t)); // Copy the content of m_advData.
|
||||
m_scanRespData.set_scan_rsp = true; // Define this struct as scan response data
|
||||
m_scanRespData.include_name = true; // Caution: This may lead to a crash if the device name has more than 29 characters
|
||||
m_scanRespData.include_txpower = true;
|
||||
m_scanRespData.appearance = 0; // If defined the 'Appearance' attribute is already included in the advertising data
|
||||
m_scanRespData.flag = 0; // 'Flags' attribute should no be included in the scan response
|
||||
|
||||
errRc = ::esp_ble_gap_config_adv_data(&m_scanRespData);
|
||||
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 +246,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 +259,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 +379,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 +393,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 +482,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 +503,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 +519,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:
|
||||
|
@ -30,7 +30,7 @@ public:
|
||||
void setPartialServices(BLEUUID uuid);
|
||||
void setServiceData(BLEUUID uuid, std::string data);
|
||||
void setShortName(std::string name);
|
||||
void addData(std::string data); // Add data to the payload.
|
||||
void addData(std::string data); // Add data to the payload.
|
||||
std::string getPayload(); // Retrieve the current advert payload.
|
||||
|
||||
private:
|
||||
@ -52,12 +52,15 @@ public:
|
||||
void start();
|
||||
void stop();
|
||||
void setAppearance(uint16_t appearance);
|
||||
void setAdvertisementType(esp_ble_adv_type_t adv_type);
|
||||
void setAdvertisementChannelMap(esp_ble_adv_channel_t channel_map);
|
||||
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);
|
||||
@ -66,13 +69,14 @@ public:
|
||||
|
||||
private:
|
||||
esp_ble_adv_data_t m_advData;
|
||||
esp_ble_adv_data_t m_scanRespData; // Used for configuration of scan response data when m_scanResp is true
|
||||
esp_ble_adv_params_t m_advParams;
|
||||
std::vector<BLEUUID> m_serviceUUIDs;
|
||||
bool m_customAdvData = false; // Are we using custom advertising data?
|
||||
bool m_customScanResponseData = false; // Are we using custom scan response data?
|
||||
FreeRTOS::Semaphore m_semaphoreSetAdv = FreeRTOS::Semaphore("startAdvert");
|
||||
bool m_scanResp = true;
|
||||
bool m_scanResp = true;
|
||||
|
||||
};
|
||||
#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:
|
||||
@ -224,21 +219,22 @@ void BLECharacteristic::handleGATTServerEvent(
|
||||
// - uint8_t exec_write_flag - Either ESP_GATT_PREP_WRITE_EXEC or ESP_GATT_PREP_WRITE_CANCEL
|
||||
//
|
||||
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) {
|
||||
if(m_writeEvt){
|
||||
m_writeEvt = false;
|
||||
if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) {
|
||||
m_value.commit();
|
||||
m_pCallbacks->onWrite(this); // Invoke the onWrite callback handler.
|
||||
} else {
|
||||
m_value.cancel();
|
||||
}
|
||||
// ???
|
||||
esp_err_t errRc = ::esp_ble_gatts_send_response(
|
||||
gatts_if,
|
||||
param->write.conn_id,
|
||||
param->write.trans_id, ESP_GATT_OK, nullptr);
|
||||
if (errRc != ESP_OK) {
|
||||
log_e("esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
} else {
|
||||
m_value.cancel();
|
||||
}
|
||||
// ???
|
||||
esp_err_t errRc = ::esp_ble_gatts_send_response(
|
||||
gatts_if,
|
||||
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));
|
||||
}
|
||||
break;
|
||||
} // ESP_GATTS_EXEC_WRITE_EVT
|
||||
@ -284,15 +280,16 @@ void BLECharacteristic::handleGATTServerEvent(
|
||||
if (param->write.handle == m_handle) {
|
||||
if (param->write.is_prep) {
|
||||
m_value.addPart(param->write.value, param->write.len);
|
||||
m_writeEvt = true;
|
||||
} else {
|
||||
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 +306,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 +358,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 +381,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 +399,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 +413,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 +428,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 +453,7 @@ void BLECharacteristic::handleGATTServerEvent(
|
||||
// event.
|
||||
|
||||
m_descriptorMap.handleGATTServerEvent(event, gatts_if, param);
|
||||
ESP_LOGD(LOG_TAG, "<< handleGATTServerEvent");
|
||||
log_v("<< handleGATTServerEvent");
|
||||
} // handleGATTServerEvent
|
||||
|
||||
|
||||
@ -468,9 +465,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 +478,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 +499,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 +557,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 +571,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 +592,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 +603,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 +617,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 +631,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 +647,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 +697,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 +712,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 +726,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 +740,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 +763,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 +773,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 */
|
||||
|
@ -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;
|
||||
@ -105,6 +107,7 @@ private:
|
||||
BLEService* m_pService;
|
||||
BLEValue m_value;
|
||||
esp_gatt_perm_t m_permissions = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE;
|
||||
bool m_writeEvt = false; // If we have started a long write, this tells the commit code that we were the target
|
||||
|
||||
void handleGATTServerEvent(
|
||||
esp_gatts_cb_event_t event,
|
||||
@ -117,6 +120,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 +133,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
|
||||
|
||||
|
||||
|
@ -18,14 +18,7 @@
|
||||
#include <sstream>
|
||||
#include <unordered_set>
|
||||
#include "BLEDevice.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 = "BLEClient";
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Design
|
||||
@ -67,6 +60,7 @@ BLEClient::~BLEClient() {
|
||||
delete myPair.second;
|
||||
}
|
||||
m_servicesMap.clear();
|
||||
m_servicesMapByInstID.clear();
|
||||
} // ~BLEClient
|
||||
|
||||
|
||||
@ -75,14 +69,14 @@ BLEClient::~BLEClient() {
|
||||
*
|
||||
*/
|
||||
void BLEClient::clearServices() {
|
||||
ESP_LOGD(LOG_TAG, ">> clearServices");
|
||||
log_v(">> clearServices");
|
||||
// Delete all the services.
|
||||
for (auto &myPair : m_servicesMap) {
|
||||
delete myPair.second;
|
||||
}
|
||||
m_servicesMap.clear();
|
||||
m_haveServices = false;
|
||||
ESP_LOGD(LOG_TAG, "<< clearServices");
|
||||
log_v("<< clearServices");
|
||||
} // clearServices
|
||||
|
||||
/**
|
||||
@ -100,7 +94,7 @@ bool BLEClient::connect(BLEAdvertisedDevice* device) {
|
||||
* @return True on success.
|
||||
*/
|
||||
bool BLEClient::connect(BLEAddress address, esp_ble_addr_type_t type) {
|
||||
ESP_LOGD(LOG_TAG, ">> connect(%s)", address.toString().c_str());
|
||||
log_v(">> connect(%s)", address.toString().c_str());
|
||||
|
||||
// We need the connection handle that we get from registering the application. We register the app
|
||||
// and then block on its completion. When the event has arrived, we will have the handle.
|
||||
@ -111,11 +105,22 @@ bool BLEClient::connect(BLEAddress address, esp_ble_addr_type_t type) {
|
||||
// clearServices(); // we dont need to delete services since every client is unique?
|
||||
esp_err_t errRc = ::esp_ble_gattc_app_register(m_appId);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_app_register: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_ble_gattc_app_register: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
BLEDevice::removePeerDevice(m_appId, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_semaphoreRegEvt.wait("connect");
|
||||
uint32_t rc = m_semaphoreRegEvt.wait("connect");
|
||||
|
||||
if (rc != ESP_GATT_OK) {
|
||||
// fixes ESP_GATT_NO_RESOURCES error mostly
|
||||
log_e("esp_ble_gattc_app_register_error: rc=%d", rc);
|
||||
BLEDevice::removePeerDevice(m_appId, true);
|
||||
// not sure if this is needed here
|
||||
// esp_ble_gattc_app_unregister(m_gattc_if);
|
||||
// m_gattc_if = ESP_GATT_IF_NONE;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_peerAddress = address;
|
||||
|
||||
@ -128,12 +133,19 @@ bool BLEClient::connect(BLEAddress address, esp_ble_addr_type_t type) {
|
||||
1 // direct connection <-- maybe needs to be changed in case of direct indirect connection???
|
||||
);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_open: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_ble_gattc_open: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
BLEDevice::removePeerDevice(m_appId, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t rc = m_semaphoreOpenEvt.wait("connect"); // Wait for the connection to complete.
|
||||
ESP_LOGD(LOG_TAG, "<< connect(), rc=%d", rc==ESP_GATT_OK);
|
||||
rc = m_semaphoreOpenEvt.wait("connect"); // Wait for the connection to complete.
|
||||
// check the status of the connection and cleanup in case of failure
|
||||
if (rc != ESP_GATT_OK) {
|
||||
BLEDevice::removePeerDevice(m_appId, true);
|
||||
esp_ble_gattc_app_unregister(m_gattc_if);
|
||||
m_gattc_if = ESP_GATT_IF_NONE;
|
||||
}
|
||||
log_v("<< connect(), rc=%d", rc==ESP_GATT_OK);
|
||||
return rc == ESP_GATT_OK;
|
||||
} // connect
|
||||
|
||||
@ -143,13 +155,13 @@ bool BLEClient::connect(BLEAddress address, esp_ble_addr_type_t type) {
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLEClient::disconnect() {
|
||||
ESP_LOGD(LOG_TAG, ">> disconnect()");
|
||||
log_v(">> disconnect()");
|
||||
esp_err_t errRc = ::esp_ble_gattc_close(getGattcIf(), getConnId());
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_close: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_ble_gattc_close: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(LOG_TAG, "<< disconnect()");
|
||||
log_v("<< disconnect()");
|
||||
} // disconnect
|
||||
|
||||
|
||||
@ -161,14 +173,19 @@ void BLEClient::gattClientEventHandler(
|
||||
esp_gatt_if_t gattc_if,
|
||||
esp_ble_gattc_cb_param_t* evtParam) {
|
||||
|
||||
ESP_LOGD(LOG_TAG, "gattClientEventHandler [esp_gatt_if: %d] ... %s",
|
||||
log_d("gattClientEventHandler [esp_gatt_if: %d] ... %s",
|
||||
gattc_if, BLEUtils::gattClientEventTypeToString(event).c_str());
|
||||
|
||||
// it is possible to receive events from other connections while waiting for registration
|
||||
if (m_gattc_if == ESP_GATT_IF_NONE && event != ESP_GATTC_REG_EVT) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Execute handler code based on the type of event received.
|
||||
switch(event) {
|
||||
|
||||
case ESP_GATTC_SRVC_CHG_EVT:
|
||||
ESP_LOGI(LOG_TAG, "SERVICE CHANGED");
|
||||
log_i("SERVICE CHANGED");
|
||||
break;
|
||||
|
||||
case ESP_GATTC_CLOSE_EVT: {
|
||||
@ -185,16 +202,20 @@ void BLEClient::gattClientEventHandler(
|
||||
// - uint16_t conn_id
|
||||
// - esp_bd_addr_t remote_bda
|
||||
case ESP_GATTC_DISCONNECT_EVT: {
|
||||
if (evtParam->disconnect.conn_id != getConnId()) break;
|
||||
// If we receive a disconnect event, set the class flag that indicates that we are
|
||||
// no longer connected.
|
||||
bool m_wasConnected = m_isConnected;
|
||||
m_isConnected = false;
|
||||
if (m_pClientCallbacks != nullptr) {
|
||||
m_pClientCallbacks->onDisconnect(this);
|
||||
}
|
||||
BLEDevice::removePeerDevice(m_appId, true);
|
||||
esp_ble_gattc_app_unregister(m_gattc_if);
|
||||
m_gattc_if = ESP_GATT_IF_NONE;
|
||||
m_semaphoreOpenEvt.give(ESP_GATT_IF_NONE);
|
||||
m_semaphoreRssiCmplEvt.give();
|
||||
m_semaphoreSearchCmplEvt.give(1);
|
||||
BLEDevice::removePeerDevice(m_appId, true);
|
||||
if (m_wasConnected && m_pClientCallbacks != nullptr) {
|
||||
m_pClientCallbacks->onDisconnect(this);
|
||||
}
|
||||
break;
|
||||
} // ESP_GATTC_DISCONNECT_EVT
|
||||
|
||||
@ -208,11 +229,13 @@ void BLEClient::gattClientEventHandler(
|
||||
//
|
||||
case ESP_GATTC_OPEN_EVT: {
|
||||
m_conn_id = evtParam->open.conn_id;
|
||||
if (m_pClientCallbacks != nullptr) {
|
||||
m_pClientCallbacks->onConnect(this);
|
||||
}
|
||||
if (evtParam->open.status == ESP_GATT_OK) {
|
||||
m_isConnected = true; // Flag us as connected.
|
||||
if (m_pClientCallbacks != nullptr) {
|
||||
m_pClientCallbacks->onConnect(this);
|
||||
}
|
||||
} else {
|
||||
log_e("Failed to connect, status=%s", GeneralUtils::errorToString(evtParam->open.status));
|
||||
}
|
||||
m_semaphoreOpenEvt.give(evtParam->open.status);
|
||||
break;
|
||||
@ -228,22 +251,25 @@ void BLEClient::gattClientEventHandler(
|
||||
//
|
||||
case ESP_GATTC_REG_EVT: {
|
||||
m_gattc_if = gattc_if;
|
||||
m_semaphoreRegEvt.give();
|
||||
// pass on the registration status result, in case of failure
|
||||
m_semaphoreRegEvt.give(evtParam->reg.status);
|
||||
break;
|
||||
} // ESP_GATTC_REG_EVT
|
||||
|
||||
case ESP_GATTC_CFG_MTU_EVT:
|
||||
if (evtParam->cfg_mtu.conn_id != getConnId()) break;
|
||||
if(evtParam->cfg_mtu.status != ESP_GATT_OK) {
|
||||
ESP_LOGE(LOG_TAG,"Config mtu failed");
|
||||
log_e("Config mtu failed");
|
||||
}
|
||||
m_mtu = evtParam->cfg_mtu.mtu;
|
||||
break;
|
||||
|
||||
case ESP_GATTC_CONNECT_EVT: {
|
||||
BLEDevice::updatePeerDevice(this, true, m_gattc_if);
|
||||
if (evtParam->connect.conn_id != getConnId()) break;
|
||||
BLEDevice::updatePeerDevice(this, true, m_appId);
|
||||
esp_err_t errRc = esp_ble_gattc_send_mtu_req(gattc_if, evtParam->connect.conn_id);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_send_mtu_req: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_ble_gattc_send_mtu_req: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
if(BLEDevice::m_securityLevel){
|
||||
@ -261,19 +287,20 @@ void BLEClient::gattClientEventHandler(
|
||||
// - uint16_t conn_id
|
||||
//
|
||||
case ESP_GATTC_SEARCH_CMPL_EVT: {
|
||||
if (evtParam->search_cmpl.conn_id != getConnId()) break;
|
||||
esp_ble_gattc_cb_param_t* p_data = (esp_ble_gattc_cb_param_t*)evtParam;
|
||||
if (p_data->search_cmpl.status != ESP_GATT_OK){
|
||||
ESP_LOGE(LOG_TAG, "search service failed, error status = %x", p_data->search_cmpl.status);
|
||||
log_e("search service failed, error status = %x", p_data->search_cmpl.status);
|
||||
break;
|
||||
}
|
||||
#ifndef ARDUINO_ARCH_ESP32
|
||||
// commented out just for now to keep backward compatibility
|
||||
// if(p_data->search_cmpl.searched_service_source == ESP_GATT_SERVICE_FROM_REMOTE_DEVICE) {
|
||||
// ESP_LOGI(LOG_TAG, "Get service information from remote device");
|
||||
// log_i("Get service information from remote device");
|
||||
// } else if (p_data->search_cmpl.searched_service_source == ESP_GATT_SERVICE_FROM_NVS_FLASH) {
|
||||
// ESP_LOGI(LOG_TAG, "Get service information from flash");
|
||||
// log_i("Get service information from flash");
|
||||
// } else {
|
||||
// ESP_LOGI(LOG_TAG, "unknown service source");
|
||||
// log_i("unknown service source");
|
||||
// }
|
||||
#endif
|
||||
m_semaphoreSearchCmplEvt.give(0);
|
||||
@ -291,6 +318,7 @@ void BLEClient::gattClientEventHandler(
|
||||
// - esp_gatt_id_t srvc_id
|
||||
//
|
||||
case ESP_GATTC_SEARCH_RES_EVT: {
|
||||
if (evtParam->search_res.conn_id != getConnId()) break;
|
||||
BLEUUID uuid = BLEUUID(evtParam->search_res.srvc_id);
|
||||
BLERemoteService* pRemoteService = new BLERemoteService(
|
||||
evtParam->search_res.srvc_id,
|
||||
@ -343,9 +371,9 @@ BLEAddress BLEClient::getPeerAddress() {
|
||||
* @return The RSSI value.
|
||||
*/
|
||||
int BLEClient::getRssi() {
|
||||
ESP_LOGD(LOG_TAG, ">> getRssi()");
|
||||
log_v(">> getRssi()");
|
||||
if (!isConnected()) {
|
||||
ESP_LOGD(LOG_TAG, "<< getRssi(): Not connected");
|
||||
log_v("<< getRssi(): Not connected");
|
||||
return 0;
|
||||
}
|
||||
// We make the API call to read the RSSI value which is an asynchronous operation. We expect to receive
|
||||
@ -354,11 +382,11 @@ int BLEClient::getRssi() {
|
||||
m_semaphoreRssiCmplEvt.take("getRssi");
|
||||
esp_err_t rc = ::esp_ble_gap_read_rssi(*getPeerAddress().getNative());
|
||||
if (rc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "<< getRssi: esp_ble_gap_read_rssi: rc=%d %s", rc, GeneralUtils::errorToString(rc));
|
||||
log_e("<< getRssi: esp_ble_gap_read_rssi: rc=%d %s", rc, GeneralUtils::errorToString(rc));
|
||||
return 0;
|
||||
}
|
||||
int rssiValue = m_semaphoreRssiCmplEvt.wait("getRssi");
|
||||
ESP_LOGD(LOG_TAG, "<< getRssi(): %d", rssiValue);
|
||||
log_v("<< getRssi(): %d", rssiValue);
|
||||
return rssiValue;
|
||||
} // getRssi
|
||||
|
||||
@ -380,7 +408,7 @@ BLERemoteService* BLEClient::getService(const char* uuid) {
|
||||
* @throws BLEUuidNotFound
|
||||
*/
|
||||
BLERemoteService* BLEClient::getService(BLEUUID uuid) {
|
||||
ESP_LOGD(LOG_TAG, ">> getService: uuid: %s", uuid.toString().c_str());
|
||||
log_v(">> getService: uuid: %s", uuid.toString().c_str());
|
||||
// Design
|
||||
// ------
|
||||
// We wish to retrieve the service given its UUID. It is possible that we have not yet asked the
|
||||
@ -393,11 +421,11 @@ BLERemoteService* BLEClient::getService(BLEUUID uuid) {
|
||||
std::string uuidStr = uuid.toString();
|
||||
for (auto &myPair : m_servicesMap) {
|
||||
if (myPair.first == uuidStr) {
|
||||
ESP_LOGD(LOG_TAG, "<< getService: found the service with uuid: %s", uuid.toString().c_str());
|
||||
log_v("<< getService: found the service with uuid: %s", uuid.toString().c_str());
|
||||
return myPair.second;
|
||||
}
|
||||
} // End of each of the services.
|
||||
ESP_LOGD(LOG_TAG, "<< getService: not found");
|
||||
log_v("<< getService: not found");
|
||||
return nullptr;
|
||||
} // getService
|
||||
|
||||
@ -416,7 +444,7 @@ std::map<std::string, BLERemoteService*>* BLEClient::getServices() {
|
||||
* peer BLE partner to be returned as events. Each event will be an an instance of ESP_GATTC_SEARCH_RES_EVT
|
||||
* and will culminate with an ESP_GATTC_SEARCH_CMPL_EVT when all have been received.
|
||||
*/
|
||||
ESP_LOGD(LOG_TAG, ">> getServices");
|
||||
log_v(">> getServices");
|
||||
// TODO implement retrieving services from cache
|
||||
clearServices(); // Clear any services that may exist.
|
||||
|
||||
@ -428,12 +456,12 @@ std::map<std::string, BLERemoteService*>* BLEClient::getServices() {
|
||||
|
||||
m_semaphoreSearchCmplEvt.take("getServices");
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_search_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_ble_gattc_search_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return &m_servicesMap;
|
||||
}
|
||||
// If sucessfull, remember that we now have services.
|
||||
m_haveServices = (m_semaphoreSearchCmplEvt.wait("getServices") == 0);
|
||||
ESP_LOGD(LOG_TAG, "<< getServices");
|
||||
log_v("<< getServices");
|
||||
return &m_servicesMap;
|
||||
} // getServices
|
||||
|
||||
@ -445,9 +473,9 @@ std::map<std::string, BLERemoteService*>* BLEClient::getServices() {
|
||||
* @throws BLEUuidNotFound
|
||||
*/
|
||||
std::string BLEClient::getValue(BLEUUID serviceUUID, BLEUUID characteristicUUID) {
|
||||
ESP_LOGD(LOG_TAG, ">> getValue: serviceUUID: %s, characteristicUUID: %s", serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
||||
log_v(">> getValue: serviceUUID: %s, characteristicUUID: %s", serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
||||
std::string ret = getService(serviceUUID)->getCharacteristic(characteristicUUID)->readValue();
|
||||
ESP_LOGD(LOG_TAG, "<<getValue");
|
||||
log_v("<<getValue");
|
||||
return ret;
|
||||
} // getValue
|
||||
|
||||
@ -461,7 +489,7 @@ std::string BLEClient::getValue(BLEUUID serviceUUID, BLEUUID characteristicUUID)
|
||||
void BLEClient::handleGAPEvent(
|
||||
esp_gap_ble_cb_event_t event,
|
||||
esp_ble_gap_cb_param_t* param) {
|
||||
ESP_LOGD(LOG_TAG, "BLEClient ... handling GAP event!");
|
||||
log_d("BLEClient ... handling GAP event!");
|
||||
switch (event) {
|
||||
//
|
||||
// ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT
|
||||
@ -508,9 +536,9 @@ void BLEClient::setClientCallbacks(BLEClientCallbacks* pClientCallbacks) {
|
||||
* @throws BLEUuidNotFound
|
||||
*/
|
||||
void BLEClient::setValue(BLEUUID serviceUUID, BLEUUID characteristicUUID, std::string value) {
|
||||
ESP_LOGD(LOG_TAG, ">> setValue: serviceUUID: %s, characteristicUUID: %s", serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
||||
log_v(">> setValue: serviceUUID: %s, characteristicUUID: %s", serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
||||
getService(serviceUUID)->getCharacteristic(characteristicUUID)->writeValue(value);
|
||||
ESP_LOGD(LOG_TAG, "<< setValue");
|
||||
log_v("<< setValue");
|
||||
} // setValue
|
||||
|
||||
uint16_t BLEClient::getMTU() {
|
||||
@ -522,14 +550,13 @@ uint16_t BLEClient::getMTU() {
|
||||
* @return A string representation of this client.
|
||||
*/
|
||||
std::string BLEClient::toString() {
|
||||
std::ostringstream ss;
|
||||
ss << "peer address: " << m_peerAddress.toString();
|
||||
ss << "\nServices:\n";
|
||||
std::string res = "peer address: " + m_peerAddress.toString();
|
||||
res += "\nServices:\n";
|
||||
for (auto &myPair : m_servicesMap) {
|
||||
ss << myPair.second->toString() << "\n";
|
||||
res += myPair.second->toString() + "\n";
|
||||
// myPair.second is the value
|
||||
}
|
||||
return ss.str();
|
||||
return res;
|
||||
} // toString
|
||||
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include <string.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "BLEExceptions.h"
|
||||
//#include "BLEExceptions.h"
|
||||
#include "BLERemoteService.h"
|
||||
#include "BLEService.h"
|
||||
#include "BLEAddress.h"
|
||||
|
@ -15,16 +15,7 @@
|
||||
#include "BLEService.h"
|
||||
#include "BLEDescriptor.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 = "BLEDescriptor";
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#define NULL_HANDLE (0xffff)
|
||||
|
||||
@ -63,10 +54,10 @@ BLEDescriptor::~BLEDescriptor() {
|
||||
* @param [in] pCharacteristic The characteristic to which to register this descriptor.
|
||||
*/
|
||||
void BLEDescriptor::executeCreate(BLECharacteristic* pCharacteristic) {
|
||||
ESP_LOGD(LOG_TAG, ">> executeCreate(): %s", toString().c_str());
|
||||
log_v(">> executeCreate(): %s", toString().c_str());
|
||||
|
||||
if (m_handle != NULL_HANDLE) {
|
||||
ESP_LOGE(LOG_TAG, "Descriptor already has a handle.");
|
||||
log_e("Descriptor already has a handle.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -82,12 +73,12 @@ void BLEDescriptor::executeCreate(BLECharacteristic* pCharacteristic) {
|
||||
&m_value,
|
||||
&control);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_add_char_descr: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("<< esp_ble_gatts_add_char_descr: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
|
||||
m_semaphoreCreateEvt.wait("executeCreate");
|
||||
ESP_LOGD(LOG_TAG, "<< executeCreate");
|
||||
log_v("<< executeCreate");
|
||||
} // executeCreate
|
||||
|
||||
|
||||
@ -213,9 +204,9 @@ void BLEDescriptor::handleGATTServerEvent(
|
||||
* @param [in] pCallbacks An instance of a callback structure used to define any callbacks for the descriptor.
|
||||
*/
|
||||
void BLEDescriptor::setCallbacks(BLEDescriptorCallbacks* pCallback) {
|
||||
ESP_LOGD(LOG_TAG, ">> setCallbacks: 0x%x", (uint32_t) pCallback);
|
||||
log_v(">> setCallbacks: 0x%x", (uint32_t) pCallback);
|
||||
m_pCallback = pCallback;
|
||||
ESP_LOGD(LOG_TAG, "<< setCallbacks");
|
||||
log_v("<< setCallbacks");
|
||||
} // setCallbacks
|
||||
|
||||
|
||||
@ -226,9 +217,9 @@ void BLEDescriptor::setCallbacks(BLEDescriptorCallbacks* pCallback) {
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLEDescriptor::setHandle(uint16_t handle) {
|
||||
ESP_LOGD(LOG_TAG, ">> setHandle(0x%.2x): Setting descriptor handle to be 0x%.2x", handle, handle);
|
||||
log_v(">> setHandle(0x%.2x): Setting descriptor handle to be 0x%.2x", handle, handle);
|
||||
m_handle = handle;
|
||||
ESP_LOGD(LOG_TAG, "<< setHandle()");
|
||||
log_v("<< setHandle()");
|
||||
} // setHandle
|
||||
|
||||
|
||||
@ -239,7 +230,7 @@ void BLEDescriptor::setHandle(uint16_t handle) {
|
||||
*/
|
||||
void BLEDescriptor::setValue(uint8_t* data, size_t length) {
|
||||
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_value.attr_len = length;
|
||||
@ -264,10 +255,10 @@ void BLEDescriptor::setAccessPermissions(esp_gatt_perm_t perm) {
|
||||
* @return A string representation of the descriptor.
|
||||
*/
|
||||
std::string BLEDescriptor::toString() {
|
||||
std::stringstream stringstream;
|
||||
stringstream << std::hex << std::setfill('0');
|
||||
stringstream << "UUID: " << m_bleUUID.toString() + ", handle: 0x" << std::setw(2) << m_handle;
|
||||
return stringstream.str();
|
||||
char hex[5];
|
||||
snprintf(hex, sizeof(hex), "%04x", m_handle);
|
||||
std::string res = "UUID: " + m_bleUUID.toString() + ", handle: 0x" + hex;
|
||||
return res;
|
||||
} // toString
|
||||
|
||||
|
||||
@ -278,8 +269,8 @@ BLEDescriptorCallbacks::~BLEDescriptorCallbacks() {}
|
||||
* @param [in] pDescriptor The descriptor that is the source of the event.
|
||||
*/
|
||||
void BLEDescriptorCallbacks::onRead(BLEDescriptor* pDescriptor) {
|
||||
ESP_LOGD("BLEDescriptorCallbacks", ">> onRead: default");
|
||||
ESP_LOGD("BLEDescriptorCallbacks", "<< onRead");
|
||||
log_d("BLEDescriptorCallbacks", ">> onRead: default");
|
||||
log_d("BLEDescriptorCallbacks", "<< onRead");
|
||||
} // onRead
|
||||
|
||||
|
||||
@ -288,8 +279,8 @@ void BLEDescriptorCallbacks::onRead(BLEDescriptor* pDescriptor) {
|
||||
* @param [in] pDescriptor The descriptor that is the source of the event.
|
||||
*/
|
||||
void BLEDescriptorCallbacks::onWrite(BLEDescriptor* pDescriptor) {
|
||||
ESP_LOGD("BLEDescriptorCallbacks", ">> onWrite: default");
|
||||
ESP_LOGD("BLEDescriptorCallbacks", "<< onWrite");
|
||||
log_d("BLEDescriptorCallbacks", ">> onWrite: default");
|
||||
log_d("BLEDescriptorCallbacks", "<< onWrite");
|
||||
} // onWrite
|
||||
|
||||
|
||||
|
@ -90,17 +90,18 @@ void BLEDescriptorMap::setByHandle(uint16_t handle, BLEDescriptor* pDescriptor)
|
||||
* @return A string representation of the descriptor map.
|
||||
*/
|
||||
std::string BLEDescriptorMap::toString() {
|
||||
std::stringstream stringStream;
|
||||
stringStream << std::hex << std::setfill('0');
|
||||
std::string res;
|
||||
char hex[5];
|
||||
int count = 0;
|
||||
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
|
||||
|
||||
|
||||
|
@ -32,13 +32,7 @@
|
||||
#include "esp32-hal-bt.h"
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define LOG_TAG ""
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* LOG_TAG = "BLEDevice";
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
@ -63,13 +57,13 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
* @return A new instance of the client.
|
||||
*/
|
||||
/* STATIC */ BLEClient* BLEDevice::createClient() {
|
||||
ESP_LOGD(LOG_TAG, ">> createClient");
|
||||
log_v(">> createClient");
|
||||
#ifndef CONFIG_GATTC_ENABLE // Check that BLE GATTC is enabled in make menuconfig
|
||||
ESP_LOGE(LOG_TAG, "BLE GATTC is not enabled - CONFIG_GATTC_ENABLE not defined");
|
||||
log_e("BLE GATTC is not enabled - CONFIG_GATTC_ENABLE not defined");
|
||||
abort();
|
||||
#endif // CONFIG_GATTC_ENABLE
|
||||
m_pClient = new BLEClient();
|
||||
ESP_LOGD(LOG_TAG, "<< createClient");
|
||||
log_v("<< createClient");
|
||||
return m_pClient;
|
||||
} // createClient
|
||||
|
||||
@ -79,14 +73,14 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
* @return A new instance of the server.
|
||||
*/
|
||||
/* STATIC */ BLEServer* BLEDevice::createServer() {
|
||||
ESP_LOGD(LOG_TAG, ">> createServer");
|
||||
log_v(">> createServer");
|
||||
#ifndef CONFIG_GATTS_ENABLE // Check that BLE GATTS is enabled in make menuconfig
|
||||
ESP_LOGE(LOG_TAG, "BLE GATTS is not enabled - CONFIG_GATTS_ENABLE not defined");
|
||||
log_e("BLE GATTS is not enabled - CONFIG_GATTS_ENABLE not defined");
|
||||
abort();
|
||||
#endif // CONFIG_GATTS_ENABLE
|
||||
m_pServer = new BLEServer();
|
||||
m_pServer->createApp(m_appId++);
|
||||
ESP_LOGD(LOG_TAG, "<< createServer");
|
||||
log_v("<< createServer");
|
||||
return m_pServer;
|
||||
} // createServer
|
||||
|
||||
@ -103,7 +97,7 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
esp_gatt_if_t gatts_if,
|
||||
esp_ble_gatts_cb_param_t* param
|
||||
) {
|
||||
ESP_LOGD(LOG_TAG, "gattServerEventHandler [esp_gatt_if: %d] ... %s",
|
||||
log_d("gattServerEventHandler [esp_gatt_if: %d] ... %s",
|
||||
gatts_if,
|
||||
BLEUtils::gattServerEventTypeToString(event).c_str());
|
||||
|
||||
@ -150,7 +144,7 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
esp_gatt_if_t gattc_if,
|
||||
esp_ble_gattc_cb_param_t* param) {
|
||||
|
||||
ESP_LOGD(LOG_TAG, "gattClientEventHandler [esp_gatt_if: %d] ... %s",
|
||||
log_d("gattClientEventHandler [esp_gatt_if: %d] ... %s",
|
||||
gattc_if, BLEUtils::gattClientEventTypeToString(event).c_str());
|
||||
BLEUtils::dumpGattClientEvent(event, gattc_if, param);
|
||||
|
||||
@ -194,16 +188,16 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
switch(event) {
|
||||
|
||||
case ESP_GAP_BLE_OOB_REQ_EVT: /* OOB request event */
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_OOB_REQ_EVT");
|
||||
log_i("ESP_GAP_BLE_OOB_REQ_EVT");
|
||||
break;
|
||||
case ESP_GAP_BLE_LOCAL_IR_EVT: /* BLE local IR event */
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_LOCAL_IR_EVT");
|
||||
log_i("ESP_GAP_BLE_LOCAL_IR_EVT");
|
||||
break;
|
||||
case ESP_GAP_BLE_LOCAL_ER_EVT: /* BLE local ER event */
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_LOCAL_ER_EVT");
|
||||
log_i("ESP_GAP_BLE_LOCAL_ER_EVT");
|
||||
break;
|
||||
case ESP_GAP_BLE_NC_REQ_EVT: /* NUMERIC CONFIRMATION */
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_NC_REQ_EVT");
|
||||
log_i("ESP_GAP_BLE_NC_REQ_EVT");
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
if(BLEDevice::m_securityCallbacks != nullptr){
|
||||
esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, BLEDevice::m_securityCallbacks->onConfirmPIN(param->ble_security.key_notif.passkey));
|
||||
@ -211,8 +205,8 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
#endif // CONFIG_BLE_SMP_ENABLE
|
||||
break;
|
||||
case ESP_GAP_BLE_PASSKEY_REQ_EVT: /* passkey request event */
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PASSKEY_REQ_EVT: ");
|
||||
// esp_log_buffer_hex(LOG_TAG, m_remote_bda, sizeof(m_remote_bda));
|
||||
log_i("ESP_GAP_BLE_PASSKEY_REQ_EVT: ");
|
||||
// esp_log_buffer_hex(m_remote_bda, sizeof(m_remote_bda));
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
if(BLEDevice::m_securityCallbacks != nullptr){
|
||||
esp_ble_passkey_reply(param->ble_security.ble_req.bd_addr, true, BLEDevice::m_securityCallbacks->onPassKeyRequest());
|
||||
@ -225,7 +219,7 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
case ESP_GAP_BLE_SEC_REQ_EVT:
|
||||
/* send the positive(true) security response to the peer device to accept the security request.
|
||||
If not accept the security request, should sent the security response with negative(false) accept value*/
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_SEC_REQ_EVT");
|
||||
log_i("ESP_GAP_BLE_SEC_REQ_EVT");
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
if(BLEDevice::m_securityCallbacks!=nullptr){
|
||||
esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, BLEDevice::m_securityCallbacks->onSecurityRequest());
|
||||
@ -240,9 +234,9 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
*/
|
||||
case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: //the app will receive this evt when the IO has Output capability and the peer device IO has Input capability.
|
||||
//display the passkey number to the user to input it in the peer deivce within 30 seconds
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PASSKEY_NOTIF_EVT");
|
||||
log_i("ESP_GAP_BLE_PASSKEY_NOTIF_EVT");
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
ESP_LOGI(LOG_TAG, "passKey = %d", param->ble_security.key_notif.passkey);
|
||||
log_i("passKey = %d", param->ble_security.key_notif.passkey);
|
||||
if(BLEDevice::m_securityCallbacks!=nullptr){
|
||||
BLEDevice::m_securityCallbacks->onPassKeyNotify(param->ble_security.key_notif.passkey);
|
||||
}
|
||||
@ -250,13 +244,13 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
break;
|
||||
case ESP_GAP_BLE_KEY_EVT:
|
||||
//shows the ble key type info share with peer device to the user.
|
||||
ESP_LOGD(LOG_TAG, "ESP_GAP_BLE_KEY_EVT");
|
||||
log_d("ESP_GAP_BLE_KEY_EVT");
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
ESP_LOGI(LOG_TAG, "key type = %s", BLESecurity::esp_key_type_to_str(param->ble_security.ble_key.key_type));
|
||||
log_i("key type = %s", BLESecurity::esp_key_type_to_str(param->ble_security.ble_key.key_type));
|
||||
#endif // CONFIG_BLE_SMP_ENABLE
|
||||
break;
|
||||
case ESP_GAP_BLE_AUTH_CMPL_EVT:
|
||||
ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_AUTH_CMPL_EVT");
|
||||
log_i("ESP_GAP_BLE_AUTH_CMPL_EVT");
|
||||
#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig
|
||||
if(BLEDevice::m_securityCallbacks != nullptr){
|
||||
BLEDevice::m_securityCallbacks->onAuthenticationComplete(param->ble_security.auth_cmpl);
|
||||
@ -305,12 +299,12 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
* try and release/delete it.
|
||||
*/
|
||||
/* STATIC */ BLEScan* BLEDevice::getScan() {
|
||||
//ESP_LOGD(LOG_TAG, ">> getScan");
|
||||
//log_v(">> getScan");
|
||||
if (m_pScan == nullptr) {
|
||||
m_pScan = new BLEScan();
|
||||
//ESP_LOGD(LOG_TAG, " - creating a new scan object");
|
||||
//log_d(" - creating a new scan object");
|
||||
}
|
||||
//ESP_LOGD(LOG_TAG, "<< getScan: Returning object at 0x%x", (uint32_t)m_pScan);
|
||||
//log_v("<< getScan: Returning object at 0x%x", (uint32_t)m_pScan);
|
||||
return m_pScan;
|
||||
} // getScan
|
||||
|
||||
@ -322,12 +316,12 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
* @param [in] characteristicUUID
|
||||
*/
|
||||
/* STATIC */ std::string BLEDevice::getValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID) {
|
||||
ESP_LOGD(LOG_TAG, ">> getValue: bdAddress: %s, serviceUUID: %s, characteristicUUID: %s", bdAddress.toString().c_str(), serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
||||
log_v(">> getValue: bdAddress: %s, serviceUUID: %s, characteristicUUID: %s", bdAddress.toString().c_str(), serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
||||
BLEClient* pClient = createClient();
|
||||
pClient->connect(bdAddress);
|
||||
std::string ret = pClient->getValue(serviceUUID, characteristicUUID);
|
||||
pClient->disconnect();
|
||||
ESP_LOGD(LOG_TAG, "<< getValue");
|
||||
log_v("<< getValue");
|
||||
return ret;
|
||||
} // getValue
|
||||
|
||||
@ -349,7 +343,7 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
#else
|
||||
errRc = ::nvs_flash_init();
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "nvs_flash_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("nvs_flash_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -359,20 +353,20 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
errRc = esp_bt_controller_init(&bt_cfg);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_bt_controller_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_bt_controller_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef CLASSIC_BT_ENABLED
|
||||
errRc = esp_bt_controller_enable(ESP_BT_MODE_BLE);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_bt_controller_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_bt_controller_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
#else
|
||||
errRc = esp_bt_controller_enable(ESP_BT_MODE_BTDM);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_bt_controller_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_bt_controller_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@ -382,7 +376,7 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
if (bt_state == ESP_BLUEDROID_STATUS_UNINITIALIZED) {
|
||||
errRc = esp_bluedroid_init();
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_bluedroid_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_bluedroid_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -390,21 +384,21 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
if (bt_state != ESP_BLUEDROID_STATUS_ENABLED) {
|
||||
errRc = esp_bluedroid_enable();
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_bluedroid_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_bluedroid_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
errRc = esp_ble_gap_register_callback(BLEDevice::gapEventHandler);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_ble_gap_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GATTC_ENABLE // Check that BLE client is configured in make menuconfig
|
||||
errRc = esp_ble_gattc_register_callback(BLEDevice::gattClientEventHandler);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gattc_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_ble_gattc_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
#endif // CONFIG_GATTC_ENABLE
|
||||
@ -412,14 +406,14 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
#ifdef CONFIG_GATTS_ENABLE // Check that BLE server is configured in make menuconfig
|
||||
errRc = esp_ble_gatts_register_callback(BLEDevice::gattServerEventHandler);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gatts_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_ble_gatts_register_callback: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
}
|
||||
#endif // CONFIG_GATTS_ENABLE
|
||||
|
||||
errRc = ::esp_ble_gap_set_device_name(deviceName.c_str());
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_set_device_name: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_ble_gap_set_device_name: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
};
|
||||
|
||||
@ -427,7 +421,7 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE;
|
||||
errRc = ::esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t));
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_set_security_param: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_ble_gap_set_security_param: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
};
|
||||
#endif // CONFIG_BLE_SMP_ENABLE
|
||||
@ -447,15 +441,30 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
* * ESP_PWR_LVL_P1
|
||||
* * ESP_PWR_LVL_P4
|
||||
* * ESP_PWR_LVL_P7
|
||||
*
|
||||
* The power types can be one of:
|
||||
* * ESP_BLE_PWR_TYPE_CONN_HDL0
|
||||
* * ESP_BLE_PWR_TYPE_CONN_HDL1
|
||||
* * ESP_BLE_PWR_TYPE_CONN_HDL2
|
||||
* * ESP_BLE_PWR_TYPE_CONN_HDL3
|
||||
* * ESP_BLE_PWR_TYPE_CONN_HDL4
|
||||
* * ESP_BLE_PWR_TYPE_CONN_HDL5
|
||||
* * ESP_BLE_PWR_TYPE_CONN_HDL6
|
||||
* * ESP_BLE_PWR_TYPE_CONN_HDL7
|
||||
* * ESP_BLE_PWR_TYPE_CONN_HDL8
|
||||
* * ESP_BLE_PWR_TYPE_ADV
|
||||
* * ESP_BLE_PWR_TYPE_SCAN
|
||||
* * ESP_BLE_PWR_TYPE_DEFAULT
|
||||
* @param [in] powerType.
|
||||
* @param [in] powerLevel.
|
||||
*/
|
||||
/* STATIC */ void BLEDevice::setPower(esp_power_level_t powerLevel) {
|
||||
ESP_LOGD(LOG_TAG, ">> setPower: %d", powerLevel);
|
||||
esp_err_t errRc = ::esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_DEFAULT, powerLevel);
|
||||
/* STATIC */ void BLEDevice::setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType) {
|
||||
log_v(">> setPower: %d (type: %d)", powerLevel, powerType);
|
||||
esp_err_t errRc = ::esp_ble_tx_power_set(powerType, powerLevel);
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_tx_power_set: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_ble_tx_power_set: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
};
|
||||
ESP_LOGD(LOG_TAG, "<< setPower");
|
||||
log_v("<< setPower");
|
||||
} // setPower
|
||||
|
||||
|
||||
@ -466,7 +475,7 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
* @param [in] characteristicUUID
|
||||
*/
|
||||
/* STATIC */ void BLEDevice::setValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID, std::string value) {
|
||||
ESP_LOGD(LOG_TAG, ">> setValue: bdAddress: %s, serviceUUID: %s, characteristicUUID: %s", bdAddress.toString().c_str(), serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
||||
log_v(">> setValue: bdAddress: %s, serviceUUID: %s, characteristicUUID: %s", bdAddress.toString().c_str(), serviceUUID.toString().c_str(), characteristicUUID.toString().c_str());
|
||||
BLEClient* pClient = createClient();
|
||||
pClient->connect(bdAddress);
|
||||
pClient->setValue(serviceUUID, characteristicUUID, value);
|
||||
@ -479,9 +488,8 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
* @return A string representation of the nature of this device.
|
||||
*/
|
||||
/* STATIC */ std::string BLEDevice::toString() {
|
||||
std::ostringstream oss;
|
||||
oss << "BD Address: " << getAddress().toString();
|
||||
return oss.str();
|
||||
std::string res = "BD Address: " + getAddress().toString();
|
||||
return res;
|
||||
} // toString
|
||||
|
||||
|
||||
@ -490,12 +498,12 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
* @param [in] address The address to add to the white list.
|
||||
*/
|
||||
void BLEDevice::whiteListAdd(BLEAddress address) {
|
||||
ESP_LOGD(LOG_TAG, ">> whiteListAdd: %s", address.toString().c_str());
|
||||
log_v(">> whiteListAdd: %s", address.toString().c_str());
|
||||
esp_err_t errRc = esp_ble_gap_update_whitelist(true, *address.getNative()); // True to add an entry.
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_update_whitelist: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_ble_gap_update_whitelist: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
ESP_LOGD(LOG_TAG, "<< whiteListAdd");
|
||||
log_v("<< whiteListAdd");
|
||||
} // whiteListAdd
|
||||
|
||||
|
||||
@ -504,12 +512,12 @@ void BLEDevice::whiteListAdd(BLEAddress address) {
|
||||
* @param [in] address The address to remove from the white list.
|
||||
*/
|
||||
void BLEDevice::whiteListRemove(BLEAddress address) {
|
||||
ESP_LOGD(LOG_TAG, ">> whiteListRemove: %s", address.toString().c_str());
|
||||
log_v(">> whiteListRemove: %s", address.toString().c_str());
|
||||
esp_err_t errRc = esp_ble_gap_update_whitelist(false, *address.getNative()); // False to remove an entry.
|
||||
if (errRc != ESP_OK) {
|
||||
ESP_LOGE(LOG_TAG, "esp_ble_gap_update_whitelist: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
log_e("esp_ble_gap_update_whitelist: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
ESP_LOGD(LOG_TAG, "<< whiteListRemove");
|
||||
log_v("<< whiteListRemove");
|
||||
} // whiteListRemove
|
||||
|
||||
/*
|
||||
@ -533,14 +541,14 @@ void BLEDevice::setSecurityCallbacks(BLESecurityCallbacks* callbacks) {
|
||||
* @param [in] mtu Value to set local mtu, should be larger than 23 and lower or equal to 517
|
||||
*/
|
||||
esp_err_t BLEDevice::setMTU(uint16_t mtu) {
|
||||
ESP_LOGD(LOG_TAG, ">> setLocalMTU: %d", mtu);
|
||||
log_v(">> setLocalMTU: %d", mtu);
|
||||
esp_err_t err = esp_ble_gatt_set_local_mtu(mtu);
|
||||
if (err == ESP_OK) {
|
||||
m_localMTU = mtu;
|
||||
} else {
|
||||
ESP_LOGE(LOG_TAG, "can't set local mtu value: %d", mtu);
|
||||
log_e("can't set local mtu value: %d", mtu);
|
||||
}
|
||||
ESP_LOGD(LOG_TAG, "<< setLocalMTU");
|
||||
log_v("<< setLocalMTU");
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -558,18 +566,24 @@ bool BLEDevice::getInitialized() {
|
||||
BLEAdvertising* BLEDevice::getAdvertising() {
|
||||
if(m_bleAdvertising == nullptr) {
|
||||
m_bleAdvertising = new BLEAdvertising();
|
||||
ESP_LOGI(LOG_TAG, "create advertising");
|
||||
log_i("create advertising");
|
||||
}
|
||||
ESP_LOGD(LOG_TAG, "get advertising");
|
||||
log_d("get advertising");
|
||||
return m_bleAdvertising;
|
||||
}
|
||||
|
||||
void BLEDevice::startAdvertising() {
|
||||
ESP_LOGD(LOG_TAG, ">> startAdvertising");
|
||||
log_v(">> startAdvertising");
|
||||
getAdvertising()->start();
|
||||
ESP_LOGD(LOG_TAG, "<< startAdvertising");
|
||||
log_v("<< startAdvertising");
|
||||
} // startAdvertising
|
||||
|
||||
void BLEDevice::stopAdvertising() {
|
||||
log_v(">> stopAdvertising");
|
||||
getAdvertising()->stop();
|
||||
log_v("<< stopAdvertising");
|
||||
} // stopAdvertising
|
||||
|
||||
/* multi connect support */
|
||||
/* requires a little more work */
|
||||
std::map<uint16_t, conn_status_t> BLEDevice::getPeerDevices(bool _client) {
|
||||
@ -581,7 +595,7 @@ BLEClient* BLEDevice::getClientByGattIf(uint16_t conn_id) {
|
||||
}
|
||||
|
||||
void BLEDevice::updatePeerDevice(void* peer, bool _client, uint16_t conn_id) {
|
||||
ESP_LOGD(LOG_TAG, "update conn_id: %d, GATT role: %s", conn_id, _client? "client":"server");
|
||||
log_d("update conn_id: %d, GATT role: %s", conn_id, _client? "client":"server");
|
||||
std::map<uint16_t, conn_status_t>::iterator it = m_connectedClientsMap.find(ESP_GATT_IF_NONE);
|
||||
if (it != m_connectedClientsMap.end()) {
|
||||
std::swap(m_connectedClientsMap[conn_id], it->second);
|
||||
@ -597,7 +611,7 @@ void BLEDevice::updatePeerDevice(void* peer, bool _client, uint16_t conn_id) {
|
||||
}
|
||||
|
||||
void BLEDevice::addPeerDevice(void* peer, bool _client, uint16_t conn_id) {
|
||||
ESP_LOGI(LOG_TAG, "add conn_id: %d, GATT role: %s", conn_id, _client? "client":"server");
|
||||
log_i("add conn_id: %d, GATT role: %s", conn_id, _client? "client":"server");
|
||||
conn_status_t status = {
|
||||
.peer_device = peer,
|
||||
.connected = true,
|
||||
@ -608,7 +622,7 @@ void BLEDevice::addPeerDevice(void* peer, bool _client, uint16_t conn_id) {
|
||||
}
|
||||
|
||||
void BLEDevice::removePeerDevice(uint16_t conn_id, bool _client) {
|
||||
ESP_LOGI(LOG_TAG, "remove: %d, GATT role %s", conn_id, _client?"client":"server");
|
||||
log_i("remove: %d, GATT role %s", conn_id, _client?"client":"server");
|
||||
if(m_connectedClientsMap.find(conn_id) != m_connectedClientsMap.end())
|
||||
m_connectedClientsMap.erase(conn_id);
|
||||
}
|
||||
@ -626,7 +640,7 @@ void BLEDevice::removePeerDevice(uint16_t conn_id, bool _client) {
|
||||
esp_bluedroid_deinit();
|
||||
esp_bt_controller_disable();
|
||||
esp_bt_controller_deinit();
|
||||
#ifndef ARDUINO_ARCH_ESP32
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
if (release_memory) {
|
||||
esp_bt_controller_mem_release(ESP_BT_MODE_BTDM); // <-- require tests because we released classic BT memory and this can cause crash (most likely not, esp-idf takes care of it)
|
||||
} else {
|
||||
|
@ -37,7 +37,7 @@ public:
|
||||
static BLEScan* getScan(); // Get the scan object
|
||||
static std::string getValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID); // Get the value of a characteristic of a service on a server.
|
||||
static void init(std::string deviceName); // Initialize the local BLE environment.
|
||||
static void setPower(esp_power_level_t powerLevel); // Set our power level.
|
||||
static void setPower(esp_power_level_t powerLevel, esp_ble_power_type_t powerType=ESP_BLE_PWR_TYPE_DEFAULT); // Set our power level.
|
||||
static void setValue(BLEAddress bdAddress, BLEUUID serviceUUID, BLEUUID characteristicUUID, std::string value); // Set the value of a characteristic on a service on a server.
|
||||
static std::string toString(); // Return a string representation of our device.
|
||||
static void whiteListAdd(BLEAddress address); // Add an entry to the BLE white list.
|
||||
@ -50,6 +50,7 @@ public:
|
||||
/* move advertising to BLEDevice for saving ram and flash in beacons */
|
||||
static BLEAdvertising* getAdvertising();
|
||||
static void startAdvertising();
|
||||
static void stopAdvertising();
|
||||
static uint16_t m_appId;
|
||||
/* multi connect */
|
||||
static std::map<uint16_t, conn_status_t> getPeerDevices(bool client);
|
||||
|
@ -3,12 +3,17 @@
|
||||
*
|
||||
* Created on: Mar 12, 2018
|
||||
* Author: pcbreflux
|
||||
* Edited on: Mar 20, 2020 by beegee-tokyo
|
||||
* Fix temperature value (8.8 fixed format)
|
||||
* Fix time stamp (0.1 second resolution)
|
||||
* Fixes based on EddystoneTLM frame specification https://github.com/google/eddystone/blob/master/eddystone-tlm/tlm-plain.md
|
||||
*
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <string.h>
|
||||
#include <sstream>
|
||||
#include <esp_log.h>
|
||||
#include <stdio.h>
|
||||
#include "esp32-hal-log.h"
|
||||
#include "BLEEddystoneTLM.h"
|
||||
|
||||
static const char LOG_TAG[] = "BLEEddystoneTLM";
|
||||
@ -20,7 +25,7 @@ BLEEddystoneTLM::BLEEddystoneTLM() {
|
||||
m_eddystoneData.frameType = EDDYSTONE_TLM_FRAME_TYPE;
|
||||
m_eddystoneData.version = 0;
|
||||
m_eddystoneData.volt = 3300; // 3300mV = 3.3V
|
||||
m_eddystoneData.temp = (uint16_t) ((float) 23.00);
|
||||
m_eddystoneData.temp = (uint16_t) ((float) 23.00)/256;
|
||||
m_eddystoneData.advCount = 0;
|
||||
m_eddystoneData.tmil = 0;
|
||||
} // BLEEddystoneTLM
|
||||
@ -38,78 +43,69 @@ uint8_t BLEEddystoneTLM::getVersion() {
|
||||
} // getVersion
|
||||
|
||||
uint16_t BLEEddystoneTLM::getVolt() {
|
||||
return m_eddystoneData.volt;
|
||||
return ENDIAN_CHANGE_U16(m_eddystoneData.volt);
|
||||
} // getVolt
|
||||
|
||||
float BLEEddystoneTLM::getTemp() {
|
||||
return (float)m_eddystoneData.temp;
|
||||
return ENDIAN_CHANGE_U16(m_eddystoneData.temp) / 256.0f;
|
||||
} // getTemp
|
||||
|
||||
uint32_t BLEEddystoneTLM::getCount() {
|
||||
return m_eddystoneData.advCount;
|
||||
return ENDIAN_CHANGE_U32(m_eddystoneData.advCount);
|
||||
} // getCount
|
||||
|
||||
uint32_t BLEEddystoneTLM::getTime() {
|
||||
return m_eddystoneData.tmil;
|
||||
return (ENDIAN_CHANGE_U32(m_eddystoneData.tmil)) / 10;
|
||||
} // getTime
|
||||
|
||||
std::string BLEEddystoneTLM::toString() {
|
||||
std::stringstream ss;
|
||||
std::string out = "";
|
||||
uint32_t rawsec;
|
||||
ss << "Version ";
|
||||
ss << std::dec << m_eddystoneData.version;
|
||||
ss << "\n";
|
||||
std::string out = "";
|
||||
uint32_t rawsec = ENDIAN_CHANGE_U32(m_eddystoneData.tmil);
|
||||
char val[12];
|
||||
|
||||
ss << "Battery Voltage ";
|
||||
ss << std::dec << ENDIAN_CHANGE_U16(m_eddystoneData.volt);
|
||||
ss << " mV\n";
|
||||
out += "Version "; // + std::string(m_eddystoneData.version);
|
||||
snprintf(val, sizeof(val), "%d", m_eddystoneData.version);
|
||||
out += val;
|
||||
out += "\n";
|
||||
out += "Battery Voltage "; // + ENDIAN_CHANGE_U16(m_eddystoneData.volt);
|
||||
snprintf(val, sizeof(val), "%d", ENDIAN_CHANGE_U16(m_eddystoneData.volt));
|
||||
out += val;
|
||||
out += " mV\n";
|
||||
|
||||
ss << "Temperature ";
|
||||
ss << (float) m_eddystoneData.temp;
|
||||
ss << " °C\n";
|
||||
out += "Temperature ";
|
||||
snprintf(val, sizeof(val), "%.2f", ENDIAN_CHANGE_U16(m_eddystoneData.temp) / 256.0f);
|
||||
out += val;
|
||||
out += " C\n";
|
||||
|
||||
ss << "Adv. Count ";
|
||||
ss << std::dec << ENDIAN_CHANGE_U32(m_eddystoneData.advCount);
|
||||
out += "Adv. Count ";
|
||||
snprintf(val, sizeof(val), "%d", ENDIAN_CHANGE_U32(m_eddystoneData.advCount));
|
||||
out += val;
|
||||
out += "\n";
|
||||
|
||||
ss << "\n";
|
||||
out += "Time in seconds ";
|
||||
snprintf(val, sizeof(val), "%d", rawsec/10);
|
||||
out += val;
|
||||
out += "\n";
|
||||
|
||||
ss << "Time ";
|
||||
out += "Time ";
|
||||
|
||||
rawsec = ENDIAN_CHANGE_U32(m_eddystoneData.tmil);
|
||||
std::stringstream buffstream;
|
||||
buffstream << "0000";
|
||||
buffstream << std::dec << rawsec / 864000;
|
||||
std::string buff = buffstream.str();
|
||||
snprintf(val, sizeof(val), "%04d", rawsec / 864000);
|
||||
out += val;
|
||||
out += ".";
|
||||
|
||||
ss << buff.substr(buff.length() - 4, buff.length());
|
||||
ss << ".";
|
||||
snprintf(val, sizeof(val), "%02d", (rawsec / 36000) % 24);
|
||||
out += val;
|
||||
out += ":";
|
||||
|
||||
buffstream.str("");
|
||||
buffstream.clear();
|
||||
buffstream << "00";
|
||||
buffstream << std::dec << (rawsec / 36000) % 24;
|
||||
buff = buffstream.str();
|
||||
ss << buff.substr(buff.length()-2, buff.length());
|
||||
ss << ":";
|
||||
snprintf(val, sizeof(val), "%02d", (rawsec / 600) % 60);
|
||||
out += val;
|
||||
out += ":";
|
||||
|
||||
buffstream.str("");
|
||||
buffstream.clear();
|
||||
buffstream << "00";
|
||||
buffstream << std::dec << (rawsec / 600) % 60;
|
||||
buff = buffstream.str();
|
||||
ss << buff.substr(buff.length() - 2, buff.length());
|
||||
ss << ":";
|
||||
snprintf(val, sizeof(val), "%02d", (rawsec / 10) % 60);
|
||||
out += val;
|
||||
out += "\n";
|
||||
|
||||
buffstream.str("");
|
||||
buffstream.clear();
|
||||
buffstream << "00";
|
||||
buffstream << std::dec << (rawsec / 10) % 60;
|
||||
buff = buffstream.str();
|
||||
ss << buff.substr(buff.length() - 2, buff.length());
|
||||
ss << "\n";
|
||||
|
||||
return ss.str();
|
||||
return out;
|
||||
} // toString
|
||||
|
||||
/**
|
||||
@ -117,7 +113,7 @@ std::string BLEEddystoneTLM::toString() {
|
||||
*/
|
||||
void BLEEddystoneTLM::setData(std::string data) {
|
||||
if (data.length() != sizeof(m_eddystoneData)) {
|
||||
ESP_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and expected %d", data.length(), sizeof(m_eddystoneData));
|
||||
log_e("Unable to set the data ... length passed in was %d and expected %d", data.length(), sizeof(m_eddystoneData));
|
||||
return;
|
||||
}
|
||||
memcpy(&m_eddystoneData, data.data(), data.length());
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "sdkconfig.h"
|
||||
#if defined(CONFIG_BT_ENABLED)
|
||||
#include <string.h>
|
||||
#include <esp_log.h>
|
||||
#include "esp32-hal-log.h"
|
||||
#include "BLEEddystoneURL.h"
|
||||
|
||||
static const char LOG_TAG[] = "BLEEddystoneURL";
|
||||
@ -118,7 +118,7 @@ std::string BLEEddystoneURL::getDecodedURL() {
|
||||
*/
|
||||
void BLEEddystoneURL::setData(std::string data) {
|
||||
if (data.length() > sizeof(m_eddystoneData)) {
|
||||
ESP_LOGE(LOG_TAG, "Unable to set the data ... length passed in was %d and max expected %d", data.length(), sizeof(m_eddystoneData));
|
||||
log_e("Unable to set the data ... length passed in was %d and max expected %d", data.length(), sizeof(m_eddystoneData));
|
||||
return;
|
||||
}
|
||||
memset(&m_eddystoneData, 0, sizeof(m_eddystoneData));
|
||||
@ -136,7 +136,7 @@ void BLEEddystoneURL::setPower(int8_t advertisedTxPower) {
|
||||
|
||||
void BLEEddystoneURL::setURL(std::string url) {
|
||||
if (url.length() > sizeof(m_eddystoneData.url)) {
|
||||
ESP_LOGE(LOG_TAG, "Unable to set the url ... length passed in was %d and max expected %d", url.length(), sizeof(m_eddystoneData.url));
|
||||
log_e("Unable to set the url ... length passed in was %d and max expected %d", url.length(), sizeof(m_eddystoneData.url));
|
||||
return;
|
||||
}
|
||||
memset(m_eddystoneData.url, 0, sizeof(m_eddystoneData.url));
|
||||
|
@ -5,5 +5,5 @@
|
||||
* Author: kolban
|
||||
*/
|
||||
|
||||
#include "BLEExceptions.h"
|
||||
//#include "BLEExceptions.h"
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user