mirror of
https://github.com/0xFEEDC0DE64/arduino-esp32.git
synced 2025-06-25 18:01:33 +02:00
Compare commits
229 Commits
Author | SHA1 | Date | |
---|---|---|---|
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 |
15
.github/scripts/install-arduino-ide.sh
vendored
15
.github/scripts/install-arduino-ide.sh
vendored
@ -40,21 +40,30 @@ 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-nightly-$OS_NAME.$ARCHIVE_FORMAT' to 'arduino.$ARCHIVE_FORMAT' ..."
|
||||
echo "Downloading '$ARDUINO_IDE_URL$OS_NAME.$ARCHIVE_FORMAT' to 'arduino.$ARCHIVE_FORMAT' ..."
|
||||
if [ "$OS_IS_LINUX" == "1" ]; then
|
||||
wget -O "arduino.$ARCHIVE_FORMAT" "https://www.arduino.cc/download.php?f=/arduino-nightly-$OS_NAME.$ARCHIVE_FORMAT" > /dev/null 2>&1
|
||||
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 "https://www.arduino.cc/download.php?f=/arduino-nightly-$OS_NAME.$ARCHIVE_FORMAT" > /dev/null 2>&1
|
||||
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
|
||||
|
11
.github/scripts/install-platformio-esp32.sh
vendored
11
.github/scripts/install-platformio-esp32.sh
vendored
@ -9,22 +9,17 @@ 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#feature/stage > /dev/null 2>&1
|
||||
python -m platformio platform install https://github.com/platformio/platform-espressif32.git > /dev/null 2>&1
|
||||
|
||||
echo "Replacing the framework version ..."
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
sed 's/https:\/\/github\.com\/espressif\/arduino-esp32\.git/*/' "$HOME/.platformio/platforms/espressif32/platform.json" > "platform.json"
|
||||
mv -f "platform.json" "$HOME/.platformio/platforms/espressif32/platform.json"
|
||||
else
|
||||
sed -i 's/https:\/\/github\.com\/espressif\/arduino-esp32\.git/*/' "$HOME/.platformio/platforms/espressif32/platform.json"
|
||||
fi
|
||||
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 https://github.com/espressif/arduino-esp32.git "$PLATFORMIO_ESP32_PATH" > /dev/null 2>&1
|
||||
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"
|
||||
|
2
.github/scripts/on-release.sh
vendored
2
.github/scripts/on-release.sh
vendored
@ -330,7 +330,7 @@ fi
|
||||
if [ ! -z "$COMMITS_SINCE_RELEASE" ] && [ "$COMMITS_SINCE_RELEASE" != "null" ]; then
|
||||
echo "Getting commits since $COMMITS_SINCE_RELEASE ..."
|
||||
commitFile=$OUTPUT_DIR/commits.txt
|
||||
git -C "$GITHUB_WORKSPACE" log --oneline $COMMITS_SINCE_RELEASE.. > "$OUTPUT_DIR/commits.txt"
|
||||
git -C "$GITHUB_WORKSPACE" log --oneline "$COMMITS_SINCE_RELEASE..HEAD" > "$OUTPUT_DIR/commits.txt"
|
||||
releaseNotes+=$'\r\n##### Commits\r\n'
|
||||
IFS=$'\n'
|
||||
for next in `cat $commitFile`
|
||||
|
9
.github/workflows/push.yml
vendored
9
.github/workflows/push.yml
vendored
@ -19,6 +19,9 @@ jobs:
|
||||
|
||||
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
|
||||
|
||||
@ -32,6 +35,9 @@ jobs:
|
||||
|
||||
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
|
||||
|
||||
@ -45,5 +51,8 @@ jobs:
|
||||
|
||||
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
|
||||
|
3
.github/workflows/release.yml
vendored
3
.github/workflows/release.yml
vendored
@ -11,6 +11,9 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Build Release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -12,3 +12,4 @@ tools/mkspiffs/mkspiffs.exe
|
||||
.vs/
|
||||
__vm/
|
||||
*.vcxproj*
|
||||
.vscode/
|
||||
|
@ -60,6 +60,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 +76,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,13 +202,14 @@ 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()
|
||||
|
||||
|
@ -76,13 +76,18 @@ choice ARDUINO_UDP_RUNNING_CORE
|
||||
|
||||
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"
|
||||
|
10
README.md
10
README.md
@ -11,9 +11,11 @@
|
||||
- [ESP32Dev Board PINMAP](#esp32dev-board-pinmap)
|
||||
|
||||
### Development Status
|
||||
[Latest stable release  ](https://github.com/espressif/arduino-esp32/releases/latest/) 
|
||||
|
||||
[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/)
|
||||
|
||||
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
|
||||
- Using Arduino IDE Boards Manager (preferred)
|
||||
@ -36,12 +38,12 @@ You can use [EspExceptionDecoder](https://github.com/me-no-dev/EspExceptionDecod
|
||||
### 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
|
||||
|
||||

|
||||
|
||||
### Hint
|
||||
### Tip
|
||||
|
||||
Sometimes to program ESP32 via serial you must keep GPIO0 LOW during the programming process
|
||||
|
1784
boards.txt
1784
boards.txt
File diff suppressed because it is too large
Load Diff
@ -78,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() )
|
||||
|
||||
@ -88,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
|
||||
|
@ -218,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();
|
||||
@ -309,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,6 +76,8 @@ public:
|
||||
uint32_t getMaxAllocPsram();
|
||||
|
||||
uint8_t getChipRevision();
|
||||
const char * getChipModel();
|
||||
uint8_t getChipCores();
|
||||
uint32_t getCpuFreqMHz(){ return getCpuFrequencyMhz(); }
|
||||
inline uint32_t getCycleCount() __attribute__((always_inline));
|
||||
const char * getSdkVersion();
|
||||
@ -97,6 +100,10 @@ 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();
|
||||
|
||||
};
|
||||
|
@ -53,6 +53,8 @@ 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);
|
||||
@ -70,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -84,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;
|
||||
}
|
||||
|
||||
@ -131,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);
|
||||
@ -156,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));
|
||||
@ -92,15 +101,21 @@ 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
|
||||
|
@ -111,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('-');
|
||||
int t = 0;
|
||||
if (base == 10 && n < 0) {
|
||||
t = print('-');
|
||||
n = -n;
|
||||
return printNumber(n, 10) + t;
|
||||
}
|
||||
return printNumber(n, 10);
|
||||
} else {
|
||||
return printNumber(n, base);
|
||||
}
|
||||
return printNumber(static_cast<unsigned long>(n), base) + t;
|
||||
}
|
||||
|
||||
size_t Print::print(unsigned long n, int base)
|
||||
@ -134,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);
|
||||
@ -226,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);
|
||||
@ -251,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';
|
||||
@ -262,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)
|
||||
@ -81,6 +82,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 +97,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);
|
||||
|
@ -89,7 +89,7 @@ unsigned long Stream::getTimeout(void) {
|
||||
// find returns true if the target string is found
|
||||
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
|
||||
@ -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(*target == 0) {
|
||||
return true; // return true if target is a null string
|
||||
}
|
||||
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
|
||||
}
|
||||
if (terminator == NULL) {
|
||||
MultiTarget t[1] = {{target, targetLen, 0}};
|
||||
return findMulti(t, 1) == 0 ? true : false;
|
||||
} else {
|
||||
termIndex = 0;
|
||||
MultiTarget t[2] = {{target, targetLen, 0}, {terminator, termLen, 0}};
|
||||
return findMulti(t, 2) == 0 ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
@ -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
|
||||
|
@ -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
|
||||
|
@ -66,11 +66,11 @@ long random(long howsmall, long howbig)
|
||||
}
|
||||
|
||||
long map(long x, long in_min, long in_max, long out_min, long out_max) {
|
||||
long divisor = (in_max - in_min);
|
||||
if(divisor == 0){
|
||||
return -1; //AVR returns -1, SAM returns 0
|
||||
}
|
||||
return (x - in_min) * (out_max - out_min) / divisor + out_min;
|
||||
const long dividend = out_max - out_min;
|
||||
const long divisor = in_max - in_min;
|
||||
const long delta = x - in_min;
|
||||
|
||||
return (delta * dividend + (divisor / 2)) / divisor + out_min;
|
||||
}
|
||||
|
||||
unsigned int makeWord(unsigned int w)
|
||||
|
@ -203,8 +203,20 @@ class String {
|
||||
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 access
|
||||
char charAt(unsigned int index) const;
|
||||
@ -238,7 +250,22 @@ class String {
|
||||
|
||||
// modification
|
||||
void replace(char find, char replace);
|
||||
void replace(const String& find, const String& 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);
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -65,6 +65,14 @@ bool btStop(){
|
||||
while(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED);
|
||||
}
|
||||
if(esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED){
|
||||
if (esp_bt_controller_deinit()) {
|
||||
log_e("BT deint failed");
|
||||
return false;
|
||||
}
|
||||
vTaskDelay(1);
|
||||
if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_IDLE) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
log_e("BT Stop failed");
|
||||
|
@ -28,6 +28,7 @@
|
||||
#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;
|
||||
@ -53,10 +54,20 @@ 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;
|
||||
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);
|
||||
}
|
||||
|
||||
@ -68,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);
|
||||
@ -75,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){
|
||||
// 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);
|
||||
goto unlock_and_exit;
|
||||
xSemaphoreGive(apb_change_lock);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
c->next = apb_change_callbacks;
|
||||
apb_change_callbacks-> prev = c;
|
||||
apb_change_callbacks = c;
|
||||
}
|
||||
}
|
||||
r->next = c;
|
||||
}
|
||||
}
|
||||
unlock_and_exit:
|
||||
xSemaphoreGive(apb_change_lock);
|
||||
return true;
|
||||
}
|
||||
@ -95,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){
|
||||
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;
|
||||
@ -186,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
|
||||
|
@ -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,18 +55,19 @@ 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;
|
||||
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){
|
||||
new_apb = REF_CLK_FREQ / 1000000;
|
||||
div_num = (new_apb * old_div) / old_apb;
|
||||
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
|
||||
}
|
||||
@ -77,6 +78,13 @@ static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb
|
||||
LEDC_TIMER(group, timer).conf.clock_divider = div_num;
|
||||
LEDC_MUTEX_UNLOCK();
|
||||
}
|
||||
else {
|
||||
log_d("using REF_CLK chan=%d",chan);
|
||||
}
|
||||
}
|
||||
iarg = iarg >> 1;
|
||||
chan++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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,21 @@ 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 channel = rmt->channel;
|
||||
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 +298,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 +325,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 +359,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 +367,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 +394,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 +514,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 +539,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 +562,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 +587,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 +605,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 +678,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;
|
||||
|
@ -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)
|
||||
@ -431,12 +438,8 @@ spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_1);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -974,7 +971,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();
|
||||
}
|
||||
|
@ -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;
|
||||
@ -335,6 +383,7 @@ 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.
|
||||
|
||||
@ -344,6 +393,7 @@ void uartFlush(uart_t* uart)
|
||||
}
|
||||
|
||||
xQueueReset(uart->queue);
|
||||
}
|
||||
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
@ -370,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);
|
||||
|
@ -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,12 +63,15 @@ 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();
|
||||
|
||||
|
@ -17,6 +17,7 @@ void loopTask(void *pvParameters)
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
loop();
|
||||
if (serialEventRun) serialEventRun();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,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)
|
||||
|
@ -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)
|
||||
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)
|
||||
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://espressif.github.io/arduino-esp32/package_esp32_dev_index.json`
|
||||
|
@ -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
|
||||
```
|
||||
|
@ -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.
|
@ -25,6 +25,7 @@ const char* loginIndex =
|
||||
"<br>"
|
||||
"<br>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td>Username:</td>"
|
||||
"<td><input type='text' size=25 name='userid'><br></td>"
|
||||
"</tr>"
|
||||
|
@ -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;
|
||||
@ -235,7 +246,8 @@ void ArduinoOTAClass::_onRx(){
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::_runUpdate() {
|
||||
if (!Update.begin(_size, _cmd)) {
|
||||
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());
|
||||
|
||||
|
@ -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;
|
||||
|
@ -150,7 +150,7 @@ static bool _udp_task_start(){
|
||||
}
|
||||
}
|
||||
if(!_udp_task_handle){
|
||||
xTaskCreateUniversal(_udp_task, "async_udp", 4096, NULL, 3, (TaskHandle_t*)&_udp_task_handle, CONFIG_ARDUINO_UDP_RUNNING_CORE);
|
||||
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;
|
||||
}
|
||||
|
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
|
@ -154,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);
|
||||
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,8 @@ BLEAdvertisedDevice::BLEAdvertisedDevice() {
|
||||
m_manufacturerData = "";
|
||||
m_name = "";
|
||||
m_rssi = -9999;
|
||||
m_serviceData = "";
|
||||
m_serviceData = {};
|
||||
m_serviceDataUUIDs = {};
|
||||
m_txPower = 0;
|
||||
m_pScan = nullptr;
|
||||
|
||||
@ -101,33 +102,66 @@ BLEScan* BLEAdvertisedDevice::getScan() {
|
||||
return m_pScan;
|
||||
} // getScan
|
||||
|
||||
/**
|
||||
* @brief Get the number of service data.
|
||||
* @return Number of service data discovered.
|
||||
*/
|
||||
int BLEAdvertisedDevice::getServiceDataCount() {
|
||||
if (m_haveServiceData)
|
||||
return m_serviceData.size();
|
||||
else
|
||||
return 0;
|
||||
|
||||
} //getServiceDataCount
|
||||
|
||||
/**
|
||||
* @brief Get the service data.
|
||||
* @return The ServiceData of the advertised device.
|
||||
*/
|
||||
std::string BLEAdvertisedDevice::getServiceData() {
|
||||
return m_serviceData;
|
||||
return m_serviceData[0];
|
||||
} //getServiceData
|
||||
|
||||
/**
|
||||
* @brief Get the service data.
|
||||
* @return The ServiceData of the advertised device.
|
||||
*/
|
||||
std::string BLEAdvertisedDevice::getServiceData(int i) {
|
||||
return m_serviceData[i];
|
||||
} //getServiceData
|
||||
|
||||
/**
|
||||
* @brief Get the service data UUID.
|
||||
* @return The service data UUID.
|
||||
*/
|
||||
BLEUUID BLEAdvertisedDevice::getServiceDataUUID() {
|
||||
return m_serviceDataUUID;
|
||||
return m_serviceDataUUIDs[0];
|
||||
} // getServiceDataUUID
|
||||
|
||||
/**
|
||||
* @brief Get the service data UUID.
|
||||
* @return The service data UUID.
|
||||
*/
|
||||
BLEUUID BLEAdvertisedDevice::getServiceDataUUID(int i) {
|
||||
return m_serviceDataUUIDs[i];
|
||||
} // getServiceDataUUID
|
||||
|
||||
/**
|
||||
* @brief Get the Service UUID.
|
||||
* @return The Service UUID of the advertised device.
|
||||
*/
|
||||
BLEUUID BLEAdvertisedDevice::getServiceUUID() { //TODO Remove it eventually, is no longer useful
|
||||
BLEUUID BLEAdvertisedDevice::getServiceUUID() {
|
||||
return m_serviceUUIDs[0];
|
||||
} // getServiceUUID
|
||||
|
||||
/**
|
||||
* @brief Get the Service UUID.
|
||||
* @return The Service UUID of the advertised device.
|
||||
*/
|
||||
BLEUUID BLEAdvertisedDevice::getServiceUUID(int i) {
|
||||
return m_serviceUUIDs[i];
|
||||
} // getServiceUUID
|
||||
|
||||
/**
|
||||
* @brief Check advertised serviced for existence required UUID
|
||||
* @return Return true if service is advertised
|
||||
@ -354,6 +388,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.
|
||||
@ -454,7 +497,7 @@ void BLEAdvertisedDevice::setServiceUUID(BLEUUID serviceUUID) {
|
||||
*/
|
||||
void BLEAdvertisedDevice::setServiceData(std::string serviceData) {
|
||||
m_haveServiceData = true; // Set the flag that indicates we have service data.
|
||||
m_serviceData = serviceData; // Save the service data that we received.
|
||||
m_serviceData.push_back(serviceData); // Save the service data that we received.
|
||||
} //setServiceData
|
||||
|
||||
|
||||
@ -464,7 +507,8 @@ void BLEAdvertisedDevice::setServiceData(std::string serviceData) {
|
||||
*/
|
||||
void BLEAdvertisedDevice::setServiceDataUUID(BLEUUID uuid) {
|
||||
m_haveServiceData = true; // Set the flag that indicates we have service data.
|
||||
m_serviceDataUUID = uuid;
|
||||
m_serviceDataUUIDs.push_back(uuid);
|
||||
log_d("- addServiceDataUUID(): serviceDataUUID: %s", uuid.toString().c_str());
|
||||
} // setServiceDataUUID
|
||||
|
||||
|
||||
@ -498,7 +542,9 @@ std::string BLEAdvertisedDevice::toString() {
|
||||
free(pHex);
|
||||
}
|
||||
if (haveServiceUUID()) {
|
||||
res += ", serviceUUID: " + getServiceUUID().toString();
|
||||
for (int i=0; i < m_serviceUUIDs.size(); i++) {
|
||||
res += ", serviceUUID: " + getServiceUUID(i).toString();
|
||||
}
|
||||
}
|
||||
if (haveTXPower()) {
|
||||
char val[4];
|
||||
|
@ -36,8 +36,12 @@ public:
|
||||
int getRSSI();
|
||||
BLEScan* getScan();
|
||||
std::string getServiceData();
|
||||
std::string getServiceData(int i);
|
||||
BLEUUID getServiceDataUUID();
|
||||
BLEUUID getServiceDataUUID(int i);
|
||||
BLEUUID getServiceUUID();
|
||||
BLEUUID getServiceUUID(int i);
|
||||
int getServiceDataCount();
|
||||
int8_t getTXPower();
|
||||
uint8_t* getPayload();
|
||||
size_t getPayloadLength();
|
||||
@ -60,6 +64,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);
|
||||
@ -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;
|
||||
|
@ -28,7 +28,9 @@
|
||||
* @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;
|
||||
@ -85,6 +87,10 @@ void BLEAdvertising::setAppearance(uint16_t appearance) {
|
||||
m_advData.appearance = appearance;
|
||||
} // setAppearance
|
||||
|
||||
void BLEAdvertising::setAdvertisementType(esp_ble_adv_type_t adv_type){
|
||||
m_advParams.adv_type = adv_type;
|
||||
} // setAdvertisementType
|
||||
|
||||
void BLEAdvertising::setMinInterval(uint16_t mininterval) {
|
||||
m_advParams.adv_int_min = mininterval;
|
||||
} // setMinInterval
|
||||
@ -211,10 +217,15 @@ void BLEAdvertising::start() {
|
||||
}
|
||||
|
||||
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) {
|
||||
log_e("<< esp_ble_gap_config_adv_data (Scan response): rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
return;
|
||||
|
@ -52,6 +52,7 @@ public:
|
||||
void start();
|
||||
void stop();
|
||||
void setAppearance(uint16_t appearance);
|
||||
void setAdvertisementType(esp_ble_adv_type_t adv_type);
|
||||
void setMaxInterval(uint16_t maxinterval);
|
||||
void setMinInterval(uint16_t mininterval);
|
||||
void setAdvertisementData(BLEAdvertisementData& advertisementData);
|
||||
@ -67,6 +68,7 @@ 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?
|
||||
|
@ -219,13 +219,15 @@ 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(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,
|
||||
@ -233,6 +235,7 @@ void BLECharacteristic::handleGATTServerEvent(
|
||||
if (errRc != ESP_OK) {
|
||||
log_e("esp_ble_gatts_send_response: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
}
|
||||
}
|
||||
break;
|
||||
} // ESP_GATTS_EXEC_WRITE_EVT
|
||||
|
||||
@ -277,6 +280,7 @@ 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);
|
||||
}
|
||||
|
@ -107,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,
|
||||
|
@ -105,6 +105,7 @@ bool BLEClient::connect(BLEAddress address, esp_ble_addr_type_t type) {
|
||||
esp_err_t errRc = ::esp_ble_gattc_app_register(m_appId);
|
||||
if (errRc != ESP_OK) {
|
||||
log_e("esp_ble_gattc_app_register: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
BLEDevice::removePeerDevice(m_appId, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -122,6 +123,7 @@ bool BLEClient::connect(BLEAddress address, esp_ble_addr_type_t type) {
|
||||
);
|
||||
if (errRc != ESP_OK) {
|
||||
log_e("esp_ble_gattc_open: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
BLEDevice::removePeerDevice(m_appId, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -178,12 +180,13 @@ 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.
|
||||
m_isConnected = false;
|
||||
if (m_pClientCallbacks != nullptr) {
|
||||
if (m_isConnected && m_pClientCallbacks != nullptr) {
|
||||
m_pClientCallbacks->onDisconnect(this);
|
||||
}
|
||||
m_isConnected = false;
|
||||
esp_ble_gattc_app_unregister(m_gattc_if);
|
||||
m_semaphoreOpenEvt.give(ESP_GATT_IF_NONE);
|
||||
m_semaphoreRssiCmplEvt.give();
|
||||
@ -202,11 +205,13 @@ void BLEClient::gattClientEventHandler(
|
||||
//
|
||||
case ESP_GATTC_OPEN_EVT: {
|
||||
m_conn_id = evtParam->open.conn_id;
|
||||
if (evtParam->open.status == ESP_GATT_OK) {
|
||||
m_isConnected = true; // Flag us as connected.
|
||||
if (m_pClientCallbacks != nullptr) {
|
||||
m_pClientCallbacks->onConnect(this);
|
||||
}
|
||||
if (evtParam->open.status == ESP_GATT_OK) {
|
||||
m_isConnected = true; // Flag us as connected.
|
||||
} else {
|
||||
log_e("Failed to connect, status=%s", GeneralUtils::errorToString(evtParam->open.status));
|
||||
}
|
||||
m_semaphoreOpenEvt.give(evtParam->open.status);
|
||||
break;
|
||||
@ -227,6 +232,7 @@ void BLEClient::gattClientEventHandler(
|
||||
} // 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) {
|
||||
log_e("Config mtu failed");
|
||||
}
|
||||
@ -234,7 +240,8 @@ void BLEClient::gattClientEventHandler(
|
||||
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) {
|
||||
log_e("esp_ble_gattc_send_mtu_req: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
@ -255,6 +262,7 @@ 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){
|
||||
log_e("search service failed, error status = %x", p_data->search_cmpl.status);
|
||||
@ -285,6 +293,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,
|
||||
|
@ -441,11 +441,26 @@ 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) {
|
||||
log_v(">> 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) {
|
||||
log_e("esp_ble_tx_power_set: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
};
|
||||
@ -563,6 +578,12 @@ void BLEDevice::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) {
|
||||
|
@ -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,6 +3,11 @@
|
||||
*
|
||||
* 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)
|
||||
@ -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,41 +43,50 @@ 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::string out = "";
|
||||
uint32_t rawsec = ENDIAN_CHANGE_U32(m_eddystoneData.tmil);
|
||||
char val[6];
|
||||
char val[12];
|
||||
|
||||
out += "Version " + m_eddystoneData.version;
|
||||
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);
|
||||
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";
|
||||
|
||||
out += "Temperature ";
|
||||
snprintf(val, sizeof(val), "%d", m_eddystoneData.temp);
|
||||
snprintf(val, sizeof(val), "%.2f", ENDIAN_CHANGE_U16(m_eddystoneData.temp) / 256.0f);
|
||||
out += val;
|
||||
out += ".0 °C\n";
|
||||
out += " C\n";
|
||||
|
||||
out += "Adv. Count ";
|
||||
snprintf(val, sizeof(val), "%d", ENDIAN_CHANGE_U32(m_eddystoneData.advCount));
|
||||
out += val;
|
||||
out += "\n";
|
||||
|
||||
out += "Time in seconds ";
|
||||
snprintf(val, sizeof(val), "%d", rawsec/10);
|
||||
out += val;
|
||||
out += "\n";
|
||||
|
||||
out += "Time ";
|
||||
|
||||
snprintf(val, sizeof(val), "%04d", rawsec / 864000);
|
||||
|
@ -194,6 +194,7 @@ BLECharacteristic* BLEHIDDevice::protocolMode() {
|
||||
|
||||
void BLEHIDDevice::setBatteryLevel(uint8_t level) {
|
||||
m_batteryLevelCharacteristic->setValue(&level, 1);
|
||||
m_batteryLevelCharacteristic->notify();
|
||||
}
|
||||
/*
|
||||
* @brief Returns battery level characteristic
|
||||
|
@ -40,6 +40,7 @@ BLERemoteCharacteristic::BLERemoteCharacteristic(
|
||||
m_pRemoteService = pRemoteService;
|
||||
m_notifyCallback = nullptr;
|
||||
m_rawData = nullptr;
|
||||
m_auth = ESP_GATT_AUTH_REQ_NONE;
|
||||
|
||||
retrieveDescriptors(); // Get the descriptors for this characteristic
|
||||
log_v("<< BLERemoteCharacteristic");
|
||||
@ -236,6 +237,13 @@ void BLERemoteCharacteristic::gattClientEventHandler(esp_gattc_cb_event_t event,
|
||||
break;
|
||||
} // ESP_GATTC_WRITE_CHAR_EVT
|
||||
|
||||
case ESP_GATTC_READ_DESCR_EVT:
|
||||
case ESP_GATTC_WRITE_DESCR_EVT:
|
||||
for (auto &myPair : m_descriptorMap) {
|
||||
myPair.second->gattClientEventHandler(
|
||||
event, gattc_if, evtParam);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
@ -389,6 +397,17 @@ uint8_t BLERemoteCharacteristic::readUInt8() {
|
||||
return 0;
|
||||
} // readUInt8
|
||||
|
||||
/**
|
||||
* @brief Read a float value.
|
||||
* @return the float value.
|
||||
*/
|
||||
float BLERemoteCharacteristic::readFloat() {
|
||||
std::string value = readValue();
|
||||
if (value.length() >= 4) {
|
||||
return *(float*)(value.data());
|
||||
}
|
||||
return 0.0;
|
||||
} // readFloat
|
||||
|
||||
/**
|
||||
* @brief Read the value of the remote characteristic.
|
||||
@ -412,7 +431,7 @@ std::string BLERemoteCharacteristic::readValue() {
|
||||
m_pRemoteService->getClient()->getGattcIf(),
|
||||
m_pRemoteService->getClient()->getConnId(), // The connection ID to the BLE server
|
||||
getHandle(), // The handle of this characteristic
|
||||
ESP_GATT_AUTH_REQ_NONE); // Security
|
||||
m_auth); // Security
|
||||
|
||||
if (errRc != ESP_OK) {
|
||||
log_e("esp_ble_gattc_read_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
@ -455,7 +474,8 @@ void BLERemoteCharacteristic::registerForNotify(notify_callback notifyCallback,
|
||||
uint8_t val[] = {0x01, 0x00};
|
||||
if(!notifications) val[0] = 0x02;
|
||||
BLERemoteDescriptor* desc = getDescriptor(BLEUUID((uint16_t)0x2902));
|
||||
desc->writeValue(val, 2);
|
||||
if (desc != nullptr)
|
||||
desc->writeValue(val, 2, true);
|
||||
} // End Register
|
||||
else { // If we weren't passed a callback function, then this is an unregistration.
|
||||
esp_err_t errRc = ::esp_ble_gattc_unregister_for_notify(
|
||||
@ -470,7 +490,8 @@ void BLERemoteCharacteristic::registerForNotify(notify_callback notifyCallback,
|
||||
|
||||
uint8_t val[] = {0x00, 0x00};
|
||||
BLERemoteDescriptor* desc = getDescriptor((uint16_t)0x2902);
|
||||
desc->writeValue(val, 2);
|
||||
if (desc != nullptr)
|
||||
desc->writeValue(val, 2, true);
|
||||
} // End Unregister
|
||||
|
||||
m_semaphoreRegForNotifyEvt.wait("registerForNotify");
|
||||
@ -521,7 +542,7 @@ std::string BLERemoteCharacteristic::toString() {
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLERemoteCharacteristic::writeValue(std::string newValue, bool response) {
|
||||
writeValue((uint8_t*)newValue.c_str(), strlen(newValue.c_str()), response);
|
||||
writeValue((uint8_t*)newValue.data(), newValue.length(), response);
|
||||
} // writeValue
|
||||
|
||||
|
||||
@ -563,7 +584,7 @@ void BLERemoteCharacteristic::writeValue(uint8_t* data, size_t length, bool resp
|
||||
length,
|
||||
data,
|
||||
response?ESP_GATT_WRITE_TYPE_RSP:ESP_GATT_WRITE_TYPE_NO_RSP,
|
||||
ESP_GATT_AUTH_REQ_NONE
|
||||
m_auth
|
||||
);
|
||||
|
||||
if (errRc != ESP_OK) {
|
||||
@ -584,4 +605,12 @@ uint8_t* BLERemoteCharacteristic::readRawData() {
|
||||
return m_rawData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set authentication request type for characteristic
|
||||
* @param [in] auth Authentication request type.
|
||||
*/
|
||||
void BLERemoteCharacteristic::setAuth(esp_gatt_auth_req_t auth) {
|
||||
m_auth = auth;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
|
@ -45,12 +45,14 @@ public:
|
||||
uint8_t readUInt8();
|
||||
uint16_t readUInt16();
|
||||
uint32_t readUInt32();
|
||||
float readFloat();
|
||||
void registerForNotify(notify_callback _callback, bool notifications = true);
|
||||
void writeValue(uint8_t* data, size_t length, bool response = false);
|
||||
void writeValue(std::string newValue, bool response = false);
|
||||
void writeValue(uint8_t newValue, bool response = false);
|
||||
std::string toString();
|
||||
uint8_t* readRawData();
|
||||
void setAuth(esp_gatt_auth_req_t auth);
|
||||
|
||||
private:
|
||||
BLERemoteCharacteristic(uint16_t handle, BLEUUID uuid, esp_gatt_char_prop_t charProp, BLERemoteService* pRemoteService);
|
||||
@ -68,6 +70,7 @@ private:
|
||||
// Private properties
|
||||
BLEUUID m_uuid;
|
||||
esp_gatt_char_prop_t m_charProp;
|
||||
esp_gatt_auth_req_t m_auth;
|
||||
uint16_t m_handle;
|
||||
BLERemoteService* m_pRemoteService;
|
||||
FreeRTOS::Semaphore m_semaphoreReadCharEvt = FreeRTOS::Semaphore("ReadCharEvt");
|
||||
|
@ -19,6 +19,7 @@ BLERemoteDescriptor::BLERemoteDescriptor(
|
||||
m_handle = handle;
|
||||
m_uuid = uuid;
|
||||
m_pRemoteCharacteristic = pRemoteCharacteristic;
|
||||
m_auth = ESP_GATT_AUTH_REQ_NONE;
|
||||
}
|
||||
|
||||
|
||||
@ -48,6 +49,23 @@ BLEUUID BLERemoteDescriptor::getUUID() {
|
||||
return m_uuid;
|
||||
} // getUUID
|
||||
|
||||
void BLERemoteDescriptor::gattClientEventHandler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t* evtParam) {
|
||||
switch(event) {
|
||||
case ESP_GATTC_READ_DESCR_EVT:
|
||||
if (evtParam->read.handle != getHandle())
|
||||
break;
|
||||
m_semaphoreReadDescrEvt.give();
|
||||
break;
|
||||
|
||||
case ESP_GATTC_WRITE_DESCR_EVT:
|
||||
if (evtParam->write.handle != getHandle())
|
||||
break;
|
||||
m_semaphoreWriteDescrEvt.give();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::string BLERemoteDescriptor::readValue() {
|
||||
log_v(">> readValue: %s", toString().c_str());
|
||||
@ -65,7 +83,7 @@ std::string BLERemoteDescriptor::readValue() {
|
||||
m_pRemoteCharacteristic->getRemoteService()->getClient()->getGattcIf(),
|
||||
m_pRemoteCharacteristic->getRemoteService()->getClient()->getConnId(), // The connection ID to the BLE server
|
||||
getHandle(), // The handle of this characteristic
|
||||
ESP_GATT_AUTH_REQ_NONE); // Security
|
||||
m_auth); // Security
|
||||
|
||||
if (errRc != ESP_OK) {
|
||||
log_e("esp_ble_gattc_read_char: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
@ -136,6 +154,8 @@ void BLERemoteDescriptor::writeValue(uint8_t* data, size_t length, bool response
|
||||
return;
|
||||
}
|
||||
|
||||
m_semaphoreWriteDescrEvt.take("writeValue");
|
||||
|
||||
esp_err_t errRc = ::esp_ble_gattc_write_char_descr(
|
||||
m_pRemoteCharacteristic->getRemoteService()->getClient()->getGattcIf(),
|
||||
m_pRemoteCharacteristic->getRemoteService()->getClient()->getConnId(),
|
||||
@ -143,11 +163,13 @@ void BLERemoteDescriptor::writeValue(uint8_t* data, size_t length, bool response
|
||||
length, // Data length
|
||||
data, // Data
|
||||
response ? ESP_GATT_WRITE_TYPE_RSP : ESP_GATT_WRITE_TYPE_NO_RSP,
|
||||
ESP_GATT_AUTH_REQ_NONE
|
||||
m_auth
|
||||
);
|
||||
if (errRc != ESP_OK) {
|
||||
log_e("esp_ble_gattc_write_char_descr: %d", errRc);
|
||||
}
|
||||
|
||||
m_semaphoreWriteDescrEvt.wait("writeValue");
|
||||
log_v("<< writeValue");
|
||||
} // writeValue
|
||||
|
||||
@ -171,5 +193,12 @@ void BLERemoteDescriptor::writeValue(uint8_t newValue, bool response) {
|
||||
writeValue(&newValue, 1, response);
|
||||
} // writeValue
|
||||
|
||||
/**
|
||||
* @brief Set authentication request type for characteristic
|
||||
* @param [in] auth Authentication request type.
|
||||
*/
|
||||
void BLERemoteDescriptor::setAuth(esp_gatt_auth_req_t auth) {
|
||||
m_auth = auth;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_ENABLED */
|
||||
|
@ -34,7 +34,8 @@ public:
|
||||
void writeValue(uint8_t* data, size_t length, bool response = false);
|
||||
void writeValue(std::string newValue, bool response = false);
|
||||
void writeValue(uint8_t newValue, bool response = false);
|
||||
|
||||
void setAuth(esp_gatt_auth_req_t auth);
|
||||
void gattClientEventHandler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t* evtParam);
|
||||
|
||||
private:
|
||||
friend class BLERemoteCharacteristic;
|
||||
@ -48,6 +49,8 @@ private:
|
||||
std::string m_value; // Last received value of the descriptor.
|
||||
BLERemoteCharacteristic* m_pRemoteCharacteristic; // Reference to the Remote characteristic of which this descriptor is associated.
|
||||
FreeRTOS::Semaphore m_semaphoreReadDescrEvt = FreeRTOS::Semaphore("ReadDescrEvt");
|
||||
FreeRTOS::Semaphore m_semaphoreWriteDescrEvt = FreeRTOS::Semaphore("WriteDescrEvt");
|
||||
esp_gatt_auth_req_t m_auth;
|
||||
|
||||
|
||||
};
|
||||
|
@ -244,7 +244,15 @@ std::map<uint16_t, BLERemoteCharacteristic*>* BLERemoteService::getCharacteristi
|
||||
* @brief This function is designed to get characteristics map when we have multiple characteristics with the same UUID
|
||||
*/
|
||||
void BLERemoteService::getCharacteristics(std::map<uint16_t, BLERemoteCharacteristic*>* pCharacteristicMap) {
|
||||
pCharacteristicMap = &m_characteristicMapByHandle;
|
||||
log_v(">> getCharacteristics() for service: %s", getUUID().toString().c_str());
|
||||
// If is possible that we have not read the characteristics associated with the service so do that
|
||||
// now. The request to retrieve the characteristics by calling "retrieveCharacteristics" is a blocking
|
||||
// call and does not return until all the characteristics are available.
|
||||
if (!m_haveCharacteristics) {
|
||||
retrieveCharacteristics();
|
||||
}
|
||||
log_v("<< getCharacteristics() for service: %s", getUUID().toString().c_str());
|
||||
*pCharacteristicMap = m_characteristicMapByHandle;
|
||||
} // Get the characteristics map.
|
||||
|
||||
/**
|
||||
@ -302,13 +310,10 @@ std::string BLERemoteService::getValue(BLEUUID characteristicUuid) {
|
||||
* @return N/A.
|
||||
*/
|
||||
void BLERemoteService::removeCharacteristics() {
|
||||
for (auto &myPair : m_characteristicMap) {
|
||||
delete myPair.second;
|
||||
//m_characteristicMap.erase(myPair.first); // Should be no need to delete as it will be deleted by the clear
|
||||
}
|
||||
m_characteristicMap.clear(); // Clear the map
|
||||
for (auto &myPair : m_characteristicMapByHandle) {
|
||||
delete myPair.second;
|
||||
// delete the characteristics only once
|
||||
}
|
||||
m_characteristicMapByHandle.clear(); // Clear the map
|
||||
} // removeCharacteristics
|
||||
|
@ -22,12 +22,15 @@
|
||||
* Constructor
|
||||
*/
|
||||
BLEScan::BLEScan() {
|
||||
memset(&m_scan_params, 0, sizeof(m_scan_params)); // Initialize all params
|
||||
m_scan_params.scan_type = BLE_SCAN_TYPE_PASSIVE; // Default is a passive scan.
|
||||
m_scan_params.own_addr_type = BLE_ADDR_TYPE_PUBLIC;
|
||||
m_scan_params.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL;
|
||||
m_scan_params.scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE;
|
||||
m_pAdvertisedDeviceCallbacks = nullptr;
|
||||
m_stopped = true;
|
||||
m_wantDuplicates = false;
|
||||
m_shouldParse = true;
|
||||
setInterval(100);
|
||||
setWindow(100);
|
||||
} // BLEScan
|
||||
@ -88,16 +91,19 @@ void BLEScan::handleGAPEvent(
|
||||
// ignore it.
|
||||
BLEAddress advertisedAddress(param->scan_rst.bda);
|
||||
bool found = false;
|
||||
bool shouldDelete = true;
|
||||
|
||||
if (!m_wantDuplicates) {
|
||||
if (m_scanResults.m_vectorAdvertisedDevices.count(advertisedAddress.toString()) != 0) {
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (found && !m_wantDuplicates) { // If we found a previous entry AND we don't want duplicates, then we are done.
|
||||
if (found) { // If we found a previous entry AND we don't want duplicates, then we are done.
|
||||
log_d("Ignoring %s, already seen it.", advertisedAddress.toString().c_str());
|
||||
vTaskDelay(1); // <--- allow to switch task in case we scan infinity and dont have new devices to report, or we are blocked here
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We now construct a model of the advertised device that we have just found for the first
|
||||
// time.
|
||||
@ -107,19 +113,23 @@ void BLEScan::handleGAPEvent(
|
||||
advertisedDevice->setAddress(advertisedAddress);
|
||||
advertisedDevice->setRSSI(param->scan_rst.rssi);
|
||||
advertisedDevice->setAdFlag(param->scan_rst.flag);
|
||||
if (m_shouldParse) {
|
||||
advertisedDevice->parseAdvertisement((uint8_t*)param->scan_rst.ble_adv, param->scan_rst.adv_data_len + param->scan_rst.scan_rsp_len);
|
||||
} else {
|
||||
advertisedDevice->setPayload((uint8_t*)param->scan_rst.ble_adv, param->scan_rst.adv_data_len + param->scan_rst.scan_rsp_len);
|
||||
}
|
||||
advertisedDevice->setScan(this);
|
||||
advertisedDevice->setAddressType(param->scan_rst.ble_addr_type);
|
||||
|
||||
if (!found) { // If we have previously seen this device, don't record it again.
|
||||
m_scanResults.m_vectorAdvertisedDevices.insert(std::pair<std::string, BLEAdvertisedDevice*>(advertisedAddress.toString(), advertisedDevice));
|
||||
}
|
||||
|
||||
if (m_pAdvertisedDeviceCallbacks) {
|
||||
if (m_pAdvertisedDeviceCallbacks) { // if has callback, no need to record to vector
|
||||
m_pAdvertisedDeviceCallbacks->onResult(*advertisedDevice);
|
||||
} else if (!m_wantDuplicates && !found) { // if no callback and not want duplicate, and not already in vector, record it
|
||||
m_scanResults.m_vectorAdvertisedDevices.insert(std::pair<std::string, BLEAdvertisedDevice*>(advertisedAddress.toString(), advertisedDevice));
|
||||
shouldDelete = false;
|
||||
}
|
||||
if(found)
|
||||
if (shouldDelete) {
|
||||
delete advertisedDevice;
|
||||
}
|
||||
|
||||
break;
|
||||
} // ESP_GAP_SEARCH_INQ_RES_EVT
|
||||
@ -159,13 +169,14 @@ void BLEScan::setActiveScan(bool active) {
|
||||
* @brief Set the call backs to be invoked.
|
||||
* @param [in] pAdvertisedDeviceCallbacks Call backs to be invoked.
|
||||
* @param [in] wantDuplicates True if we wish to be called back with duplicates. Default is false.
|
||||
* @param [in] shouldParse True if we wish to parse advertised package or raw payload. Default is true.
|
||||
*/
|
||||
void BLEScan::setAdvertisedDeviceCallbacks(BLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks, bool wantDuplicates) {
|
||||
void BLEScan::setAdvertisedDeviceCallbacks(BLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks, bool wantDuplicates, bool shouldParse) {
|
||||
m_wantDuplicates = wantDuplicates;
|
||||
m_pAdvertisedDeviceCallbacks = pAdvertisedDeviceCallbacks;
|
||||
m_shouldParse = shouldParse;
|
||||
} // setAdvertisedDeviceCallbacks
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set the interval to scan.
|
||||
* @param [in] The interval in msecs.
|
||||
|
@ -51,7 +51,8 @@ public:
|
||||
void setActiveScan(bool active);
|
||||
void setAdvertisedDeviceCallbacks(
|
||||
BLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks,
|
||||
bool wantDuplicates = false);
|
||||
bool wantDuplicates = false,
|
||||
bool shouldParse = true);
|
||||
void setInterval(uint16_t intervalMSecs);
|
||||
void setWindow(uint16_t windowMSecs);
|
||||
bool start(uint32_t duration, void (*scanCompleteCB)(BLEScanResults), bool is_continue = false);
|
||||
@ -73,6 +74,7 @@ private:
|
||||
esp_ble_scan_params_t m_scan_params;
|
||||
BLEAdvertisedDeviceCallbacks* m_pAdvertisedDeviceCallbacks = nullptr;
|
||||
bool m_stopped = true;
|
||||
bool m_shouldParse = true;
|
||||
FreeRTOS::Semaphore m_semaphoreScanEnd = FreeRTOS::Semaphore("ScanEnd");
|
||||
BLEScanResults m_scanResults;
|
||||
bool m_wantDuplicates;
|
||||
|
@ -61,6 +61,17 @@ void BLESecurity::setKeySize(uint8_t key_size) {
|
||||
esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &m_keySize, sizeof(uint8_t));
|
||||
} //setKeySize
|
||||
|
||||
/**
|
||||
* Setup for static PIN connection, call it first and then call setAuthenticationMode eventually to change it
|
||||
*/
|
||||
void BLESecurity::setStaticPIN(uint32_t pin){
|
||||
uint32_t passkey = pin;
|
||||
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t));
|
||||
setCapability(ESP_IO_CAP_OUT);
|
||||
setKeySize();
|
||||
setAuthenticationMode(ESP_LE_AUTH_REQ_SC_ONLY);
|
||||
setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Debug function to display what keys are exchanged by peers
|
||||
|
@ -21,6 +21,7 @@ public:
|
||||
void setInitEncryptionKey(uint8_t init_key);
|
||||
void setRespEncryptionKey(uint8_t resp_key);
|
||||
void setKeySize(uint8_t key_size = 16);
|
||||
void setStaticPIN(uint32_t pin);
|
||||
static char* esp_key_type_to_str(esp_ble_key_type_t key_type);
|
||||
|
||||
private:
|
||||
|
@ -202,12 +202,18 @@ void BLEServer::handleGATTServerEvent(esp_gatts_cb_event_t event, esp_gatt_if_t
|
||||
// If we receive a disconnect event then invoke the callback for disconnects (if one is present).
|
||||
// we also want to start advertising again.
|
||||
case ESP_GATTS_DISCONNECT_EVT: {
|
||||
m_connectedCount--; // Decrement the number of connected devices count.
|
||||
if (m_pServerCallbacks != nullptr) { // If we have callbacks, call now.
|
||||
m_pServerCallbacks->onDisconnect(this);
|
||||
}
|
||||
startAdvertising(); //- do this with some delay from the loop()
|
||||
removePeerDevice(param->disconnect.conn_id, false);
|
||||
if(m_connId == ESP_GATT_IF_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// only decrement if connection is found in map and removed
|
||||
// sometimes this event triggers w/o a valid connection
|
||||
if(removePeerDevice(param->disconnect.conn_id, false)) {
|
||||
m_connectedCount--; // Decrement the number of connected devices count.
|
||||
}
|
||||
break;
|
||||
} // ESP_GATTS_DISCONNECT_EVT
|
||||
|
||||
@ -395,8 +401,8 @@ void BLEServer::addPeerDevice(void* peer, bool _client, uint16_t conn_id) {
|
||||
m_connectedServersMap.insert(std::pair<uint16_t, conn_status_t>(conn_id, status));
|
||||
}
|
||||
|
||||
void BLEServer::removePeerDevice(uint16_t conn_id, bool _client) {
|
||||
m_connectedServersMap.erase(conn_id);
|
||||
bool BLEServer::removePeerDevice(uint16_t conn_id, bool _client) {
|
||||
return m_connectedServersMap.erase(conn_id) > 0;
|
||||
}
|
||||
/* multi connect support */
|
||||
|
||||
|
@ -79,7 +79,7 @@ public:
|
||||
/* multi connection support */
|
||||
std::map<uint16_t, conn_status_t> getPeerDevices(bool client);
|
||||
void addPeerDevice(void* peer, bool is_client, uint16_t conn_id);
|
||||
void removePeerDevice(uint16_t conn_id, bool client);
|
||||
bool removePeerDevice(uint16_t conn_id, bool client);
|
||||
BLEServer* getServerByConnId(uint16_t conn_id);
|
||||
void updatePeerMTU(uint16_t connId, uint16_t mtu);
|
||||
uint16_t getPeerMTU(uint16_t conn_id);
|
||||
|
@ -186,16 +186,16 @@ void FreeRTOS::Semaphore::giveFromISR() {
|
||||
* @return True if we took the semaphore.
|
||||
*/
|
||||
bool FreeRTOS::Semaphore::take(std::string owner) {
|
||||
log_d("Semaphore taking: %s for %s", toString().c_str(), owner.c_str());
|
||||
log_v("Semaphore taking: %s for %s", toString().c_str(), owner.c_str());
|
||||
bool rc = false;
|
||||
if (m_usePthreads) {
|
||||
pthread_mutex_lock(&m_pthread_mutex);
|
||||
} else {
|
||||
rc = ::xSemaphoreTake(m_semaphore, portMAX_DELAY) == pdTRUE;
|
||||
}
|
||||
m_owner = owner;
|
||||
if (rc) {
|
||||
log_d("Semaphore taken: %s", toString().c_str());
|
||||
m_owner = owner;
|
||||
log_v("Semaphore taken: %s", toString().c_str());
|
||||
} else {
|
||||
log_e("Semaphore NOT taken: %s", toString().c_str());
|
||||
}
|
||||
@ -218,8 +218,8 @@ bool FreeRTOS::Semaphore::take(uint32_t timeoutMs, std::string owner) {
|
||||
} else {
|
||||
rc = ::xSemaphoreTake(m_semaphore, timeoutMs / portTICK_PERIOD_MS) == pdTRUE;
|
||||
}
|
||||
m_owner = owner;
|
||||
if (rc) {
|
||||
m_owner = owner;
|
||||
log_v("Semaphore taken: %s", toString().c_str());
|
||||
} else {
|
||||
log_e("Semaphore NOT taken: %s", toString().c_str());
|
||||
|
@ -36,9 +36,7 @@
|
||||
#include "esp_spp_api.h"
|
||||
#include <esp_log.h>
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "esp32-hal-log.h"
|
||||
#endif
|
||||
|
||||
const char * _spp_server_name = "ESP32SPP";
|
||||
|
||||
@ -52,6 +50,7 @@ static TaskHandle_t _spp_task_handle = NULL;
|
||||
static EventGroupHandle_t _spp_event_group = NULL;
|
||||
static boolean secondConnectionAttempt;
|
||||
static esp_spp_cb_t * custom_spp_callback = NULL;
|
||||
static BluetoothSerialDataCb custom_data_callback = NULL;
|
||||
|
||||
#define INQ_LEN 0x10
|
||||
#define INQ_NUM_RSPS 20
|
||||
@ -76,6 +75,7 @@ typedef struct {
|
||||
uint8_t data[];
|
||||
} spp_packet_t;
|
||||
|
||||
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)
|
||||
static char *bda2str(esp_bd_addr_t bda, char *str, size_t size)
|
||||
{
|
||||
if (bda == NULL || str == NULL || size < 18) {
|
||||
@ -87,6 +87,7 @@ static char *bda2str(esp_bd_addr_t bda, char *str, size_t size)
|
||||
p[0], p[1], p[2], p[3], p[4], p[5]);
|
||||
return str;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool get_name_from_eir(uint8_t *eir, char *bdname, uint8_t *bdname_len)
|
||||
{
|
||||
@ -152,7 +153,7 @@ static uint8_t _spp_tx_buffer[SPP_TX_MAX];
|
||||
static uint16_t _spp_tx_buffer_len = 0;
|
||||
|
||||
static bool _spp_send_buffer(){
|
||||
if((xEventGroupWaitBits(_spp_event_group, SPP_CONGESTED, pdFALSE, pdTRUE, portMAX_DELAY) & SPP_CONGESTED)){
|
||||
if((xEventGroupWaitBits(_spp_event_group, SPP_CONGESTED, pdFALSE, pdTRUE, portMAX_DELAY) & SPP_CONGESTED) != 0){
|
||||
esp_err_t err = esp_spp_write(_spp_client, _spp_tx_buffer_len, _spp_tx_buffer);
|
||||
if(err != ESP_OK){
|
||||
log_e("SPP Write Failed! [0x%X]", err);
|
||||
@ -216,7 +217,6 @@ static void _spp_tx_task(void * arg){
|
||||
_spp_task_handle = NULL;
|
||||
}
|
||||
|
||||
|
||||
static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
|
||||
{
|
||||
switch (event)
|
||||
@ -276,7 +276,9 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
|
||||
//esp_log_buffer_hex("",param->data_ind.data,param->data_ind.len); //for low level debug
|
||||
//ets_printf("r:%u\n", param->data_ind.len);
|
||||
|
||||
if (_spp_rx_queue != NULL){
|
||||
if(custom_data_callback){
|
||||
custom_data_callback(param->data_ind.data, param->data_ind.len);
|
||||
} else if (_spp_rx_queue != NULL){
|
||||
for (int i = 0; i < param->data_ind.len; i++){
|
||||
if(xQueueSend(_spp_rx_queue, param->data_ind.data + i, (TickType_t)0) != pdTRUE){
|
||||
log_e("RX Full! Discarding %u bytes", param->data_ind.len - i);
|
||||
@ -320,13 +322,19 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
|
||||
if(custom_spp_callback)(*custom_spp_callback)(event, param);
|
||||
}
|
||||
|
||||
void BluetoothSerial::onData(BluetoothSerialDataCb cb){
|
||||
custom_data_callback = cb;
|
||||
}
|
||||
|
||||
static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
|
||||
{
|
||||
switch(event){
|
||||
case ESP_BT_GAP_DISC_RES_EVT:
|
||||
log_i("ESP_BT_GAP_DISC_RES_EVT");
|
||||
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)
|
||||
char bda_str[18];
|
||||
log_i("Scanned device: %s", bda2str(param->disc_res.bda, bda_str, 18));
|
||||
#endif
|
||||
for (int i = 0; i < param->disc_res.num_prop; i++) {
|
||||
uint8_t peer_bdname_len;
|
||||
char peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
|
||||
@ -361,11 +369,11 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_DEV_PROP_COD:
|
||||
//log_i("ESP_BT_GAP_DEV_PROP_COD");
|
||||
log_d("ESP_BT_GAP_DEV_PROP_COD");
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_DEV_PROP_RSSI:
|
||||
//log_i("ESP_BT_GAP_DEV_PROP_RSSI");
|
||||
log_d("ESP_BT_GAP_DEV_PROP_RSSI");
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -465,7 +473,7 @@ static bool _init_bt(const char *deviceName)
|
||||
}
|
||||
|
||||
if(!_spp_task_handle){
|
||||
xTaskCreate(_spp_tx_task, "spp_tx", 4096, NULL, 2, &_spp_task_handle);
|
||||
xTaskCreatePinnedToCore(_spp_tx_task, "spp_tx", 4096, NULL, 2, &_spp_task_handle, 0);
|
||||
if(!_spp_task_handle){
|
||||
log_e("Network Event Task Start Failed!");
|
||||
return false;
|
||||
@ -507,6 +515,10 @@ static bool _init_bt(const char *deviceName)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (esp_bt_sleep_disable() != ESP_OK){
|
||||
log_e("esp_bt_sleep_disable failed");
|
||||
}
|
||||
|
||||
log_i("device name set");
|
||||
esp_bt_dev_set_device_name(deviceName);
|
||||
|
||||
@ -574,7 +586,7 @@ static bool _stop_bt()
|
||||
|
||||
static bool waitForConnect(int timeout) {
|
||||
TickType_t xTicksToWait = timeout / portTICK_PERIOD_MS;
|
||||
return (xEventGroupWaitBits(_spp_event_group, SPP_CONNECTED, pdFALSE, pdTRUE, xTicksToWait) != 0);
|
||||
return (xEventGroupWaitBits(_spp_event_group, SPP_CONNECTED, pdFALSE, pdTRUE, xTicksToWait) & SPP_CONNECTED) != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -648,7 +660,11 @@ size_t BluetoothSerial::write(const uint8_t *buffer, size_t size)
|
||||
|
||||
void BluetoothSerial::flush()
|
||||
{
|
||||
while(read() >= 0){}
|
||||
if (_spp_tx_queue != NULL){
|
||||
while(uxQueueMessagesWaiting(_spp_tx_queue) > 0){
|
||||
delay(5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BluetoothSerial::end()
|
||||
@ -757,7 +773,7 @@ bool BluetoothSerial::disconnect() {
|
||||
log_i("disconnecting");
|
||||
if (esp_spp_disconnect(_spp_client) == ESP_OK) {
|
||||
TickType_t xTicksToWait = READY_TIMEOUT / portTICK_PERIOD_MS;
|
||||
return (xEventGroupWaitBits(_spp_event_group, SPP_DISCONNECTED, pdFALSE, pdTRUE, xTicksToWait) != 0);
|
||||
return (xEventGroupWaitBits(_spp_event_group, SPP_DISCONNECTED, pdFALSE, pdTRUE, xTicksToWait) & SPP_DISCONNECTED) != 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@ -785,6 +801,6 @@ bool BluetoothSerial::isReady(bool checkMaster, int timeout) {
|
||||
return false;
|
||||
}
|
||||
TickType_t xTicksToWait = timeout / portTICK_PERIOD_MS;
|
||||
return (xEventGroupWaitBits(_spp_event_group, SPP_RUNNING, pdFALSE, pdTRUE, xTicksToWait) != 0);
|
||||
return (xEventGroupWaitBits(_spp_event_group, SPP_RUNNING, pdFALSE, pdTRUE, xTicksToWait) & SPP_RUNNING) != 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -22,6 +22,9 @@
|
||||
#include "Arduino.h"
|
||||
#include "Stream.h"
|
||||
#include <esp_spp_api.h>
|
||||
#include <functional>
|
||||
|
||||
typedef std::function<void(const uint8_t *buffer, size_t size)> BluetoothSerialDataCb;
|
||||
|
||||
class BluetoothSerial: public Stream
|
||||
{
|
||||
@ -39,6 +42,7 @@ class BluetoothSerial: public Stream
|
||||
size_t write(const uint8_t *buffer, size_t size);
|
||||
void flush();
|
||||
void end(void);
|
||||
void onData(BluetoothSerialDataCb cb);
|
||||
esp_err_t register_callback(esp_spp_cb_t * callback);
|
||||
|
||||
void enableSSP();
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include <DNSServer.h>
|
||||
|
||||
const byte DNS_PORT = 53;
|
||||
IPAddress apIP(192, 168, 1, 1);
|
||||
IPAddress apIP(8,8,4,4); // The default android DNS
|
||||
DNSServer dnsServer;
|
||||
WiFiServer server(80);
|
||||
|
||||
@ -13,8 +13,8 @@ String responseHTML = ""
|
||||
|
||||
void setup() {
|
||||
WiFi.mode(WIFI_AP);
|
||||
WiFi.softAP("ESP32-DNSServer");
|
||||
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
|
||||
WiFi.softAP("DNSServer CaptivePortal example");
|
||||
|
||||
// if DNSServer is started with "*" for domain name, it will reply with
|
||||
// provided IP to all DNS request
|
||||
|
@ -2,6 +2,12 @@
|
||||
#include <lwip/def.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
// #define DEBUG_ESP_DNS
|
||||
#ifdef DEBUG_ESP_PORT
|
||||
#define DEBUG_OUTPUT DEBUG_ESP_PORT
|
||||
#else
|
||||
#define DEBUG_OUTPUT Serial
|
||||
#endif
|
||||
|
||||
DNSServer::DNSServer()
|
||||
{
|
||||
@ -184,6 +190,11 @@ void DNSServer::replyWithIP()
|
||||
_udp.write((unsigned char*) &answerIPv4, 2 );
|
||||
_udp.write(_resolvedIP, sizeof(_resolvedIP)); // The IP address to return
|
||||
_udp.endPacket();
|
||||
|
||||
#ifdef DEBUG_ESP_DNS
|
||||
DEBUG_OUTPUT.printf("DNS responds: %s for %s\n",
|
||||
IPAddress(_resolvedIP).toString().c_str(), getDomainNameWithoutWwwPrefix().c_str() );
|
||||
#endif
|
||||
}
|
||||
|
||||
void DNSServer::replyWithCustomCode()
|
||||
|
@ -17,6 +17,7 @@ EEPROMClass AGE("eeprom2", 0x100);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(1000);
|
||||
Serial.println("Testing EEPROMClass\n");
|
||||
if (!NAMES.begin(NAMES.length())) {
|
||||
Serial.println("Failed to initialise NAMES");
|
||||
@ -43,7 +44,7 @@ void setup() {
|
||||
uint32_t age = 47;
|
||||
|
||||
// Write: Variables ---> EEPROM stores
|
||||
NAMES.put(0, name);
|
||||
NAMES.writeString(0, name);
|
||||
HEIGHT.put(0, height);
|
||||
AGE.put(0, age);
|
||||
Serial.print("name: "); Serial.println(name);
|
||||
|
@ -2,16 +2,20 @@
|
||||
#include <WiFi.h>
|
||||
|
||||
//
|
||||
// WARNING!!! Make sure that you have either selected ESP32 Wrover Module,
|
||||
// or another board which has PSRAM enabled
|
||||
// WARNING!!! PSRAM IC required for UXGA resolution and high JPEG quality
|
||||
// Ensure ESP32 Wrover Module or other board with PSRAM is selected
|
||||
// Partial images will be transmitted if image exceeds buffer size
|
||||
//
|
||||
|
||||
// Select camera model
|
||||
#define CAMERA_MODEL_WROVER_KIT
|
||||
//#define CAMERA_MODEL_ESP_EYE
|
||||
//#define CAMERA_MODEL_M5STACK_PSRAM
|
||||
//#define CAMERA_MODEL_M5STACK_WIDE
|
||||
//#define CAMERA_MODEL_AI_THINKER
|
||||
#define CAMERA_MODEL_WROVER_KIT // Has PSRAM
|
||||
//#define CAMERA_MODEL_ESP_EYE // Has PSRAM
|
||||
//#define CAMERA_MODEL_M5STACK_PSRAM // Has PSRAM
|
||||
//#define CAMERA_MODEL_M5STACK_V2_PSRAM // M5Camera version B Has PSRAM
|
||||
//#define CAMERA_MODEL_M5STACK_WIDE // Has PSRAM
|
||||
//#define CAMERA_MODEL_M5STACK_ESP32CAM // No PSRAM
|
||||
//#define CAMERA_MODEL_AI_THINKER // Has PSRAM
|
||||
//#define CAMERA_MODEL_TTGO_T_JOURNAL // No PSRAM
|
||||
|
||||
#include "camera_pins.h"
|
||||
|
||||
@ -46,7 +50,9 @@ void setup() {
|
||||
config.pin_reset = RESET_GPIO_NUM;
|
||||
config.xclk_freq_hz = 20000000;
|
||||
config.pixel_format = PIXFORMAT_JPEG;
|
||||
//init with high specs to pre-allocate larger buffers
|
||||
|
||||
// if PSRAM IC present, init with UXGA resolution and higher JPEG quality
|
||||
// for larger pre-allocated frame buffer.
|
||||
if(psramFound()){
|
||||
config.frame_size = FRAMESIZE_UXGA;
|
||||
config.jpeg_quality = 10;
|
||||
@ -70,16 +76,16 @@ void setup() {
|
||||
}
|
||||
|
||||
sensor_t * s = esp_camera_sensor_get();
|
||||
//initial sensors are flipped vertically and colors are a bit saturated
|
||||
// initial sensors are flipped vertically and colors are a bit saturated
|
||||
if (s->id.PID == OV3660_PID) {
|
||||
s->set_vflip(s, 1);//flip it back
|
||||
s->set_brightness(s, 1);//up the blightness just a bit
|
||||
s->set_saturation(s, -2);//lower the saturation
|
||||
s->set_vflip(s, 1); // flip it back
|
||||
s->set_brightness(s, 1); // up the brightness just a bit
|
||||
s->set_saturation(s, -2); // lower the saturation
|
||||
}
|
||||
//drop down frame size for higher initial frame rate
|
||||
// drop down frame size for higher initial frame rate
|
||||
s->set_framesize(s, FRAMESIZE_QVGA);
|
||||
|
||||
#if defined(CAMERA_MODEL_M5STACK_WIDE)
|
||||
#if defined(CAMERA_MODEL_M5STACK_WIDE) || defined(CAMERA_MODEL_M5STACK_ESP32CAM)
|
||||
s->set_vflip(s, 1);
|
||||
s->set_hmirror(s, 1);
|
||||
#endif
|
||||
|
@ -403,6 +403,9 @@ static esp_err_t stream_handler(httpd_req_t *req){
|
||||
}
|
||||
}
|
||||
}
|
||||
if(res == ESP_OK){
|
||||
res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
|
||||
}
|
||||
if(res == ESP_OK){
|
||||
size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
|
||||
res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
|
||||
@ -410,9 +413,6 @@ static esp_err_t stream_handler(httpd_req_t *req){
|
||||
if(res == ESP_OK){
|
||||
res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
|
||||
}
|
||||
if(res == ESP_OK){
|
||||
res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
|
||||
}
|
||||
if(fb){
|
||||
esp_camera_fb_return(fb);
|
||||
fb = NULL;
|
||||
|
@ -56,6 +56,25 @@
|
||||
#define HREF_GPIO_NUM 26
|
||||
#define PCLK_GPIO_NUM 21
|
||||
|
||||
#elif defined(CAMERA_MODEL_M5STACK_V2_PSRAM)
|
||||
#define PWDN_GPIO_NUM -1
|
||||
#define RESET_GPIO_NUM 15
|
||||
#define XCLK_GPIO_NUM 27
|
||||
#define SIOD_GPIO_NUM 22
|
||||
#define SIOC_GPIO_NUM 23
|
||||
|
||||
#define Y9_GPIO_NUM 19
|
||||
#define Y8_GPIO_NUM 36
|
||||
#define Y7_GPIO_NUM 18
|
||||
#define Y6_GPIO_NUM 39
|
||||
#define Y5_GPIO_NUM 5
|
||||
#define Y4_GPIO_NUM 34
|
||||
#define Y3_GPIO_NUM 35
|
||||
#define Y2_GPIO_NUM 32
|
||||
#define VSYNC_GPIO_NUM 25
|
||||
#define HREF_GPIO_NUM 26
|
||||
#define PCLK_GPIO_NUM 21
|
||||
|
||||
#elif defined(CAMERA_MODEL_M5STACK_WIDE)
|
||||
#define PWDN_GPIO_NUM -1
|
||||
#define RESET_GPIO_NUM 15
|
||||
@ -75,6 +94,25 @@
|
||||
#define HREF_GPIO_NUM 26
|
||||
#define PCLK_GPIO_NUM 21
|
||||
|
||||
#elif defined(CAMERA_MODEL_M5STACK_ESP32CAM)
|
||||
#define PWDN_GPIO_NUM -1
|
||||
#define RESET_GPIO_NUM 15
|
||||
#define XCLK_GPIO_NUM 27
|
||||
#define SIOD_GPIO_NUM 25
|
||||
#define SIOC_GPIO_NUM 23
|
||||
|
||||
#define Y9_GPIO_NUM 19
|
||||
#define Y8_GPIO_NUM 36
|
||||
#define Y7_GPIO_NUM 18
|
||||
#define Y6_GPIO_NUM 39
|
||||
#define Y5_GPIO_NUM 5
|
||||
#define Y4_GPIO_NUM 34
|
||||
#define Y3_GPIO_NUM 35
|
||||
#define Y2_GPIO_NUM 17
|
||||
#define VSYNC_GPIO_NUM 22
|
||||
#define HREF_GPIO_NUM 26
|
||||
#define PCLK_GPIO_NUM 21
|
||||
|
||||
#elif defined(CAMERA_MODEL_AI_THINKER)
|
||||
#define PWDN_GPIO_NUM 32
|
||||
#define RESET_GPIO_NUM -1
|
||||
@ -94,6 +132,25 @@
|
||||
#define HREF_GPIO_NUM 23
|
||||
#define PCLK_GPIO_NUM 22
|
||||
|
||||
#elif defined(CAMERA_MODEL_TTGO_T_JOURNAL)
|
||||
#define PWDN_GPIO_NUM 0
|
||||
#define RESET_GPIO_NUM 15
|
||||
#define XCLK_GPIO_NUM 27
|
||||
#define SIOD_GPIO_NUM 25
|
||||
#define SIOC_GPIO_NUM 23
|
||||
|
||||
#define Y9_GPIO_NUM 19
|
||||
#define Y8_GPIO_NUM 36
|
||||
#define Y7_GPIO_NUM 18
|
||||
#define Y6_GPIO_NUM 39
|
||||
#define Y5_GPIO_NUM 5
|
||||
#define Y4_GPIO_NUM 34
|
||||
#define Y3_GPIO_NUM 35
|
||||
#define Y2_GPIO_NUM 17
|
||||
#define VSYNC_GPIO_NUM 22
|
||||
#define HREF_GPIO_NUM 26
|
||||
#define PCLK_GPIO_NUM 21
|
||||
|
||||
#else
|
||||
#error "Camera model not selected"
|
||||
#endif
|
||||
|
@ -1,13 +1,29 @@
|
||||
uint64_t chipid;
|
||||
/* The true ESP32 chip ID is essentially its MAC address.
|
||||
This sketch provides an alternate chip ID that matches
|
||||
the output of the ESP.getChipId() function on ESP8266
|
||||
(i.e. a 32-bit integer matching the last 3 bytes of
|
||||
the MAC address. This is less unique than the
|
||||
MAC address chip ID, but is helpful when you need
|
||||
an identifier that can be no more than a 32-bit integer
|
||||
(like for switch...case).
|
||||
|
||||
created 2020-06-07 by cweinhofer
|
||||
with help from Cicicok */
|
||||
|
||||
uint32_t chipId = 0;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
chipid=ESP.getEfuseMac();//The chip ID is essentially its MAC address(length: 6 bytes).
|
||||
Serial.printf("ESP32 Chip ID = %04X",(uint16_t)(chipid>>32));//print High 2 bytes
|
||||
Serial.printf("%08X\n",(uint32_t)chipid);//print Low 4bytes.
|
||||
for(int i=0; i<17; i=i+8) {
|
||||
chipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
|
||||
}
|
||||
|
||||
Serial.printf("ESP32 Chip model = %s Rev %d\n", ESP.getChipModel(), ESP.getChipRevision());
|
||||
Serial.printf("This chip has %d cores\n", ESP.getChipCores());
|
||||
Serial.print("Chip ID: "); Serial.println(chipId);
|
||||
|
||||
delay(3000);
|
||||
|
||||
|
64
libraries/ESP32/examples/RMT/RMTCallback/RMTCallback.ino
Normal file
64
libraries/ESP32/examples/RMT/RMTCallback/RMTCallback.ino
Normal file
@ -0,0 +1,64 @@
|
||||
#include "Arduino.h"
|
||||
#include "esp32-hal.h"
|
||||
|
||||
extern "C" void receive_trampoline(uint32_t *data, size_t len, void * arg);
|
||||
|
||||
class MyProcessor {
|
||||
private:
|
||||
rmt_obj_t* rmt_recv = NULL;
|
||||
float realNanoTick;
|
||||
uint32_t buff; // rolling buffer of most recent 32 bits.
|
||||
int at = 0;
|
||||
|
||||
public:
|
||||
MyProcessor(uint8_t pin, float nanoTicks) {
|
||||
assert((rmt_recv = rmtInit(21, false, RMT_MEM_192)));
|
||||
|
||||
realNanoTick = rmtSetTick(rmt_recv, nanoTicks);
|
||||
};
|
||||
void begin() {
|
||||
rmtRead(rmt_recv, receive_trampoline, this);
|
||||
};
|
||||
|
||||
void process(rmt_data_t *data, size_t len) {
|
||||
for (int i = 0; len; len--) {
|
||||
if (data[i].duration0 == 0)
|
||||
break;
|
||||
buff = (buff << 1) | (data[i].level0 ? 1 : 0);
|
||||
i++;
|
||||
|
||||
if (data[i].duration1 == 0)
|
||||
break;
|
||||
buff = (buff << 1) | (data[i].level1 ? 1 : 0);
|
||||
i++;
|
||||
};
|
||||
};
|
||||
uint32_t val() {
|
||||
return buff;
|
||||
}
|
||||
};
|
||||
|
||||
void receive_trampoline(uint32_t *data, size_t len, void * arg)
|
||||
{
|
||||
MyProcessor * p = (MyProcessor *)arg;
|
||||
p->process((rmt_data_t*) data, len);
|
||||
}
|
||||
|
||||
// Attach 3 processors to GPIO 4, 5 and 10 with different tick/speeds.
|
||||
MyProcessor mp1 = MyProcessor(4, 1000);
|
||||
MyProcessor mp2 = MyProcessor(5, 1000);
|
||||
MyProcessor mp3 = MyProcessor(10, 500);
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
mp1.begin();
|
||||
mp2.begin();
|
||||
mp3.begin();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.printf("GPIO 4: %08x 5: %08x 6: %08x\n", mp1.val(), mp2.val(), mp3.val());
|
||||
delay(500);
|
||||
}
|
@ -16,6 +16,7 @@ static EventGroupHandle_t events;
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
events = xEventGroupCreate();
|
||||
|
||||
if ((rmt_send = rmtInit(18, true, RMT_MEM_64)) == NULL)
|
||||
{
|
||||
|
@ -172,7 +172,7 @@ void parseRmt(rmt_data_t* items, size_t len, uint32_t* channels){
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void receive_data(uint32_t *data, size_t len)
|
||||
extern "C" void receive_data(uint32_t *data, size_t len, void * arg)
|
||||
{
|
||||
parseRmt((rmt_data_t*) data, len, channels);
|
||||
}
|
||||
@ -192,7 +192,7 @@ void setup()
|
||||
Serial.printf("real tick set to: %fns\n", realTick);
|
||||
|
||||
// Ask to start reading
|
||||
rmtRead(rmt_recv, receive_data);
|
||||
rmtRead(rmt_recv, receive_data, NULL);
|
||||
}
|
||||
|
||||
void loop()
|
||||
|
@ -47,7 +47,7 @@ void setup(void)
|
||||
|
||||
// Set up mDNS responder:
|
||||
// - first argument is the domain name, in this example
|
||||
// the fully-qualified domain name is "esp8266.local"
|
||||
// the fully-qualified domain name is "esp32.local"
|
||||
// - second argument is the IP address to advertise
|
||||
// we send our IP address on the WiFi network
|
||||
if (!MDNS.begin("esp32")) {
|
||||
|
@ -130,7 +130,7 @@ void MDNSResponder::disableWorkstation(){
|
||||
}
|
||||
}
|
||||
|
||||
void MDNSResponder::addService(char *name, char *proto, uint16_t port){
|
||||
bool MDNSResponder::addService(char *name, char *proto, uint16_t port){
|
||||
char _name[strlen(name)+2];
|
||||
char _proto[strlen(proto)+2];
|
||||
if (name[0] == '_') {
|
||||
@ -146,7 +146,9 @@ void MDNSResponder::addService(char *name, char *proto, uint16_t port){
|
||||
|
||||
if(mdns_service_add(NULL, _name, _proto, port, NULL, 0)) {
|
||||
log_e("Failed adding service %s.%s.\n", name, proto);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MDNSResponder::addServiceTxt(char *name, char *proto, char *key, char *value){
|
||||
|
@ -65,12 +65,12 @@ public:
|
||||
setInstanceName(String(name));
|
||||
}
|
||||
|
||||
void addService(char *service, char *proto, uint16_t port);
|
||||
void addService(const char *service, const char *proto, uint16_t port){
|
||||
addService((char *)service, (char *)proto, port);
|
||||
bool addService(char *service, char *proto, uint16_t port);
|
||||
bool addService(const char *service, const char *proto, uint16_t port){
|
||||
return addService((char *)service, (char *)proto, port);
|
||||
}
|
||||
void addService(String service, String proto, uint16_t port){
|
||||
addService(service.c_str(), proto.c_str(), port);
|
||||
bool addService(String service, String proto, uint16_t port){
|
||||
return addService(service.c_str(), proto.c_str(), port);
|
||||
}
|
||||
|
||||
bool addServiceTxt(char *name, char *proto, char * key, char * value);
|
||||
|
@ -52,6 +52,7 @@ void readFile(fs::FS &fs, const char * path){
|
||||
while(file.available()){
|
||||
Serial.write(file.read());
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
void writeFile(fs::FS &fs, const char * path, const char * message){
|
||||
@ -65,8 +66,9 @@ void writeFile(fs::FS &fs, const char * path, const char * message){
|
||||
if(file.print(message)){
|
||||
Serial.println("- file written");
|
||||
} else {
|
||||
Serial.println("- frite failed");
|
||||
Serial.println("- write failed");
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
void appendFile(fs::FS &fs, const char * path, const char * message){
|
||||
@ -82,6 +84,7 @@ void appendFile(fs::FS &fs, const char * path, const char * message){
|
||||
} else {
|
||||
Serial.println("- append failed");
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
void renameFile(fs::FS &fs, const char * path1, const char * path2){
|
||||
|
@ -135,6 +135,21 @@ size_t F_Fat::totalBytes()
|
||||
return tot_sect * sect_size;
|
||||
}
|
||||
|
||||
size_t F_Fat::usedBytes()
|
||||
{
|
||||
FATFS *fs;
|
||||
DWORD free_clust, used_sect, sect_size;
|
||||
|
||||
BYTE pdrv = ff_diskio_get_pdrv_wl(_wl_handle);
|
||||
char drv[3] = {(char)(48+pdrv), ':', 0};
|
||||
if ( f_getfree(drv, &free_clust, &fs) != FR_OK){
|
||||
return 0;
|
||||
}
|
||||
used_sect = (fs->n_fatent - 2 - free_clust) * fs->csize;
|
||||
sect_size = CONFIG_WL_SECTOR_SIZE;
|
||||
return used_sect * sect_size;
|
||||
}
|
||||
|
||||
size_t F_Fat::freeBytes()
|
||||
{
|
||||
|
||||
|
@ -31,6 +31,7 @@ public:
|
||||
bool begin(bool formatOnFail=false, const char * basePath="/ffat", uint8_t maxOpenFiles=10, const char * partitionLabel = (char*)FFAT_PARTITION_LABEL);
|
||||
bool format(bool full_wipe = FFAT_WIPE_QUICK, char* partitionLabel = (char*)FFAT_PARTITION_LABEL);
|
||||
size_t totalBytes();
|
||||
size_t usedBytes();
|
||||
size_t freeBytes();
|
||||
void end();
|
||||
bool exists(const char* path);
|
||||
|
@ -184,6 +184,11 @@ bool VFSImpl::rmdir(const char *path)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(_mountpoint, "/spiffs") == 0) {
|
||||
log_e("rmdir is unnecessary in SPIFFS");
|
||||
return false;
|
||||
}
|
||||
|
||||
VFSFileImpl f(this, path, "r");
|
||||
if(!f || !f.isDirectory()) {
|
||||
if(f) {
|
||||
@ -200,7 +205,7 @@ bool VFSImpl::rmdir(const char *path)
|
||||
return false;
|
||||
}
|
||||
sprintf(temp,"%s%s", _mountpoint, path);
|
||||
auto rc = unlink(temp);
|
||||
auto rc = ::rmdir(temp);
|
||||
free(temp);
|
||||
return rc == 0;
|
||||
}
|
||||
|
@ -548,6 +548,19 @@ int HTTPClient::sendRequest(const char * type, String payload)
|
||||
*/
|
||||
int HTTPClient::sendRequest(const char * type, uint8_t * payload, size_t size)
|
||||
{
|
||||
int code;
|
||||
bool redirect = false;
|
||||
uint16_t redirectCount = 0;
|
||||
do {
|
||||
// wipe out any existing headers from previous request
|
||||
for(size_t i = 0; i < _headerKeysCount; i++) {
|
||||
if (_currentHeaders[i].value.length() > 0) {
|
||||
_currentHeaders[i].value.clear();
|
||||
}
|
||||
}
|
||||
|
||||
log_d("request type: '%s' redirCount: %d\n", type, redirectCount);
|
||||
|
||||
// connect to server
|
||||
if(!connect()) {
|
||||
return returnError(HTTPC_ERROR_CONNECTION_REFUSED);
|
||||
@ -569,8 +582,72 @@ int HTTPClient::sendRequest(const char * type, uint8_t * payload, size_t size)
|
||||
}
|
||||
}
|
||||
|
||||
code = handleHeaderResponse();
|
||||
log_d("sendRequest code=%d\n", code);
|
||||
|
||||
// Handle redirections as stated in RFC document:
|
||||
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
||||
//
|
||||
// Implementing HTTP_CODE_FOUND as redirection with GET method,
|
||||
// to follow most of existing user agent implementations.
|
||||
//
|
||||
redirect = false;
|
||||
if (
|
||||
_followRedirects != HTTPC_DISABLE_FOLLOW_REDIRECTS &&
|
||||
redirectCount < _redirectLimit &&
|
||||
_location.length() > 0
|
||||
) {
|
||||
switch (code) {
|
||||
// redirecting using the same method
|
||||
case HTTP_CODE_MOVED_PERMANENTLY:
|
||||
case HTTP_CODE_TEMPORARY_REDIRECT: {
|
||||
if (
|
||||
// allow to force redirections on other methods
|
||||
// (the RFC require user to accept the redirection)
|
||||
_followRedirects == HTTPC_FORCE_FOLLOW_REDIRECTS ||
|
||||
// allow GET and HEAD methods without force
|
||||
!strcmp(type, "GET") ||
|
||||
!strcmp(type, "HEAD")
|
||||
) {
|
||||
redirectCount += 1;
|
||||
log_d("following redirect (the same method): '%s' redirCount: %d\n", _location.c_str(), redirectCount);
|
||||
if (!setURL(_location)) {
|
||||
log_d("failed setting URL for redirection\n");
|
||||
// no redirection
|
||||
break;
|
||||
}
|
||||
// redirect using the same request method and payload, diffrent URL
|
||||
redirect = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// redirecting with method dropped to GET or HEAD
|
||||
// note: it does not need `HTTPC_FORCE_FOLLOW_REDIRECTS` for any method
|
||||
case HTTP_CODE_FOUND:
|
||||
case HTTP_CODE_SEE_OTHER: {
|
||||
redirectCount += 1;
|
||||
log_d("following redirect (dropped to GET/HEAD): '%s' redirCount: %d\n", _location.c_str(), redirectCount);
|
||||
if (!setURL(_location)) {
|
||||
log_d("failed setting URL for redirection\n");
|
||||
// no redirection
|
||||
break;
|
||||
}
|
||||
// redirect after changing method to GET/HEAD and dropping payload
|
||||
type = "GET";
|
||||
payload = nullptr;
|
||||
size = 0;
|
||||
redirect = true;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} while (redirect);
|
||||
// handle Server Response (Header)
|
||||
return returnError(handleHeaderResponse());
|
||||
return returnError(code);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -842,18 +919,19 @@ int HTTPClient::writeToStream(Stream * stream)
|
||||
*/
|
||||
String HTTPClient::getString(void)
|
||||
{
|
||||
// _size can be -1 when Server sends no Content-Length header
|
||||
if(_size > 0 || _size == -1) {
|
||||
StreamString sstring;
|
||||
|
||||
if(_size) {
|
||||
// try to reserve needed memmory
|
||||
if(!sstring.reserve((_size + 1))) {
|
||||
log_d("not enough memory to reserve a string! need: %d", (_size + 1));
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// try to reserve needed memory (noop if _size == -1)
|
||||
if(sstring.reserve((_size + 1))) {
|
||||
writeToStream(&sstring);
|
||||
return sstring;
|
||||
} else {
|
||||
log_d("not enough memory to reserve a string! need: %d", (_size + 1));
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -910,7 +988,7 @@ void HTTPClient::addHeader(const String& name, const String& value, bool first,
|
||||
|
||||
if (replace) {
|
||||
int headerStart = _headers.indexOf(headerLine);
|
||||
if (headerStart != -1) {
|
||||
if (headerStart != -1 && (headerStart == 0 || _headers[headerStart - 1] == '\n')) {
|
||||
int headerEnd = _headers.indexOf('\n', headerStart);
|
||||
_headers = _headers.substring(0, headerStart) + _headers.substring(headerEnd + 1);
|
||||
}
|
||||
@ -924,7 +1002,6 @@ void HTTPClient::addHeader(const String& name, const String& value, bool first,
|
||||
_headers += headerLine;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void HTTPClient::collectHeaders(const char* headerKeys[], const size_t headerKeysCount)
|
||||
@ -1013,7 +1090,13 @@ bool HTTPClient::connect(void)
|
||||
log_d("HTTPClient::begin was not called or returned error");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef HTTPCLIENT_1_1_COMPATIBLE
|
||||
if (_tcpDeprecated && !_transportTraits->verify(*_client, _host.c_str())) {
|
||||
log_d("transport level verify failed");
|
||||
_client->stop();
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if(!_client->connect(_host.c_str(), _port, _connectTimeout)) {
|
||||
log_d("failed connect to %s:%u", _host.c_str(), _port);
|
||||
return false;
|
||||
@ -1024,14 +1107,6 @@ bool HTTPClient::connect(void)
|
||||
|
||||
log_d(" connected to %s:%u", _host.c_str(), _port);
|
||||
|
||||
#ifdef HTTPCLIENT_1_1_COMPATIBLE
|
||||
if (_tcpDeprecated && !_transportTraits->verify(*_client, _host.c_str())) {
|
||||
log_d("transport level verify failed");
|
||||
_client->stop();
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
#ifdef ESP8266
|
||||
@ -1111,6 +1186,7 @@ int HTTPClient::handleHeaderResponse()
|
||||
|
||||
_transferEncoding = HTTPC_TE_IDENTITY;
|
||||
unsigned long lastDataTime = millis();
|
||||
bool firstLine = true;
|
||||
|
||||
while(connected()) {
|
||||
size_t len = _client->available();
|
||||
@ -1122,11 +1198,13 @@ int HTTPClient::handleHeaderResponse()
|
||||
|
||||
log_v("RX: '%s'", headerLine.c_str());
|
||||
|
||||
if(headerLine.startsWith("HTTP/1.")) {
|
||||
if(_canReuse) {
|
||||
if(firstLine) {
|
||||
firstLine = false;
|
||||
if(_canReuse && headerLine.startsWith("HTTP/1.")) {
|
||||
_canReuse = (headerLine[sizeof "HTTP/1." - 1] != '0');
|
||||
}
|
||||
_returnCode = headerLine.substring(9, headerLine.indexOf(' ', 9)).toInt();
|
||||
int codePos = headerLine.indexOf(' ') + 1;
|
||||
_returnCode = headerLine.substring(codePos, headerLine.indexOf(' ', codePos)).toInt();
|
||||
} else if(headerLine.indexOf(':')) {
|
||||
String headerName = headerLine.substring(0, headerLine.indexOf(':'));
|
||||
String headerValue = headerLine.substring(headerLine.indexOf(':') + 1);
|
||||
@ -1146,6 +1224,10 @@ int HTTPClient::handleHeaderResponse()
|
||||
transferEncoding = headerValue;
|
||||
}
|
||||
|
||||
if (headerName.equalsIgnoreCase("Location")) {
|
||||
_location = headerValue;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < _headerKeysCount; i++) {
|
||||
if(_currentHeaders[i].key.equalsIgnoreCase(headerName)) {
|
||||
_currentHeaders[i].value = headerValue;
|
||||
@ -1323,3 +1405,52 @@ int HTTPClient::returnError(int error)
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
void HTTPClient::setFollowRedirects(followRedirects_t follow)
|
||||
{
|
||||
_followRedirects = follow;
|
||||
}
|
||||
|
||||
void HTTPClient::setRedirectLimit(uint16_t limit)
|
||||
{
|
||||
_redirectLimit = limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the URL to a new value. Handy for following redirects.
|
||||
* @param url
|
||||
*/
|
||||
bool HTTPClient::setURL(const String& url)
|
||||
{
|
||||
// if the new location is only a path then only update the URI
|
||||
if (url && url[0] == '/') {
|
||||
_uri = url;
|
||||
clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!url.startsWith(_protocol + ':')) {
|
||||
log_d("new URL not the same protocol, expected '%s', URL: '%s'\n", _protocol.c_str(), url.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if the port is specified
|
||||
int indexPort = url.indexOf(':', 6); // find the first ':' excluding the one from the protocol
|
||||
int indexURI = url.indexOf('/', 7); // find where the URI starts to make sure the ':' is not part of it
|
||||
if (indexPort == -1 || indexPort > indexURI) {
|
||||
// the port is not specified
|
||||
_port = (_protocol == "https" ? 443 : 80);
|
||||
}
|
||||
|
||||
// disconnect but preserve _client.
|
||||
// Also have to keep the connection otherwise it will free some of the memory used by _client
|
||||
// and will blow up later when trying to do _client->available() or similar
|
||||
_canReuse = true;
|
||||
disconnect(true);
|
||||
return beginInternal(url, _protocol.c_str());
|
||||
}
|
||||
|
||||
const String &HTTPClient::getLocation(void)
|
||||
{
|
||||
return _location;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user