mirror of
https://github.com/0xFEEDC0DE64/arduino-esp32.git
synced 2025-06-25 18:01:33 +02:00
Compare commits
79 Commits
Author | SHA1 | Date | |
---|---|---|---|
33011ede30 | |||
f3e416217d | |||
0efa90df6e | |||
548412952b | |||
3e8f7fe8d4 | |||
832c08e9fb | |||
99ba0e1cc5 | |||
d32d70dc0d | |||
6b93a6c21e | |||
f9423ab83f | |||
e5913c36ea | |||
247bca8bda | |||
46a026a45d | |||
2cb664eeec | |||
2cde553e17 | |||
adb88d7bed | |||
1a7962ece8 | |||
2b67a4e68a | |||
722c4641c4 | |||
ba6e82c30d | |||
ad14258d2c | |||
ed33e15752 | |||
5482315036 | |||
09c0a39d2a | |||
a9d77ac66e | |||
14156d8071 | |||
b42b20850b | |||
edd2bd2dab | |||
1fed09bc74 | |||
49bdd5f053 | |||
709029996f | |||
bdeef89cc6 | |||
ca77502ceb | |||
d302091267 | |||
5dc4226cc5 | |||
85ec66a4e0 | |||
44beee2f2c | |||
0b3f1a9fa9 | |||
6707ceb63c | |||
142fceb856 | |||
ba591fd958 | |||
4453ca5493 | |||
ce2cd111a1 | |||
5f6d093d4a | |||
51bf1832b8 | |||
384dbc2081 | |||
f2cfe78705 | |||
45583af189 | |||
f60cd8a069 | |||
5fa0c2010e | |||
adfaaecc65 | |||
0dd517dc9f | |||
823fe77e41 | |||
a9d33de70e | |||
d7ffd573d0 | |||
b88a70a0bd | |||
f3bdfb31f9 | |||
d8a99ed449 | |||
0a1ba74b60 | |||
1aa16104ff | |||
22c51579da | |||
f0636d515f | |||
b3c203db26 | |||
323bbbf63b | |||
02f4178b72 | |||
e1c9606531 | |||
fb60efd592 | |||
12045d335b | |||
45b7fa05b6 | |||
d3340837c7 | |||
6cfe4613e4 | |||
7dc8ca4e1e | |||
d4e20294e5 | |||
f1acc432af | |||
6fe1c4c5d6 | |||
5d6b9d0939 | |||
6b72fee59b | |||
a1409ef90d | |||
ab197e12a9 |
12
.github/ISSUE_TEMPLATE/Issue-report.yml
vendored
12
.github/ISSUE_TEMPLATE/Issue-report.yml
vendored
@ -39,7 +39,9 @@ body:
|
||||
label: Version
|
||||
description: What version of Arduino ESP32 are you running? If possible, consider updating to the latest version.
|
||||
options:
|
||||
- latest master
|
||||
- latest master (checkout manually)
|
||||
- latest development Release Candidate (RC-X)
|
||||
- v2.0.3
|
||||
- v2.0.2
|
||||
- v2.0.1
|
||||
- v2.0.0
|
||||
@ -52,7 +54,7 @@ body:
|
||||
attributes:
|
||||
label: IDE Name
|
||||
description: What IDE are you using?
|
||||
placeholder: eg. Arduino IDE, PlatformIO, IDF component...
|
||||
placeholder: eg. Arduino IDE, PlatformIO, Sloeber...
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
@ -101,8 +103,8 @@ body:
|
||||
id: sketch
|
||||
attributes:
|
||||
label: Sketch
|
||||
description: Please provide your sketch/code which was run
|
||||
placeholder: ex. related part of the code
|
||||
description: Please provide full minimal sketch/code which can be run to reproduce your issue
|
||||
placeholder: ex. Related part of the code to replicate the issue
|
||||
render: cpp
|
||||
validations:
|
||||
required: true
|
||||
@ -128,4 +130,4 @@ body:
|
||||
description: You agree to check all the resources above before opening a new issue.
|
||||
options:
|
||||
- label: I confirm I have checked existing issues, online documentation and Troubleshooting guide.
|
||||
required: true
|
||||
required: true
|
||||
|
21
.github/PULL_REQUEST_TEMPLATE.md
vendored
21
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,18 +1,23 @@
|
||||
*By completing this PR sufficiently, you help us to improve the quality of Release Notes*
|
||||
*By completing this PR sufficiently, you help us to review this Pull Request quicker and also help improve the quality of Release Notes*
|
||||
|
||||
### Checklist
|
||||
1. [ ] Please provide specific title of the PR describing the change, including the component name (eg. *„Update of Documentation link on Readme.md“*)
|
||||
2. [ ] Please provide related links (eg. Issue, other Project, submodule PR..)
|
||||
3. [ ] Please check [Contributing guide](https://docs.espressif.com/projects/arduino-esp32/en/latest/contributing.html)
|
||||
1. [ ] Please provide specific title of the PR describing the change, including the component name (*eg. „Update of Documentation link on Readme.md“*)
|
||||
2. [ ] Please provide related links (*eg. Issue which will be closed by this Pull Request*)
|
||||
3. [ ] Please **update relevant Documentation** if applicable
|
||||
4. [ ] Please check [Contributing guide](https://docs.espressif.com/projects/arduino-esp32/en/latest/contributing.html)
|
||||
|
||||
*This entire section above can be deleted if all items are checked.*
|
||||
|
||||
-----------
|
||||
## Summary
|
||||
Please describe your proposed PR and what it contains.
|
||||
## Description of Change
|
||||
Please describe your proposed Pull Request and it's impact.
|
||||
|
||||
## Impact
|
||||
Please describe impact of your PR and it's function.
|
||||
## Tests scenarios
|
||||
Please describe on what Hardware and Software combinations you have tested this Pull Request and how.
|
||||
|
||||
(*eg. I have tested my Pull Request on Arduino-esp32 core v2.0.2 with ESP32 and ESP32-S2 Board with this scenario*)
|
||||
|
||||
## Related links
|
||||
Please provide links to related issue, PRs etc.
|
||||
|
||||
(*eg. Closes #number of issue*)
|
||||
|
2
.github/scripts/install-platformio-esp32.sh
vendored
2
.github/scripts/install-platformio-esp32.sh
vendored
@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
export PLATFORMIO_ESP32_PATH="$HOME/.platformio/packages/framework-arduinoespressif32"
|
||||
PLATFORMIO_ESP32_URL="https://github.com/platformio/platform-espressif32.git#feature/arduino-idf-master"
|
||||
PLATFORMIO_ESP32_URL="https://github.com/platformio/platform-espressif32.git"
|
||||
|
||||
TOOLCHAIN_VERSION="8.4.0+2021r2-patch3"
|
||||
ESPTOOLPY_VERSION="~1.30100.0"
|
||||
|
1
.github/scripts/on-release.sh
vendored
1
.github/scripts/on-release.sh
vendored
@ -172,6 +172,7 @@ mkdir -p "$PKG_DIR/tools"
|
||||
# Copy all core files to the package folder
|
||||
echo "Copying files for packaging ..."
|
||||
cp -f "$GITHUB_WORKSPACE/boards.txt" "$PKG_DIR/"
|
||||
cp -f "$GITHUB_WORKSPACE/package.json" "$PKG_DIR/"
|
||||
cp -f "$GITHUB_WORKSPACE/programmers.txt" "$PKG_DIR/"
|
||||
cp -Rf "$GITHUB_WORKSPACE/cores" "$PKG_DIR/"
|
||||
cp -Rf "$GITHUB_WORKSPACE/libraries" "$PKG_DIR/"
|
||||
|
15
.github/scripts/sketch_utils.sh
vendored
15
.github/scripts/sketch_utils.sh
vendored
@ -7,12 +7,6 @@ function build_sketch(){ # build_sketch <ide_path> <user_path> <fqbn> <path-to-i
|
||||
return 1
|
||||
fi
|
||||
|
||||
ARDUINO_CACHE_DIR="$HOME/.arduino/cache.tmp"
|
||||
if [ -z "$ARDUINO_BUILD_DIR" ]; then
|
||||
build_dir="$(dirname $sketch)/build"
|
||||
else
|
||||
build_dir="$ARDUINO_BUILD_DIR"
|
||||
fi
|
||||
local ide_path=$1
|
||||
local usr_path=$2
|
||||
local fqbn=$3
|
||||
@ -20,6 +14,15 @@ function build_sketch(){ # build_sketch <ide_path> <user_path> <fqbn> <path-to-i
|
||||
local xtra_opts=$5
|
||||
local win_opts=$6
|
||||
|
||||
ARDUINO_CACHE_DIR="$HOME/.arduino/cache.tmp"
|
||||
if [ -z "$ARDUINO_BUILD_DIR" ]; then
|
||||
build_dir="$(dirname $sketch)/build"
|
||||
else
|
||||
build_dir="$ARDUINO_BUILD_DIR"
|
||||
fi
|
||||
|
||||
echo $sketch
|
||||
|
||||
rm -rf "$build_dir"
|
||||
mkdir -p "$build_dir"
|
||||
mkdir -p "$ARDUINO_CACHE_DIR"
|
||||
|
4
.github/scripts/update-version.sh
vendored
4
.github/scripts/update-version.sh
vendored
@ -1,5 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
# For reference: add tools for all boards by replacing one line in each board
|
||||
# "[board].upload.tool=esptool_py" to "[board].upload.tool=esptool_py\n[board].upload.tool.default=esptool_py\n[board].upload.tool.network=esp_ota"
|
||||
#cat boards.txt | sed "s/\([a-zA-Z0-9_\-]*\)\.upload\.tool\=esptool_py/\1\.upload\.tool\=esptool_py\\n\1\.upload\.tool\.default\=esptool_py\\n\1\.upload\.tool\.network\=esp_ota/"
|
||||
|
||||
if [ ! $# -eq 3 ]; then
|
||||
echo "Bad number of arguments: $#" >&2
|
||||
echo "usage: $0 <major> <minor> <patch>" >&2
|
||||
|
26
.github/stale.yml
vendored
26
.github/stale.yml
vendored
@ -1,26 +0,0 @@
|
||||
# This workflow firstly warns and then closes issues that have had no activity for a specified amount of time.
|
||||
#
|
||||
# You can adjust the behavior by modifying this file.
|
||||
# For more information can be found here: https://github.com/actions/stale
|
||||
|
||||
name: Mark stale issues
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 9 * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v3
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs. Thank you for your contributions.'
|
||||
days-before-stale: 60
|
||||
days-before-close: 14
|
||||
exempt-issue-labels: 'Type: For reference,Type: To be implemented,Type: Feature request'
|
||||
stale-issue-label: 'Status: Stale'
|
18
.github/workflows/hil.yml
vendored
18
.github/workflows/hil.yml
vendored
@ -18,7 +18,7 @@ jobs:
|
||||
gen_chunks:
|
||||
if: |
|
||||
contains(github.event.pull_request.labels.*.name, 'hil_test') ||
|
||||
github.event_name == 'schedule'
|
||||
(github.event_name == 'schedule' && github.repository == 'espressif/arduino-esp32')
|
||||
name: Generate Chunks matrix
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
@ -67,7 +67,12 @@ jobs:
|
||||
Test:
|
||||
needs: [gen_chunks, Build]
|
||||
name: ${{matrix.chip}}-Test#${{matrix.chunks}}
|
||||
runs-on: ESP32
|
||||
runs-on:
|
||||
- ESP32
|
||||
- ESP32-S2
|
||||
- ESP32-S3
|
||||
- ESP32-C3
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@ -87,11 +92,6 @@ jobs:
|
||||
name: ${{matrix.chip}}-${{matrix.chunks}}.artifacts
|
||||
path: tests/
|
||||
|
||||
- name: Check Artifacts
|
||||
run: |
|
||||
ls -R tests
|
||||
cat tests/*/build/build.options.json
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
pip install -U pip
|
||||
@ -110,7 +110,9 @@ jobs:
|
||||
|
||||
event_file:
|
||||
name: "Event File"
|
||||
if: ${{ always() }}
|
||||
if: |
|
||||
contains(github.event.pull_request.labels.*.name, 'hil_test') ||
|
||||
github.event_name == 'schedule'
|
||||
needs: Test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
3
.github/workflows/publish.yml
vendored
3
.github/workflows/publish.yml
vendored
@ -14,7 +14,8 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: |
|
||||
github.event.workflow_run.event == 'pull_request' &&
|
||||
github.event.workflow_run.conclusion != 'skipped'
|
||||
(github.event.workflow_run.conclusion == 'success' ||
|
||||
github.event.workflow_run.conclusion == 'failure')
|
||||
steps:
|
||||
- name: Download and Extract Artifacts
|
||||
env:
|
||||
|
27
.github/workflows/push.yml
vendored
27
.github/workflows/push.yml
vendored
@ -78,3 +78,30 @@ jobs:
|
||||
python-version: '3.x'
|
||||
- name: Build Sketches
|
||||
run: bash ./.github/scripts/on-push.sh 1 1 #equal and non-zero to trigger PIO
|
||||
|
||||
build-esp-idf-component:
|
||||
name: Build with ESP-IDF ${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
# The version names here correspond to the versions of espressif/idf Docker image.
|
||||
# See https://hub.docker.com/r/espressif/idf/tags and
|
||||
# https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-docker-image.html
|
||||
# for details.
|
||||
idf_ver: ["release-v4.4"]
|
||||
idf_target: ["esp32", "esp32s2", "esp32s3", "esp32c3"]
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Check out arduino-esp32 as a component
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
path: components/arduino-esp32
|
||||
- name: Build
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
idf.py create-project test
|
||||
idf.py -C test -DEXTRA_COMPONENT_DIRS=$PWD/components build
|
||||
|
2
.github/workflows/upload-idf-component.yml
vendored
2
.github/workflows/upload-idf-component.yml
vendored
@ -2,7 +2,7 @@ name: Push components to https://components.espressif.com
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
- '*'
|
||||
jobs:
|
||||
upload_components:
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -95,6 +95,8 @@ set(LIBRARY_SRCS
|
||||
libraries/RainMaker/src/RMakerParam.cpp
|
||||
libraries/RainMaker/src/RMakerDevice.cpp
|
||||
libraries/RainMaker/src/RMakerType.cpp
|
||||
libraries/RainMaker/src/RMakerQR.cpp
|
||||
libraries/RainMaker/src/RMakerUtils.cpp
|
||||
libraries/SD_MMC/src/SD_MMC.cpp
|
||||
libraries/SD/src/SD.cpp
|
||||
libraries/SD/src/sd_diskio.cpp
|
||||
|
@ -21,7 +21,8 @@ config AUTOSTART_ARDUINO
|
||||
|
||||
choice ARDUINO_RUNNING_CORE
|
||||
bool "Core on which Arduino's setup() and loop() are running"
|
||||
default ARDUINO_RUN_CORE1
|
||||
default ARDUINO_RUN_CORE0 if FREERTOS_UNICORE
|
||||
default ARDUINO_RUN_CORE1 if !FREERTOS_UNICORE
|
||||
help
|
||||
Select on which core Arduino's setup() and loop() functions run
|
||||
|
||||
@ -29,8 +30,10 @@ choice ARDUINO_RUNNING_CORE
|
||||
bool "CORE 0"
|
||||
config ARDUINO_RUN_CORE1
|
||||
bool "CORE 1"
|
||||
depends on !FREERTOS_UNICORE
|
||||
config ARDUINO_RUN_NO_AFFINITY
|
||||
bool "BOTH"
|
||||
depends on !FREERTOS_UNICORE
|
||||
|
||||
endchoice
|
||||
|
||||
@ -48,7 +51,8 @@ config ARDUINO_LOOP_STACK_SIZE
|
||||
|
||||
choice ARDUINO_EVENT_RUNNING_CORE
|
||||
bool "Core on which Arduino's event handler is running"
|
||||
default ARDUINO_EVENT_RUN_CORE1
|
||||
default ARDUINO_EVENT_RUN_CORE0 if FREERTOS_UNICORE
|
||||
default ARDUINO_EVENT_RUN_CORE1 if !FREERTOS_UNICORE
|
||||
help
|
||||
Select on which core Arduino's WiFi.onEvent() run
|
||||
|
||||
@ -56,8 +60,10 @@ choice ARDUINO_EVENT_RUNNING_CORE
|
||||
bool "CORE 0"
|
||||
config ARDUINO_EVENT_RUN_CORE1
|
||||
bool "CORE 1"
|
||||
depends on !FREERTOS_UNICORE
|
||||
config ARDUINO_EVENT_RUN_NO_AFFINITY
|
||||
bool "BOTH"
|
||||
depends on !FREERTOS_UNICORE
|
||||
|
||||
endchoice
|
||||
|
||||
@ -67,9 +73,45 @@ config ARDUINO_EVENT_RUNNING_CORE
|
||||
default 1 if ARDUINO_EVENT_RUN_CORE1
|
||||
default -1 if ARDUINO_EVENT_RUN_NO_AFFINITY
|
||||
|
||||
choice ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE
|
||||
bool "Core on which Arduino's Serial Event task is running"
|
||||
default ARDUINO_SERIAL_EVENT_RUN_CORE0 if FREERTOS_UNICORE
|
||||
default ARDUINO_SERIAL_EVENT_RUN_NO_AFFINITY if !FREERTOS_UNICORE
|
||||
help
|
||||
Select on which core Arduino's Serial Event task run
|
||||
|
||||
config ARDUINO_SERIAL_EVENT_RUN_CORE0
|
||||
bool "CORE 0"
|
||||
config ARDUINO_SERIAL_EVENT_RUN_CORE1
|
||||
bool "CORE 1"
|
||||
depends on !FREERTOS_UNICORE
|
||||
config ARDUINO_SERIAL_EVENT_RUN_NO_AFFINITY
|
||||
bool "BOTH"
|
||||
depends on !FREERTOS_UNICORE
|
||||
|
||||
endchoice
|
||||
|
||||
config ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE
|
||||
int
|
||||
default 0 if ARDUINO_SERIAL_EVENT_RUN_CORE0
|
||||
default 1 if ARDUINO_SERIAL_EVENT_RUN_CORE1
|
||||
default -1 if ARDUINO_SERIAL_EVENT_RUN_NO_AFFINITY
|
||||
|
||||
config ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE
|
||||
int "Serial Event task stack size"
|
||||
default 2048
|
||||
help
|
||||
Amount of stack available for the Serial Event task.
|
||||
|
||||
config ARDUINO_SERIAL_EVENT_TASK_PRIORITY
|
||||
int "Priority of the Serial Event task"
|
||||
default 24
|
||||
help
|
||||
Select at what priority you want the Serial Event task to run.
|
||||
|
||||
choice ARDUINO_UDP_RUNNING_CORE
|
||||
bool "Core on which Arduino's UDP is running"
|
||||
default ARDUINO_UDP_RUN_CORE1
|
||||
default ARDUINO_UDP_RUN_CORE0
|
||||
help
|
||||
Select on which core Arduino's UDP run
|
||||
|
||||
@ -77,23 +119,25 @@ choice ARDUINO_UDP_RUNNING_CORE
|
||||
bool "CORE 0"
|
||||
config ARDUINO_UDP_RUN_CORE1
|
||||
bool "CORE 1"
|
||||
depends on !FREERTOS_UNICORE
|
||||
config ARDUINO_UDP_RUN_NO_AFFINITY
|
||||
bool "BOTH"
|
||||
depends on !FREERTOS_UNICORE
|
||||
|
||||
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 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_ISR_IRAM
|
||||
bool "Run interrupts in IRAM"
|
||||
default "n"
|
||||
@ -356,3 +400,4 @@ config ARDUINO_SELECTIVE_Wire
|
||||
|
||||
|
||||
endmenu
|
||||
|
||||
|
21
README.md
21
README.md
@ -2,13 +2,17 @@
|
||||
|
||||
 [](https://docs.espressif.com/projects/arduino-esp32/en/latest/?badge=latest)
|
||||
|
||||
### Need help or have a question? Join the chat at [](https://gitter.im/espressif/arduino-esp32?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
### Need help or have a question? Join the chat at [](https://gitter.im/espressif/arduino-esp32?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) or [open a new Discussion](https://github.com/espressif/arduino-esp32/discussions)
|
||||
|
||||
## Contents
|
||||
|
||||
- [Development Status](#development-status)
|
||||
- [Decoding Exceptions](#decoding-exceptions)
|
||||
- [Issue/Bug report template](#issuebug-report-template)
|
||||
- [Development Status](#development-status)
|
||||
- [Development Planning](#development-planning)
|
||||
- [Documentation](#documentation)
|
||||
- [Supported Chips](#supported-chips)
|
||||
- [Decoding exceptions](#decoding-exceptions)
|
||||
- [Issue/Bug report template](#issuebug-report-template)
|
||||
- [Contributing](#contributing)
|
||||
|
||||
### Development Status
|
||||
|
||||
@ -16,9 +20,15 @@ Latest Stable Release [](https://github.com/espressif/arduino-esp32/releases/) [](https://github.com/espressif/arduino-esp32/releases/) [](https://github.com/espressif/arduino-esp32/releases/)
|
||||
|
||||
### Development Planning
|
||||
|
||||
Our Development is fully tracked on this public **[Roadmap 🎉](https://github.com/orgs/espressif/projects/3)**
|
||||
|
||||
For even more information you can take a look at [Sprint Meeting notes](https://github.com/espressif/arduino-esp32/discussions/categories/sprints-meeting-notes) or join [Monthly Community Meetings 🔔](https://github.com/espressif/arduino-esp32/discussions/categories/monthly-community-meetings)
|
||||
|
||||
### Documentation
|
||||
|
||||
You can use [Arduino-ESP32 Online Documentation](https://docs.espressif.com/projects/arduino-esp32/en/latest/) to get all information about this project.
|
||||
You can use the [Arduino-ESP32 Online Documentation](https://docs.espressif.com/projects/arduino-esp32/en/latest/) to get all information about this project.
|
||||
|
||||
* [Getting Started](https://docs.espressif.com/projects/arduino-esp32/en/latest/getting_started.html)
|
||||
* [Installing (Windows, Linux and macOS)](https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html)
|
||||
@ -36,6 +46,7 @@ Visit the [supported chips](https://docs.espressif.com/projects/arduino-esp32/en
|
||||
You can use [EspExceptionDecoder](https://github.com/me-no-dev/EspExceptionDecoder) to get meaningful call trace.
|
||||
|
||||
### 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 [Type: For reference](https://github.com/espressif/arduino-esp32/issues?q=is%3Aissue+label%3A%22Type%3A+For+reference%22+).
|
||||
|
||||
Finally, if you are sure no one else had the issue, follow the **Issue template** or **Feature request template** while reporting any [new Issue](https://github.com/espressif/arduino-esp32/issues/new/choose).
|
||||
|
1918
boards.txt
Executable file → Normal file
1918
boards.txt
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
@ -69,7 +69,12 @@
|
||||
#define __STRINGIFY(a) #a
|
||||
#endif
|
||||
|
||||
// can't define max() / min() because of conflicts with C++
|
||||
#define _min(a,b) ((a)<(b)?(a):(b))
|
||||
#define _max(a,b) ((a)>(b)?(a):(b))
|
||||
#define _abs(x) ((x)>0?(x):-(x)) // abs() comes from STL
|
||||
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
|
||||
#define _round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) // round() comes from STL
|
||||
#define radians(deg) ((deg)*DEG_TO_RAD)
|
||||
#define degrees(rad) ((rad)*RAD_TO_DEG)
|
||||
#define sq(x) ((x)*(x))
|
||||
@ -89,6 +94,7 @@
|
||||
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
|
||||
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
|
||||
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
|
||||
#define bitToggle(value, bit) ((value) ^= (1UL << (bit)))
|
||||
#define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet(value, bit) : bitClear(value, bit))
|
||||
|
||||
// avr-libc defines _NOP() since 1.6.2
|
||||
@ -168,12 +174,13 @@ void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
|
||||
#include "Esp.h"
|
||||
#include "esp32/spiram.h"
|
||||
|
||||
// Use float-compatible stl abs() and round(), we don't use Arduino macros to avoid issues with the C++ libraries
|
||||
using std::abs;
|
||||
using std::isinf;
|
||||
using std::isnan;
|
||||
using std::max;
|
||||
using std::min;
|
||||
using ::round;
|
||||
using std::round;
|
||||
|
||||
uint16_t makeWord(uint16_t w);
|
||||
uint16_t makeWord(uint8_t h, uint8_t l);
|
||||
@ -203,9 +210,6 @@ void noTone(uint8_t _pin);
|
||||
long random(long);
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define _min(a,b) ((a)<(b)?(a):(b))
|
||||
#define _max(a,b) ((a)>(b)?(a):(b))
|
||||
|
||||
#include "pins_arduino.h"
|
||||
|
||||
#endif /* _ESP32_CORE_ARDUINO_H_ */
|
||||
|
@ -9,6 +9,18 @@
|
||||
#include "driver/uart.h"
|
||||
#include "freertos/queue.h"
|
||||
|
||||
#ifndef ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE
|
||||
#define ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE 2048
|
||||
#endif
|
||||
|
||||
#ifndef ARDUINO_SERIAL_EVENT_TASK_PRIORITY
|
||||
#define ARDUINO_SERIAL_EVENT_TASK_PRIORITY (configMAX_PRIORITIES-1)
|
||||
#endif
|
||||
|
||||
#ifndef ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE
|
||||
#define ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE -1
|
||||
#endif
|
||||
|
||||
#ifndef SOC_RX0
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define SOC_RX0 3
|
||||
@ -159,7 +171,7 @@ HardwareSerial::~HardwareSerial()
|
||||
void HardwareSerial::_createEventTask(void *args)
|
||||
{
|
||||
// Creating UART event Task
|
||||
xTaskCreate(_uartEventTask, "uart_event_task", 2048, this, configMAX_PRIORITIES - 1, &_eventTask);
|
||||
xTaskCreateUniversal(_uartEventTask, "uart_event_task", ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE, this, ARDUINO_SERIAL_EVENT_TASK_PRIORITY, &_eventTask, ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE);
|
||||
if (_eventTask == NULL) {
|
||||
log_e(" -- UART%d Event Task not Created!", _uart_nr);
|
||||
}
|
||||
|
@ -120,3 +120,6 @@ bool IPAddress::fromString(const char *address)
|
||||
_address.bytes[3] = acc;
|
||||
return true;
|
||||
}
|
||||
|
||||
// declared one time - as external in IPAddress.h
|
||||
IPAddress INADDR_NONE(0, 0, 0, 0);
|
||||
|
@ -91,6 +91,6 @@ public:
|
||||
friend class DNSClient;
|
||||
};
|
||||
|
||||
const IPAddress INADDR_NONE(0, 0, 0, 0);
|
||||
|
||||
// changed to extern because const declaration creates copies in BSS of INADDR_NONE for each CPP unit that includes it
|
||||
extern IPAddress INADDR_NONE;
|
||||
#endif
|
||||
|
@ -28,7 +28,7 @@ static void tone_task(void*){
|
||||
xQueueReceive(_tone_queue, &tone_msg, portMAX_DELAY);
|
||||
switch(tone_msg.tone_cmd){
|
||||
case TONE_START:
|
||||
log_d("Task received from queue TONE_START: _pin=%d, frequency=%u Hz, duration=%u ms", tone_msg.pin, tone_msg.frequency, tone_msg.duration);
|
||||
log_d("Task received from queue TONE_START: _pin=%d, frequency=%u Hz, duration=%lu ms", tone_msg.pin, tone_msg.frequency, tone_msg.duration);
|
||||
|
||||
log_d("Setup LED controll on channel %d", _channel);
|
||||
// ledcSetup(_channel, tone_msg.frequency, 11);
|
||||
@ -95,6 +95,9 @@ void setToneChannel(uint8_t channel){
|
||||
if(tone_init()){
|
||||
tone_msg_t tone_msg = {
|
||||
.tone_cmd = TONE_SET_CHANNEL,
|
||||
.pin = 0, // Ignored
|
||||
.frequency = 0, // Ignored
|
||||
.duration = 0, // Ignored
|
||||
.channel = channel
|
||||
};
|
||||
xQueueSend(_tone_queue, &tone_msg, portMAX_DELAY);
|
||||
@ -106,7 +109,10 @@ void noTone(uint8_t _pin){
|
||||
if(tone_init()){
|
||||
tone_msg_t tone_msg = {
|
||||
.tone_cmd = TONE_END,
|
||||
.pin = _pin
|
||||
.pin = _pin,
|
||||
.frequency = 0, // Ignored
|
||||
.duration = 0, // Ignored
|
||||
.channel = 0 // Ignored
|
||||
};
|
||||
xQueueSend(_tone_queue, &tone_msg, portMAX_DELAY);
|
||||
}
|
||||
@ -118,13 +124,14 @@ void noTone(uint8_t _pin){
|
||||
// duration - time in ms - how long will the signal be outputted.
|
||||
// If not provided, or 0 you must manually call noTone to end output
|
||||
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){
|
||||
log_d("_pin=%d, frequency=%u Hz, duration=%u ms", _pin, frequency, duration);
|
||||
log_d("_pin=%d, frequency=%u Hz, duration=%lu ms", _pin, frequency, duration);
|
||||
if(tone_init()){
|
||||
tone_msg_t tone_msg = {
|
||||
.tone_cmd = TONE_START,
|
||||
.pin = _pin,
|
||||
.frequency = frequency,
|
||||
.duration = duration
|
||||
.duration = duration,
|
||||
.channel = 0 // Ignored
|
||||
};
|
||||
xQueueSend(_tone_queue, &tone_msg, portMAX_DELAY);
|
||||
}
|
||||
|
@ -137,6 +137,24 @@ String::String(double value, unsigned int decimalPlaces) {
|
||||
}
|
||||
}
|
||||
|
||||
String::String(long long value, unsigned char base) {
|
||||
init();
|
||||
char buf[2 + 8 * sizeof(long long)];
|
||||
if (base==10) {
|
||||
sprintf(buf, "%lld", value); // NOT SURE - NewLib Nano ... does it support %lld?
|
||||
} else {
|
||||
lltoa(value, buf, base);
|
||||
}
|
||||
*this = buf;
|
||||
}
|
||||
|
||||
String::String(unsigned long long value, unsigned char base) {
|
||||
init();
|
||||
char buf[1 + 8 * sizeof(unsigned long long)];
|
||||
ulltoa(value, buf, base);
|
||||
*this = buf;
|
||||
}
|
||||
|
||||
String::~String() {
|
||||
invalidate();
|
||||
}
|
||||
@ -408,6 +426,17 @@ unsigned char String::concat(double num) {
|
||||
return concat(string, strlen(string));
|
||||
}
|
||||
|
||||
unsigned char String::concat(long long num) {
|
||||
char buf[2 + 3 * sizeof(long long)];
|
||||
return concat(buf, sprintf(buf, "%lld", num)); // NOT SURE - NewLib Nano ... does it support %lld?
|
||||
}
|
||||
|
||||
unsigned char String::concat(unsigned long long num) {
|
||||
char buf[1 + 3 * sizeof(unsigned long long)];
|
||||
ulltoa(num, buf, 10);
|
||||
return concat(buf, strlen(buf));
|
||||
}
|
||||
|
||||
unsigned char String::concat(const __FlashStringHelper * str) {
|
||||
if (!str) return 0;
|
||||
int length = strlen_P((PGM_P)str);
|
||||
@ -493,6 +522,20 @@ StringSumHelper & operator +(const StringSumHelper &lhs, double num) {
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator +(const StringSumHelper &lhs, long long num) {
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if(!a.concat(num))
|
||||
a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator +(const StringSumHelper &lhs, unsigned long long num) {
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if(!a.concat(num))
|
||||
a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
|
@ -73,6 +73,8 @@ class String {
|
||||
explicit String(unsigned long, unsigned char base = 10);
|
||||
explicit String(float, unsigned int decimalPlaces = 2);
|
||||
explicit String(double, unsigned int decimalPlaces = 2);
|
||||
explicit String(long long, unsigned char base = 10);
|
||||
explicit String(unsigned long long, unsigned char base = 10);
|
||||
~String(void);
|
||||
|
||||
// memory management
|
||||
@ -122,6 +124,8 @@ class String {
|
||||
unsigned char concat(unsigned long num);
|
||||
unsigned char concat(float num);
|
||||
unsigned char concat(double num);
|
||||
unsigned char concat(long long num);
|
||||
unsigned char concat(unsigned long long num);
|
||||
unsigned char concat(const __FlashStringHelper * str);
|
||||
|
||||
// if there's not enough memory for the concatenated value, the string
|
||||
@ -166,6 +170,14 @@ class String {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(long long num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator +=(unsigned long long num) {
|
||||
concat(num);
|
||||
return (*this);
|
||||
}
|
||||
String & operator += (const __FlashStringHelper *str){
|
||||
concat(str);
|
||||
return (*this);
|
||||
@ -182,6 +194,8 @@ class String {
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, float num);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, double num);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, const __FlashStringHelper *rhs);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, long long num);
|
||||
friend StringSumHelper & operator +(const StringSumHelper &lhs, unsigned long long num);
|
||||
|
||||
// comparison (only works w/ Strings and "strings")
|
||||
operator StringIfHelperType() const {
|
||||
@ -373,6 +387,12 @@ class StringSumHelper: public String {
|
||||
StringSumHelper(double num) :
|
||||
String(num) {
|
||||
}
|
||||
StringSumHelper(long long num) :
|
||||
String(num) {
|
||||
}
|
||||
StringSumHelper(unsigned long long num) :
|
||||
String(num) {
|
||||
}
|
||||
};
|
||||
|
||||
extern const String emptyString;
|
||||
|
@ -13,43 +13,16 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include "esp32-hal-adc.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_attr.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "driver/adc.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp_adc_cal.h"
|
||||
|
||||
#if SOC_DAC_SUPPORTED //ESP32, ESP32S2
|
||||
#include "soc/dac_channel.h"
|
||||
#include "soc/sens_reg.h"
|
||||
#include "soc/rtc_io_reg.h"
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "soc/dac_channel.h"
|
||||
#endif
|
||||
|
||||
#define DEFAULT_VREF 1100
|
||||
static esp_adc_cal_characteristics_t *__analogCharacteristics[2] = {NULL, NULL};
|
||||
static uint16_t __analogVRef = 0;
|
||||
static uint8_t __analogVRefPin = 0;
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/ets_sys.h"
|
||||
#include "soc/sens_reg.h"
|
||||
#include "soc/rtc_io_reg.h"
|
||||
#include "soc/dac_channel.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "esp32s3/rom/ets_sys.h"
|
||||
#include "soc/sens_reg.h"
|
||||
#include "soc/rtc_io_reg.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#include "esp32c3/rom/ets_sys.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_intr.h"
|
||||
#endif
|
||||
|
||||
static uint8_t __analogAttenuation = 3;//11db
|
||||
static uint8_t __analogWidth = ADC_WIDTH_MAX - 1; //3 for ESP32/ESP32C3; 4 for ESP32S2
|
||||
@ -57,6 +30,11 @@ static uint8_t __analogReturnedWidth = SOC_ADC_MAX_BITWIDTH; //12 for ESP32/ESP3
|
||||
static uint8_t __analogClockDiv = 1;
|
||||
static adc_attenuation_t __pin_attenuation[SOC_GPIO_PIN_COUNT];
|
||||
|
||||
static uint16_t __analogVRef = 0;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
static uint8_t __analogVRefPin = 0;
|
||||
#endif
|
||||
|
||||
static inline uint16_t mapResolution(uint16_t value)
|
||||
{
|
||||
uint8_t from = __analogWidth + 9;
|
||||
@ -117,8 +95,8 @@ void __analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation)
|
||||
if(channel < 0 || attenuation > 3){
|
||||
return ;
|
||||
}
|
||||
if(channel > 9){
|
||||
adc2_config_channel_atten(channel - 10, attenuation);
|
||||
if(channel > (SOC_ADC_MAX_CHANNEL_NUM - 1)){
|
||||
adc2_config_channel_atten(channel - SOC_ADC_MAX_CHANNEL_NUM, attenuation);
|
||||
} else {
|
||||
adc1_config_channel_atten(channel, attenuation);
|
||||
}
|
||||
@ -181,8 +159,8 @@ uint16_t __analogRead(uint8_t pin)
|
||||
return value;
|
||||
}
|
||||
__adcAttachPin(pin);
|
||||
if(channel > 9){
|
||||
channel -= 10;
|
||||
if(channel > (SOC_ADC_MAX_CHANNEL_NUM - 1)){
|
||||
channel -= SOC_ADC_MAX_CHANNEL_NUM;
|
||||
r = adc2_get_raw( channel, __analogWidth, &value);
|
||||
if ( r == ESP_OK ) {
|
||||
return mapResolution(value);
|
||||
@ -206,7 +184,7 @@ uint32_t __analogReadMilliVolts(uint8_t pin){
|
||||
log_e("Pin %u is not ADC pin!", pin);
|
||||
return 0;
|
||||
}
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
|
||||
if(!__analogVRef){
|
||||
if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) {
|
||||
log_d("eFuse Two Point: Supported");
|
||||
@ -218,6 +196,8 @@ uint32_t __analogReadMilliVolts(uint8_t pin){
|
||||
}
|
||||
if(!__analogVRef){
|
||||
__analogVRef = DEFAULT_VREF;
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
if(__analogVRefPin){
|
||||
esp_adc_cal_characteristics_t chars;
|
||||
if(adc_vref_to_gpio(ADC_UNIT_2, __analogVRefPin) == ESP_OK){
|
||||
@ -227,42 +207,44 @@ uint32_t __analogReadMilliVolts(uint8_t pin){
|
||||
log_d("Vref to GPIO%u: %u", __analogVRefPin, __analogVRef);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
uint8_t unit = 1;
|
||||
if(channel > 9){
|
||||
if(channel > (SOC_ADC_MAX_CHANNEL_NUM - 1)){
|
||||
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]);
|
||||
|
||||
uint8_t atten = __analogAttenuation;
|
||||
if (__pin_attenuation[pin] != ADC_ATTENDB_MAX){
|
||||
atten = __pin_attenuation[pin];
|
||||
}
|
||||
|
||||
esp_adc_cal_characteristics_t chars = {};
|
||||
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, __analogWidth, __analogVRef, &chars);
|
||||
|
||||
static bool print_chars_info = true;
|
||||
if(print_chars_info)
|
||||
{
|
||||
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);
|
||||
log_i("ADC%u: Characterized using Two Point Value: %u\n", unit, chars.vref);
|
||||
}
|
||||
else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
|
||||
log_i("ADC%u: Characterized using eFuse Vref: %u\n", unit, chars.vref);
|
||||
}
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
else if(__analogVRef != DEFAULT_VREF){
|
||||
log_i("ADC%u: Characterized using Vref to GPIO%u: %u\n", unit, __analogVRefPin, chars.vref);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
log_i("ADC%u: Characterized using Default Vref: %u\n", unit, chars.vref);
|
||||
}
|
||||
print_chars_info = false;
|
||||
}
|
||||
return esp_adc_cal_raw_to_voltage(adc_reading, __analogCharacteristics[unit - 1]);
|
||||
#else
|
||||
uint16_t adc_reading = __analogRead(pin);
|
||||
uint16_t max_reading = 8191;
|
||||
uint16_t max_mv = 1100;
|
||||
switch(__analogAttenuation){
|
||||
case 3: max_mv = 3900; break;
|
||||
case 2: max_mv = 2200; break;
|
||||
case 1: max_mv = 1500; break;
|
||||
default: break;
|
||||
}
|
||||
return (adc_reading * max_mv) / max_reading;
|
||||
#endif
|
||||
return esp_adc_cal_raw_to_voltage((uint32_t)adc_reading, &chars);
|
||||
}
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
@ -297,4 +279,3 @@ extern void analogSetVRefPin(uint8_t pin) __attribute__ ((weak, alias("__analogS
|
||||
extern void analogSetWidth(uint8_t bits) __attribute__ ((weak, alias("__analogSetWidth")));
|
||||
extern int hallRead() __attribute__ ((weak, alias("__hallRead")));
|
||||
#endif
|
||||
|
||||
|
@ -107,7 +107,7 @@ bool addApbChangeCallback(void * arg, apb_change_cb_t cb){
|
||||
// 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);
|
||||
log_e("duplicate func=%8p arg=%8p",c->cb,c->arg);
|
||||
free(c);
|
||||
xSemaphoreGive(apb_change_lock);
|
||||
return false;
|
||||
@ -129,7 +129,7 @@ bool removeApbChangeCallback(void * arg, apb_change_cb_t cb){
|
||||
// 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);
|
||||
log_e("not found func=%8p arg=%8p",cb,arg);
|
||||
xSemaphoreGive(apb_change_lock);
|
||||
return false;
|
||||
}
|
||||
|
@ -91,30 +91,34 @@ static InterruptHandle_t __pinInterruptHandlers[SOC_GPIO_PIN_COUNT] = {0,};
|
||||
|
||||
extern void ARDUINO_ISR_ATTR __pinMode(uint8_t pin, uint8_t mode)
|
||||
{
|
||||
if (!GPIO_IS_VALID_GPIO(pin)) {
|
||||
if (!GPIO_IS_VALID_GPIO(pin)) {
|
||||
log_e("Invalid pin selected");
|
||||
return;
|
||||
}
|
||||
gpio_config_t conf = {
|
||||
.pin_bit_mask = (1ULL<<pin), /*!< GPIO pin: set with bit mask, each bit maps to a GPIO */
|
||||
.mode = GPIO_MODE_DISABLE, /*!< GPIO mode: set input/output mode */
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE, /*!< GPIO pull-up */
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE, /*!< GPIO pull-down */
|
||||
.intr_type = GPIO_INTR_DISABLE /*!< GPIO interrupt type */
|
||||
};
|
||||
if (mode < 0x20) {//io
|
||||
conf.mode = mode & (INPUT | OUTPUT);
|
||||
if (mode & OPEN_DRAIN) {
|
||||
conf.mode |= GPIO_MODE_DEF_OD;
|
||||
}
|
||||
if (mode & PULLUP) {
|
||||
conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
}
|
||||
if (mode & PULLDOWN) {
|
||||
conf.pull_down_en = GPIO_PULLDOWN_ENABLE;
|
||||
}
|
||||
}
|
||||
if(gpio_config(&conf) != ESP_OK)
|
||||
return;
|
||||
}
|
||||
|
||||
gpio_hal_context_t gpiohal;
|
||||
gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0);
|
||||
|
||||
gpio_config_t conf = {
|
||||
.pin_bit_mask = (1ULL<<pin), /*!< GPIO pin: set with bit mask, each bit maps to a GPIO */
|
||||
.mode = GPIO_MODE_DISABLE, /*!< GPIO mode: set input/output mode */
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE, /*!< GPIO pull-up */
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE, /*!< GPIO pull-down */
|
||||
.intr_type = gpiohal.dev->pin[pin].int_type /*!< GPIO interrupt type - previously set */
|
||||
};
|
||||
if (mode < 0x20) {//io
|
||||
conf.mode = mode & (INPUT | OUTPUT);
|
||||
if (mode & OPEN_DRAIN) {
|
||||
conf.mode |= GPIO_MODE_DEF_OD;
|
||||
}
|
||||
if (mode & PULLUP) {
|
||||
conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
}
|
||||
if (mode & PULLDOWN) {
|
||||
conf.pull_down_en = GPIO_PULLDOWN_ENABLE;
|
||||
}
|
||||
}
|
||||
if(gpio_config(&conf) != ESP_OK)
|
||||
{
|
||||
log_e("GPIO config failed");
|
||||
return;
|
||||
|
@ -42,20 +42,15 @@ extern "C" {
|
||||
|
||||
//GPIO FUNCTIONS
|
||||
#define INPUT 0x01
|
||||
#define OUTPUT 0x02
|
||||
// Changed OUTPUT from 0x02 to behave the same as Arduino pinMode(pin,OUTPUT)
|
||||
// where you can read the state of pin even when it is set as OUTPUT
|
||||
#define OUTPUT 0x03
|
||||
#define PULLUP 0x04
|
||||
#define INPUT_PULLUP 0x05
|
||||
#define PULLDOWN 0x08
|
||||
#define INPUT_PULLDOWN 0x09
|
||||
#define OPEN_DRAIN 0x10
|
||||
#define OUTPUT_OPEN_DRAIN 0x12
|
||||
#define SPECIAL 0xF0
|
||||
#define FUNCTION_1 0x00
|
||||
#define FUNCTION_2 0x20
|
||||
#define FUNCTION_3 0x40
|
||||
#define FUNCTION_4 0x60
|
||||
#define FUNCTION_5 0x80
|
||||
#define FUNCTION_6 0xA0
|
||||
#define ANALOG 0xC0
|
||||
|
||||
//Interrupt Modes
|
||||
|
@ -695,7 +695,6 @@ static void i2c_slave_isr_handler(void* arg)
|
||||
uint32_t activeInt = i2c_ll_get_intsts_mask(i2c->dev);
|
||||
i2c_ll_clr_intsts_mask(i2c->dev, activeInt);
|
||||
uint8_t rx_fifo_len = i2c_ll_get_rxfifo_cnt(i2c->dev);
|
||||
uint8_t tx_fifo_len = SOC_I2C_FIFO_LEN - i2c_ll_get_txfifo_len(i2c->dev);
|
||||
bool slave_rw = i2c_ll_slave_rw(i2c->dev);
|
||||
|
||||
if(activeInt & I2C_RXFIFO_WM_INT_ENA){ // RX FiFo Full
|
||||
@ -719,10 +718,12 @@ static void i2c_slave_isr_handler(void* arg)
|
||||
}
|
||||
if(slave_rw){ // READ
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
//SEND TX Event
|
||||
i2c_slave_queue_event_t event;
|
||||
event.event = I2C_SLAVE_EVT_TX;
|
||||
pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event);
|
||||
if(i2c->dev->status_reg.scl_main_state_last == 6){
|
||||
//SEND TX Event
|
||||
i2c_slave_queue_event_t event;
|
||||
event.event = I2C_SLAVE_EVT_TX;
|
||||
pxHigherPriorityTaskWoken |= i2c_slave_send_event(i2c, &event);
|
||||
}
|
||||
#else
|
||||
//reset TX data
|
||||
i2c_ll_txfifo_rst(i2c->dev);
|
||||
|
@ -317,6 +317,8 @@ esp_err_t i2cSetClock(uint8_t i2c_num, uint32_t frequency){
|
||||
hal.dev = I2C_LL_GET_HW(i2c_num);
|
||||
i2c_hal_set_bus_timing(&(hal), frequency, src_clk);
|
||||
bus[i2c_num].frequency = frequency;
|
||||
//Clock Stretching Timeout: 20b:esp32, 5b:esp32-c3, 24b:esp32-s2
|
||||
i2c_set_timeout((i2c_port_t)i2c_num, I2C_LL_MAX_TIMEOUT);
|
||||
}
|
||||
|
||||
end:
|
||||
|
@ -54,7 +54,7 @@
|
||||
|
||||
uint8_t channels_resolution[LEDC_CHANNELS] = {0};
|
||||
|
||||
double ledcSetup(uint8_t chan, double freq, uint8_t bit_num)
|
||||
uint32_t ledcSetup(uint8_t chan, uint32_t freq, uint8_t bit_num)
|
||||
{
|
||||
if(chan >= LEDC_CHANNELS || bit_num > LEDC_MAX_BIT_WIDTH){
|
||||
log_e("No more LEDC channels available! (maximum %u) or bit width too big (maximum %u)", LEDC_CHANNELS, LEDC_MAX_BIT_WIDTH);
|
||||
@ -106,7 +106,7 @@ uint32_t ledcRead(uint8_t chan)
|
||||
return ledc_get_duty(group,channel);
|
||||
}
|
||||
|
||||
double ledcReadFreq(uint8_t chan)
|
||||
uint32_t ledcReadFreq(uint8_t chan)
|
||||
{
|
||||
if(!ledcRead(chan)){
|
||||
return 0;
|
||||
@ -115,7 +115,7 @@ double ledcReadFreq(uint8_t chan)
|
||||
return ledc_get_freq(group,timer);
|
||||
}
|
||||
|
||||
double ledcWriteTone(uint8_t chan, double freq)
|
||||
uint32_t ledcWriteTone(uint8_t chan, uint32_t freq)
|
||||
{
|
||||
if(chan >= LEDC_CHANNELS){
|
||||
return 0;
|
||||
@ -142,12 +142,12 @@ double ledcWriteTone(uint8_t chan, double freq)
|
||||
}
|
||||
channels_resolution[chan] = 10;
|
||||
|
||||
double res_freq = ledc_get_freq(group,timer);
|
||||
uint32_t res_freq = ledc_get_freq(group,timer);
|
||||
ledcWrite(chan, 0x1FF);
|
||||
return res_freq;
|
||||
}
|
||||
|
||||
double ledcWriteNote(uint8_t chan, note_t note, uint8_t octave){
|
||||
uint32_t ledcWriteNote(uint8_t chan, note_t note, uint8_t octave){
|
||||
const uint16_t noteFrequencyBase[12] = {
|
||||
// C C# D Eb E F F# G G# A Bb B
|
||||
4186, 4435, 4699, 4978, 5274, 5588, 5920, 6272, 6645, 7040, 7459, 7902
|
||||
@ -156,7 +156,7 @@ double ledcWriteNote(uint8_t chan, note_t note, uint8_t octave){
|
||||
if(octave > 8 || note >= NOTE_MAX){
|
||||
return 0;
|
||||
}
|
||||
double noteFreq = (double)noteFrequencyBase[note] / (double)(1 << (8-octave));
|
||||
uint32_t noteFreq = (uint32_t)noteFrequencyBase[note] / (uint32_t)(1 << (8-octave));
|
||||
return ledcWriteTone(chan, noteFreq);
|
||||
}
|
||||
|
||||
@ -184,7 +184,7 @@ void ledcDetachPin(uint8_t pin)
|
||||
pinMatrixOutDetach(pin, false, false);
|
||||
}
|
||||
|
||||
double ledcChangeFrequency(uint8_t chan, double freq, uint8_t bit_num)
|
||||
uint32_t ledcChangeFrequency(uint8_t chan, uint32_t freq, uint8_t bit_num)
|
||||
{
|
||||
if(chan >= LEDC_CHANNELS || bit_num > LEDC_MAX_BIT_WIDTH){
|
||||
log_e("LEDC channel not available! (maximum %u) or bit width too big (maximum %u)", LEDC_CHANNELS, LEDC_MAX_BIT_WIDTH);
|
||||
|
@ -27,15 +27,15 @@ typedef enum {
|
||||
} note_t;
|
||||
|
||||
//channel 0-15 resolution 1-16bits freq limits depend on resolution
|
||||
double ledcSetup(uint8_t channel, double freq, uint8_t resolution_bits);
|
||||
uint32_t ledcSetup(uint8_t channel, uint32_t freq, uint8_t resolution_bits);
|
||||
void ledcWrite(uint8_t channel, uint32_t duty);
|
||||
double ledcWriteTone(uint8_t channel, double freq);
|
||||
double ledcWriteNote(uint8_t channel, note_t note, uint8_t octave);
|
||||
uint32_t ledcWriteTone(uint8_t channel, uint32_t freq);
|
||||
uint32_t ledcWriteNote(uint8_t channel, note_t note, uint8_t octave);
|
||||
uint32_t ledcRead(uint8_t channel);
|
||||
double ledcReadFreq(uint8_t channel);
|
||||
uint32_t ledcReadFreq(uint8_t channel);
|
||||
void ledcAttachPin(uint8_t pin, uint8_t channel);
|
||||
void ledcDetachPin(uint8_t pin);
|
||||
double ledcChangeFrequency(uint8_t channel, double freq, uint8_t resolution_bits);
|
||||
uint32_t ledcChangeFrequency(uint8_t channel, uint32_t freq, uint8_t resolution_bits);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -206,16 +206,16 @@ void log_print_buf(const uint8_t *b, size_t len);
|
||||
#undef ESP_EARLY_LOGD
|
||||
#undef ESP_EARLY_LOGV
|
||||
|
||||
#define ESP_LOGE(tag, ...) log_e(__VA_ARGS__)
|
||||
#define ESP_LOGW(tag, ...) log_w(__VA_ARGS__)
|
||||
#define ESP_LOGI(tag, ...) log_i(__VA_ARGS__)
|
||||
#define ESP_LOGD(tag, ...) log_d(__VA_ARGS__)
|
||||
#define ESP_LOGV(tag, ...) log_v(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGE(tag, ...) isr_log_e(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGW(tag, ...) isr_log_w(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGI(tag, ...) isr_log_i(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGD(tag, ...) isr_log_d(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGV(tag, ...) isr_log_v(__VA_ARGS__)
|
||||
#define ESP_LOGE(tag, format, ...) log_e("[%s] " format, tag, ##__VA_ARGS__)
|
||||
#define ESP_LOGW(tag, format, ...) log_w("[%s] " format, tag, ##__VA_ARGS__)
|
||||
#define ESP_LOGI(tag, format, ...) log_i("[%s] " format, tag, ##__VA_ARGS__)
|
||||
#define ESP_LOGD(tag, format, ...) log_d("[%s] " format, tag, ##__VA_ARGS__)
|
||||
#define ESP_LOGV(tag, format, ...) log_v("[%s] " format, tag, ##__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGE(tag, format, ...) isr_log_e("[%s] " format, tag, ##__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGW(tag, format, ...) isr_log_w("[%s] " format, tag, ##__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGI(tag, format, ...) isr_log_i("[%s] " format, tag, ##__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGD(tag, format, ...) isr_log_d("[%s] " format, tag, ##__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGV(tag, format, ...) isr_log_v("[%s] " format, tag, ##__VA_ARGS__)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -200,9 +200,14 @@ void initVariant() {}
|
||||
void init() __attribute__((weak));
|
||||
void init() {}
|
||||
|
||||
#ifdef CONFIG_APP_ROLLBACK_ENABLE
|
||||
bool verifyOta() __attribute__((weak));
|
||||
bool verifyOta() { return true; }
|
||||
|
||||
bool verifyRollbackLater() __attribute__((weak));
|
||||
bool verifyRollbackLater() { return false; }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_ENABLED
|
||||
//overwritten in esp32-hal-bt.c
|
||||
bool btInUse() __attribute__((weak));
|
||||
@ -212,15 +217,17 @@ bool btInUse(){ return false; }
|
||||
void initArduino()
|
||||
{
|
||||
#ifdef CONFIG_APP_ROLLBACK_ENABLE
|
||||
const esp_partition_t *running = esp_ota_get_running_partition();
|
||||
esp_ota_img_states_t ota_state;
|
||||
if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
|
||||
if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
|
||||
if (verifyOta()) {
|
||||
esp_ota_mark_app_valid_cancel_rollback();
|
||||
} else {
|
||||
log_e("OTA verification failed! Start rollback to the previous version ...");
|
||||
esp_ota_mark_app_invalid_rollback_and_reboot();
|
||||
if(!verifyRollbackLater()){
|
||||
const esp_partition_t *running = esp_ota_get_running_partition();
|
||||
esp_ota_img_states_t ota_state;
|
||||
if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
|
||||
if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
|
||||
if (verifyOta()) {
|
||||
esp_ota_mark_app_valid_cancel_rollback();
|
||||
} else {
|
||||
log_e("OTA verification failed! Start rollback to the previous version ...");
|
||||
esp_ota_mark_app_invalid_rollback_and_reboot();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,13 +32,6 @@ typedef union {
|
||||
|
||||
#define NUM_OF_TIMERS SOC_TIMER_GROUP_TOTAL_TIMERS
|
||||
|
||||
typedef struct {
|
||||
int timer_group;
|
||||
int timer_idx;
|
||||
int alarm_interval;
|
||||
bool auto_reload;
|
||||
} timer_info_t;
|
||||
|
||||
typedef struct hw_timer_s
|
||||
{
|
||||
uint8_t group;
|
||||
@ -47,7 +40,7 @@ typedef struct hw_timer_s
|
||||
|
||||
// Works for all chips
|
||||
static hw_timer_t timer_dev[4] = {
|
||||
{0,0}, {1,0}, {1,0}, {1,1}
|
||||
{0,0}, {1,0}, {0,1}, {1,1}
|
||||
};
|
||||
|
||||
// NOTE: (in IDF 5.0 there wont be need to know groups/numbers
|
||||
@ -194,7 +187,7 @@ static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb
|
||||
hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){
|
||||
if(num >= NUM_OF_TIMERS)
|
||||
{
|
||||
log_e("Timer dont have that timer number.");
|
||||
log_e("Timer number %u exceeds available number of Timers.", num);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -220,24 +213,23 @@ void timerEnd(hw_timer_t *timer){
|
||||
timer_deinit(timer->group, timer->num);
|
||||
}
|
||||
|
||||
bool IRAM_ATTR timerFnWrapper(void *arg){
|
||||
void (*fn)(void) = arg;
|
||||
fn();
|
||||
|
||||
// some additional logic or handling may be required here to approriately yield or not
|
||||
return false;
|
||||
}
|
||||
|
||||
void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){
|
||||
if(edge){
|
||||
log_w("EDGE timer interrupt is not supported! Setting to LEVEL...");
|
||||
edge = false;
|
||||
}
|
||||
timer_enable_intr(timer->group, timer->num);
|
||||
|
||||
timer_info_t *timer_info = calloc(1, sizeof(timer_info_t));
|
||||
timer_info->timer_group = timer->group;
|
||||
timer_info->timer_idx = timer->num;
|
||||
timer_info->auto_reload = timerGetAutoReload(timer);
|
||||
timer_info->alarm_interval = timerAlarmRead(timer);
|
||||
|
||||
timer_isr_callback_add(timer->group, timer->num, (timer_isr_t)fn, timer_info, 0);
|
||||
timer_isr_callback_add(timer->group, timer->num, timerFnWrapper, fn, 0);
|
||||
}
|
||||
|
||||
void timerDetachInterrupt(hw_timer_t *timer){
|
||||
timerAttachInterrupt(timer, NULL, false);
|
||||
timer_isr_callback_remove(timer->group, timer->num);
|
||||
}
|
||||
|
||||
uint64_t timerReadMicros(hw_timer_t *timer){
|
||||
|
@ -646,8 +646,9 @@ static void usb_device_task(void *param) {
|
||||
/*
|
||||
* PUBLIC API
|
||||
* */
|
||||
static const char *tinyusb_interface_names[USB_INTERFACE_MAX] = {"MSC", "DFU", "HID", "VENDOR", "CDC", "MIDI", "CUSTOM"};
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
|
||||
const char *tinyusb_interface_names[USB_INTERFACE_MAX] = {"MSC", "DFU", "HID", "VENDOR", "CDC", "MIDI", "CUSTOM"};
|
||||
#endif
|
||||
static bool tinyusb_is_initialized = false;
|
||||
|
||||
esp_err_t tinyusb_enable_interface(tinyusb_interface_t interface, uint16_t descriptor_len, tinyusb_descriptor_cb_t cb)
|
||||
|
@ -119,11 +119,6 @@ static void __touchInit()
|
||||
if (err != ESP_OK) {
|
||||
goto err;
|
||||
}
|
||||
// Initial no Threshold and setup
|
||||
for (int i = 0; i < SOC_TOUCH_SENSOR_NUM; i++) {
|
||||
__touchInterruptHandlers[i].fn = NULL;
|
||||
touch_pad_config(i, SOC_TOUCH_PAD_THRESHOLD_MAX); // returns ESP_OK
|
||||
}
|
||||
// keep ISR activated - it can run all together (ISR + touchRead())
|
||||
err = touch_pad_isr_register(__touchISR, NULL);
|
||||
if (err != ESP_OK) {
|
||||
@ -148,18 +143,7 @@ static void __touchInit()
|
||||
// Touch Sensor Timer initiated
|
||||
touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); // returns ESP_OK
|
||||
touch_pad_fsm_start(); // returns ESP_OK
|
||||
|
||||
// Initial no Threshold and setup - TOUCH0 is internal denoise channel
|
||||
for (int i = 1; i < SOC_TOUCH_SENSOR_NUM; i++) {
|
||||
__touchInterruptHandlers[i].fn = NULL;
|
||||
touch_pad_config(i); // returns ESP_OK
|
||||
}
|
||||
// keep ISR activated - it can run all together (ISR + touchRead())
|
||||
err = touch_pad_isr_register(__touchISR, NULL, TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE);
|
||||
if (err != ESP_OK) {
|
||||
goto err;
|
||||
}
|
||||
touch_pad_intr_enable(TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE); // returns ESP_OK
|
||||
//ISR setup moved to __touchChannelInit
|
||||
#endif
|
||||
|
||||
initialized = true;
|
||||
@ -170,13 +154,43 @@ err:
|
||||
return;
|
||||
}
|
||||
|
||||
static void __touchChannelInit(int pad)
|
||||
{
|
||||
static bool channels_initialized[SOC_TOUCH_SENSOR_NUM] = { false };
|
||||
if(channels_initialized[pad]){
|
||||
return;
|
||||
}
|
||||
|
||||
#if SOC_TOUCH_VERSION_1 // ESP32
|
||||
// Initial no Threshold and setup
|
||||
__touchInterruptHandlers[pad].fn = NULL;
|
||||
touch_pad_config(pad, SOC_TOUCH_PAD_THRESHOLD_MAX); // returns ESP_OK
|
||||
#elif SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3
|
||||
// Initial no Threshold and setup
|
||||
__touchInterruptHandlers[pad].fn = NULL;
|
||||
touch_pad_config(pad); // returns ESP_OK
|
||||
// keep ISR activated - it can run all together (ISR + touchRead())
|
||||
esp_err_t err = touch_pad_isr_register(__touchISR, NULL, TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE);
|
||||
if (err != ESP_OK) {
|
||||
log_e(" Touch sensor initialization error.");
|
||||
return;
|
||||
}
|
||||
touch_pad_intr_enable(TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE); // returns ESP_OK
|
||||
#endif
|
||||
|
||||
channels_initialized[pad] = true;
|
||||
delay(20); //delay needed before reading from touch channel after config
|
||||
}
|
||||
|
||||
static touch_value_t __touchRead(uint8_t pin)
|
||||
{
|
||||
int8_t pad = digitalPinToTouchChannel(pin);
|
||||
if(pad < 0){
|
||||
return 0;
|
||||
}
|
||||
|
||||
__touchInit();
|
||||
__touchChannelInit(pad);
|
||||
|
||||
touch_value_t touch_value;
|
||||
touch_pad_read_raw_data(pad, &touch_value);
|
||||
@ -198,6 +212,9 @@ static void __touchConfigInterrupt(uint8_t pin, void (*userFunc)(void), void *Ar
|
||||
} else {
|
||||
// attach ISR User Call
|
||||
__touchInit();
|
||||
#if SOC_TOUCH_VERSION_2 // ESP32S2, ESP32S3
|
||||
__touchChannelInit(pad);
|
||||
#endif
|
||||
__touchInterruptHandlers[pad].fn = userFunc;
|
||||
__touchInterruptHandlers[pad].callWithArgs = callWithArgs;
|
||||
__touchInterruptHandlers[pad].arg = Args;
|
||||
|
@ -115,7 +115,7 @@ void uartSetPins(uart_t* uart, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t
|
||||
}
|
||||
UART_MUTEX_LOCK();
|
||||
// IDF uart_set_pin() will issue necessary Error Message and take care of all GPIO Number validation.
|
||||
uart_set_pin(uart->num, txPin, rxPin, ctsPin, rtsPin);
|
||||
uart_set_pin(uart->num, txPin, rxPin, rtsPin, ctsPin);
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
@ -538,8 +538,6 @@ void uartStartDetectBaudrate(uart_t *uart) {
|
||||
return;
|
||||
}
|
||||
|
||||
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32C3
|
||||
|
||||
// ESP32-C3 requires further testing
|
||||
@ -555,6 +553,7 @@ void uartStartDetectBaudrate(uart_t *uart) {
|
||||
//hw->conf0.autobaud_en = 1;
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#else
|
||||
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
|
||||
hw->auto_baud.glitch_filt = 0x08;
|
||||
hw->auto_baud.en = 0;
|
||||
hw->auto_baud.en = 1;
|
||||
@ -571,7 +570,6 @@ uartDetectBaudrate(uart_t *uart)
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3 requires further testing - Baud rate detection returns wrong values
|
||||
|
||||
static bool uartStateDetectingBaudrate = false;
|
||||
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
|
||||
|
||||
if(!uartStateDetectingBaudrate) {
|
||||
uartStartDetectBaudrate(uart);
|
||||
@ -592,6 +590,7 @@ uartDetectBaudrate(uart_t *uart)
|
||||
//hw->conf0.autobaud_en = 0;
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#else
|
||||
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
|
||||
hw->auto_baud.en = 0;
|
||||
#endif
|
||||
uartStateDetectingBaudrate = false; // Initialize for the next round
|
||||
|
@ -23,7 +23,7 @@ extern "C" {
|
||||
/** Minor version number (x.X.x) */
|
||||
#define ESP_ARDUINO_VERSION_MINOR 0
|
||||
/** Patch version number (x.x.X) */
|
||||
#define ESP_ARDUINO_VERSION_PATCH 3
|
||||
#define ESP_ARDUINO_VERSION_PATCH 4
|
||||
|
||||
/**
|
||||
* Macro to convert ARDUINO version number into an integer
|
||||
|
@ -40,6 +40,7 @@ static int base64_decode_block_signed(const int8_t* code_in, const int length_in
|
||||
fragment = (int8_t)base64_decode_value_signed(*codechar++);
|
||||
} while (fragment < 0);
|
||||
*plainchar = (fragment & 0x03f) << 2;
|
||||
// fall through
|
||||
case step_b:
|
||||
do {
|
||||
if (codechar == code_in+length_in){
|
||||
@ -51,6 +52,7 @@ static int base64_decode_block_signed(const int8_t* code_in, const int length_in
|
||||
} while (fragment < 0);
|
||||
*plainchar++ |= (fragment & 0x030) >> 4;
|
||||
*plainchar = (fragment & 0x00f) << 4;
|
||||
// fall through
|
||||
case step_c:
|
||||
do {
|
||||
if (codechar == code_in+length_in){
|
||||
@ -62,6 +64,7 @@ static int base64_decode_block_signed(const int8_t* code_in, const int length_in
|
||||
} while (fragment < 0);
|
||||
*plainchar++ |= (fragment & 0x03c) >> 2;
|
||||
*plainchar = (fragment & 0x003) << 6;
|
||||
// fall through
|
||||
case step_d:
|
||||
do {
|
||||
if (codechar == code_in+length_in){
|
||||
|
@ -44,6 +44,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out,
|
||||
result = (fragment & 0x0fc) >> 2;
|
||||
*codechar++ = base64_encode_value(result);
|
||||
result = (fragment & 0x003) << 4;
|
||||
// fall through
|
||||
case step_B:
|
||||
if (plainchar == plaintextend) {
|
||||
state_in->result = result;
|
||||
@ -54,6 +55,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out,
|
||||
result |= (fragment & 0x0f0) >> 4;
|
||||
*codechar++ = base64_encode_value(result);
|
||||
result = (fragment & 0x00f) << 2;
|
||||
// fall through
|
||||
case step_C:
|
||||
if (plainchar == plaintextend) {
|
||||
state_in->result = result;
|
||||
|
@ -67,6 +67,31 @@ char* ltoa(long value, char* result, int base) {
|
||||
return result;
|
||||
}
|
||||
|
||||
char* lltoa (long long val, char* result, int base) {
|
||||
if(base < 2 || base > 16) {
|
||||
*result = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
char* out = result;
|
||||
long long quotient = val > 0 ? val : -val;
|
||||
|
||||
do {
|
||||
const long long tmp = quotient / base;
|
||||
*out = "0123456789abcdef"[quotient - (tmp * base)];
|
||||
++out;
|
||||
quotient = tmp;
|
||||
} while(quotient);
|
||||
|
||||
// Apply negative sign
|
||||
if(val < 0)
|
||||
*out++ = '-';
|
||||
|
||||
reverse(result, out);
|
||||
*out = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
char* ultoa(unsigned long value, char* result, int base) {
|
||||
if(base < 2 || base > 16) {
|
||||
*result = 0;
|
||||
@ -88,6 +113,27 @@ char* ultoa(unsigned long value, char* result, int base) {
|
||||
return result;
|
||||
}
|
||||
|
||||
char* ulltoa (unsigned long long val, char* result, int base) {
|
||||
if(base < 2 || base > 16) {
|
||||
*result = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
char* out = result;
|
||||
unsigned long long quotient = val;
|
||||
|
||||
do {
|
||||
const unsigned long long tmp = quotient / base;
|
||||
*out = "0123456789abcdef"[quotient - (tmp * base)];
|
||||
++out;
|
||||
quotient = tmp;
|
||||
} while(quotient);
|
||||
|
||||
reverse(result, out);
|
||||
*out = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
char * dtostrf(double number, signed int width, unsigned int prec, char *s) {
|
||||
bool negative = false;
|
||||
|
||||
@ -160,3 +206,5 @@ char * dtostrf(double number, signed int width, unsigned int prec, char *s) {
|
||||
*out = 0;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
@ -35,10 +35,14 @@ char* itoa (int val, char *s, int radix);
|
||||
|
||||
char* ltoa (long val, char *s, int radix);
|
||||
|
||||
char* lltoa (long long val, char* s, int radix);
|
||||
|
||||
char* utoa (unsigned int val, char *s, int radix);
|
||||
|
||||
char* ultoa (unsigned long val, char *s, int radix);
|
||||
|
||||
char* ulltoa (unsigned long long val, char* s, int radix);
|
||||
|
||||
char* dtostrf (double val, signed int width, unsigned int prec, char *s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -71,48 +71,70 @@ Installing using PlatformIO
|
||||
:width: 200
|
||||
:figclass: align-center
|
||||
|
||||
PlatformIO is one of most popular embedded development tool. Currently, it supports Arduino ESP32 and ESP-IDF from Espressif (other platforms are also supported).
|
||||
PlatformIO is a professional collaborative platform for embedded development. It has out-of-the-box support for ESP32 SoCs and allows working with Arduino ESP32 as well as ESP-IDF from Espressif without changing your development environment. PlatformIO includes lots of instruments for the most common development tasks such as debugging, unit testing, and static code analysis.
|
||||
|
||||
To install PIO, you can follow this Getting Started, provided by PIO at `docs.platformio.org`_.
|
||||
A detailed overview of the PlatformIO ecosystem and its philosophy can be found in `the official documentation <https://docs.platformio.org/en/latest/core/index.html>`_.
|
||||
|
||||
To test the latest Arduino ESP32, you need to change your project *platform.ini* accordingly.
|
||||
PlatformIO can be used in two flavors:
|
||||
|
||||
- Start a new project and select one of the available board. You can change after by changing the *platform.ini* file.
|
||||
- `PlatformIO IDE <https://platformio.org/platformio-ide>`_ is a toolset for embedded C/C++ development available on Windows, macOS and Linux platforms
|
||||
|
||||
- `PlatformIO Core (CLI) <https://docs.platformio.org/en/latest/core/index.html>`_ is a command-line tool that consists of a multi-platform build system, platform and library managers and other integration components. It can be used with a variety of code development environments and allows integration with cloud platforms and web services
|
||||
|
||||
To install PlatformIO, you can follow this Getting Started, provided at `docs.platformio.org`_.
|
||||
|
||||
Using the stable code
|
||||
*********************
|
||||
|
||||
.. note::
|
||||
A detailed overview of supported development boards, examples and frameworks can be found on `the official Espressif32 dev-platform page <https://registry.platformio.org/platforms/platformio/espressif32>`_ in the PlatformIO Registry.
|
||||
|
||||
The most reliable and easiest way to get started is to use the latest stable version of the ESP32 development platform that passed all tests/verifications and can be used in production.
|
||||
|
||||
Create a new project and select one of the available boards. You can change after by changing the `platformio.ini <https://docs.platformio.org/en/latest/projectconf/index.html>`_ file.
|
||||
|
||||
- For ESP32
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
[env:arduino-esp32]
|
||||
platform = https://github.com/platformio/platform-espressif32.git#feature/arduino-upstream
|
||||
[env:esp32dev]
|
||||
platform = espressif32
|
||||
board = esp32dev
|
||||
framework = arduino
|
||||
platform_packages =
|
||||
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32#master
|
||||
|
||||
- For ESP32-S2 (ESP32-S2-Saola-1 board)
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
[env:arduino-esp32s2]
|
||||
platform = https://github.com/platformio/platform-espressif32.git#feature/arduino-upstream
|
||||
[env:esp32-s2-saola-1]
|
||||
platform = espressif32
|
||||
board = esp32-s2-saola-1
|
||||
framework = arduino
|
||||
platform_packages =
|
||||
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32#master
|
||||
|
||||
- For ESP32-C3 (ESP32-S3-DevKitM-1 board)
|
||||
- For ESP32-C3 (ESP32-C3-DevKitM-1 board)
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
[env:arduino-esp32c3]
|
||||
platform = https://github.com/platformio/platform-espressif32.git#feature/arduino-upstream
|
||||
[env:esp32-c3-devkitm-1]
|
||||
platform = espressif32
|
||||
board = esp32-c3-devkitm-1
|
||||
framework = arduino
|
||||
|
||||
How to update to the latest code
|
||||
********************************
|
||||
|
||||
To test the latest Arduino ESP32, you need to change your project *platformio.ini* accordingly.
|
||||
The following configuration uses the upstream version of the Espressif development platform and the latest Arduino core directly from the Espressif GitHub repository:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
[env:esp32-c3-devkitm-1]
|
||||
platform = https://github.com/platformio/platform-espressif32.git
|
||||
board = esp32-c3-devkitm-1
|
||||
framework = arduino
|
||||
platform_packages =
|
||||
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32#master
|
||||
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32#master
|
||||
|
||||
Now you're able to use the latest Arduino ESP32 support directly from Espressif GitHub repository.
|
||||
|
||||
To get more information about PlatformIO, see the following links:
|
||||
|
||||
|
188
docs/source/tutorials/partition_table.rst
Normal file
188
docs/source/tutorials/partition_table.rst
Normal file
@ -0,0 +1,188 @@
|
||||
###############
|
||||
Partition Table
|
||||
###############
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Partition table is used to define the flash memory organization and the different kind of data will be stored on each partition.
|
||||
|
||||
You can use one of the available partition table scheme or create your own. You can see all the different schemes on the `tools/partitions <https://github.com/espressif/arduino-esp32/tree/master/tools/partitions>`_ folder or by the Arduino IDE tools menu `Tools -> Partition Scheme`.
|
||||
|
||||
The partition table is created by a .CSV (Comma-separeted Values) file with the following structure:
|
||||
|
||||
.. code-block::
|
||||
|
||||
# ESP-IDF Partition Table
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
|
||||
Where:
|
||||
|
||||
1. **Name**
|
||||
|
||||
Is the partition name and must be a unique name. This name is not relevant for the system and the size must be at maximum of 16-chars (no special chars).
|
||||
|
||||
2. **Type**
|
||||
|
||||
This is the type of the partition. This value can be ``data`` or ``app``.
|
||||
|
||||
* ``app`` type is used to define the partition that will store the application.
|
||||
|
||||
* ``data`` type can be used to define the partition that stores general data, not the application.
|
||||
|
||||
3. **SubType**
|
||||
|
||||
The SubType defines the usage of the ``app`` and ``data`` partitions.
|
||||
|
||||
**data**
|
||||
|
||||
``ota``
|
||||
|
||||
The ota subtype is used to store the OTA information. This partition is used only when the OTA is used to select the initialization partition, otherwise no need to add it to your custom partition table.
|
||||
The size of this partition should be a fixed size of 8kB (0x2000 bytes).
|
||||
|
||||
``nvs``
|
||||
|
||||
The nvs partition subtype is used to define the partition to store general data, like the WiFi data, device PHY calibration data and any other data to be stored on the non-volatile memory.
|
||||
This kind of partition is suitable for small custom configuration data, cloud certificates, etc. Another usage for the NVS is to store sensitive data, since the NVS supports encryption.
|
||||
It is highly recommended to add at least one nvs partition, labeled with the name nvs, in your custom partition tables with size of at least 12kB (0x3000 bytes). If needed, you can increase the size of the nvs partition.
|
||||
The recommended size for this partition is from 12kb to 64kb. Although larger NVS partitions can be defined, we recommend using FAT or SPIFFS filesystem for storage of larger amounts of data.
|
||||
|
||||
``coredump``
|
||||
|
||||
The coredump partition subtype is used to store the core dump on the flash. The core dump is used to analyze critical errors like crash and panic.
|
||||
This function must be enabled in the project configuration menu and set the data destination to flash.
|
||||
The recommended size for this partition is 64kB (0x10000).
|
||||
|
||||
``nvs_keys``
|
||||
|
||||
The nvs_keys partition subtype is used to store the keys when the NVS encryption is used.
|
||||
The size for this partition is 4kB (0x1000).
|
||||
|
||||
``fat``
|
||||
|
||||
The fat partition subtype defines the FAT filesystem usage, and it is suitable for larger data and if this data is often updated and changed. The FAT FS can be used with wear leveling feature to increase the erase/modification cycles per memory sector and encryption for sensitive data storage, like cloud certificates or any other data that may be protected.
|
||||
To use FAT FS with wear leveling see the example.
|
||||
|
||||
``spiffs``
|
||||
|
||||
The spiffs partition subtype defines the SPI flash filesystem usage, and it is also suitable for larger files and it also performs the wear leveling and file system consistency check.
|
||||
The SPIFFS do not support flash encryption.
|
||||
|
||||
**app**
|
||||
|
||||
``factory``
|
||||
|
||||
The factory partition subtype is the default application. The bootloader will set this partition as the default application initialization if no OTA partition is found, or the OTA partitions are empty.
|
||||
If the OTA partition is used, the ota_0 can be used as the default application and the factory can be removed from the partition table to save memory space.
|
||||
|
||||
``ota_0`` to ``ota_15``
|
||||
|
||||
The ota_x partition subtype is used for the Over-the air update. The OTA feature requires at least two ota_x partition (usually ota_0 and ota_1) and it also requires the ota partition to keep the OTA information data.
|
||||
Up to 16 OTA partitions can be defined but only two are needed for basic OTA feature.
|
||||
|
||||
``test``
|
||||
|
||||
The test partition subtype is used for factory test procedures.
|
||||
|
||||
4. **Offset**
|
||||
|
||||
The offset defines the partition start address. The offset is defined by the sum of the offset and the size of the earlier partition.
|
||||
|
||||
.. note::
|
||||
Offset must be multiple of 4kB (0x1000) and for app partitions it must be aligned by 64kB (0x10000).
|
||||
If left blank, the offset will be automatically calculated based on the end of the previous partition, including any necessary alignment, however, the offset for the first partition must be always set as **0x9000** and for the first application partition **0x10000**.
|
||||
|
||||
5. **Size**
|
||||
|
||||
Size defines the amount of memory to be allocated on the partition. The size can be formatted as decimal, hex numbers (0x prefix), or using unit prefix K (kilo) or M (mega) i.e: 4096 = 4K = 0x1000.
|
||||
|
||||
6. **Flags**
|
||||
|
||||
The last column in the CSV file is the flags and it is currently used to define if the partition will be encrypted by the flash encryption feature.
|
||||
|
||||
|
||||
For example, **the most common partition** is the ``default_8MB.csv`` (see `tools/partitions <https://github.com/espressif/arduino-esp32/tree/master/tools/partitions>`_ folder for some examples):
|
||||
|
||||
.. code-block::
|
||||
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x330000,
|
||||
app1, app, ota_1, 0x340000,0x330000,
|
||||
spiffs, data, spiffs, 0x670000,0x190000,
|
||||
|
||||
Using a Custom Partition Scheme
|
||||
-------------------------------
|
||||
|
||||
To create your own partition table, you can create the ``partitions.csv`` file **in the same folder you created your sketch**. The build system will automatically pick the partition table file and use it instead of the predefined ones.
|
||||
|
||||
Here is an example you can use for a custom partition table:
|
||||
|
||||
.. code-block::
|
||||
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 36K, 20K,
|
||||
otadata, data, ota, 56K, 8K,
|
||||
app0, app, ota_0, 64K, 2M,
|
||||
app1, app, ota_1, , 2M,
|
||||
spiffs, data, spiffs, , 8M,
|
||||
|
||||
This partition will use about 12MB of the 16MB flash. The offset will be automatically calculated after the first application partition and the units are in K and M.
|
||||
|
||||
A alternative is to create the new partition table as a new file in the `tools/partitions <https://github.com/espressif/arduino-esp32/tree/master/tools/partitions>`_ folder and edit the `boards.txt <https://github.com/espressif/arduino-esp32/tree/master/boards.txt>`_ file to add your custom partition table.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
**2MB no OTA**
|
||||
|
||||
.. code-block::
|
||||
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 36K, 20K,
|
||||
factory, app, factory, 64K, 1900K,
|
||||
|
||||
**4MB no OTA**
|
||||
|
||||
.. code-block::
|
||||
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 36K, 20K,
|
||||
factory, app, factory, 64K, 4000K,
|
||||
|
||||
**4MB with OTA**
|
||||
|
||||
.. code-block::
|
||||
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 36K, 20K,
|
||||
otadata, data, ota, 56K, 8K,
|
||||
app0, app, ota_0, 64K, 1900K,
|
||||
app1, app, ota_1, , 1900K,
|
||||
|
||||
**8MB no OTA with Storage**
|
||||
|
||||
.. code-block::
|
||||
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 36K, 20K,
|
||||
factory, app, factory, 64K, 2M,
|
||||
spiffs, data, spiffs, , 5M,
|
||||
|
||||
**8MB with OTA and Storage**
|
||||
|
||||
.. code-block::
|
||||
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 36K, 20K,
|
||||
otadata, data, ota, 56K, 8K,
|
||||
app0, app, ota_0, 64K, 2M,
|
||||
app1, app, ota_1, , 2M,
|
||||
spiffs, data, spiffs, , 3M,
|
||||
|
||||
Reference
|
||||
---------
|
||||
|
||||
This documentation was based on the `How to use custom partition tables on ESP32 <https://medium.com/p/69c0f3fa89c8>`_ article.
|
@ -7,7 +7,6 @@
|
||||
#include "Stream.h"
|
||||
#include <functional>
|
||||
extern "C" {
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "esp_netif.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
@ -71,7 +71,7 @@ bool BLEAddress::operator!=(const BLEAddress& otherAddress) const {
|
||||
}
|
||||
|
||||
bool BLEAddress::operator<(const BLEAddress& otherAddress) const {
|
||||
return memcmp(otherAddress.m_address, m_address, ESP_BD_ADDR_LEN) < 0;
|
||||
return memcmp(m_address, otherAddress.m_address, ESP_BD_ADDR_LEN) < 0;
|
||||
}
|
||||
|
||||
bool BLEAddress::operator<=(const BLEAddress& otherAddress) const {
|
||||
@ -83,7 +83,7 @@ bool BLEAddress::operator>=(const BLEAddress& otherAddress) const {
|
||||
}
|
||||
|
||||
bool BLEAddress::operator>(const BLEAddress& otherAddress) const {
|
||||
return memcmp(otherAddress.m_address, m_address, ESP_BD_ADDR_LEN) > 0;
|
||||
return memcmp(m_address, otherAddress.m_address, ESP_BD_ADDR_LEN) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,114 @@
|
||||
/**
|
||||
* Bluetooth Classic Example
|
||||
* Scan for devices - asyncronously, print device as soon as found
|
||||
* query devices for SPP - SDP profile
|
||||
* connect to first device offering a SPP connection
|
||||
*
|
||||
* Example python server:
|
||||
* source: https://gist.github.com/ukBaz/217875c83c2535d22a16ba38fc8f2a91
|
||||
*
|
||||
* Tested with Raspberry Pi onboard Wifi/BT, USB BT 4.0 dongles, USB BT 1.1 dongles,
|
||||
* 202202: does NOT work with USB BT 2.0 dongles when esp32 aduino lib is compiled with SSP support!
|
||||
* see https://github.com/espressif/esp-idf/issues/8394
|
||||
*
|
||||
* use ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE in connect() if remote side requests 'RequireAuthentication': dbus.Boolean(True),
|
||||
* use ESP_SPP_SEC_NONE or ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE in connect() if remote side has Authentication: False
|
||||
*/
|
||||
|
||||
#include <map>
|
||||
#include <BluetoothSerial.h>
|
||||
|
||||
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
|
||||
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_BT_SPP_ENABLED)
|
||||
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
|
||||
#endif
|
||||
|
||||
BluetoothSerial SerialBT;
|
||||
|
||||
|
||||
#define BT_DISCOVER_TIME 10000
|
||||
esp_spp_sec_t sec_mask=ESP_SPP_SEC_NONE; // or ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE to request pincode confirmation
|
||||
esp_spp_role_t role=ESP_SPP_ROLE_SLAVE; // or ESP_SPP_ROLE_MASTER
|
||||
|
||||
// std::map<BTAddress, BTAdvertisedDeviceSet> btDeviceList;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
if(! SerialBT.begin("ESP32test", true) ) {
|
||||
Serial.println("========== serialBT failed!");
|
||||
abort();
|
||||
}
|
||||
// SerialBT.setPin("1234"); // doesn't seem to change anything
|
||||
// SerialBT.enableSSP(); // doesn't seem to change anything
|
||||
|
||||
|
||||
Serial.println("Starting discoverAsync...");
|
||||
BTScanResults* btDeviceList = SerialBT.getScanResults(); // maybe accessing from different threads!
|
||||
if (SerialBT.discoverAsync([](BTAdvertisedDevice* pDevice) {
|
||||
// BTAdvertisedDeviceSet*set = reinterpret_cast<BTAdvertisedDeviceSet*>(pDevice);
|
||||
// btDeviceList[pDevice->getAddress()] = * set;
|
||||
Serial.printf(">>>>>>>>>>>Found a new device asynchronously: %s\n", pDevice->toString().c_str());
|
||||
} )
|
||||
) {
|
||||
delay(BT_DISCOVER_TIME);
|
||||
Serial.print("Stopping discoverAsync... ");
|
||||
SerialBT.discoverAsyncStop();
|
||||
Serial.println("discoverAsync stopped");
|
||||
delay(5000);
|
||||
if(btDeviceList->getCount() > 0) {
|
||||
BTAddress addr;
|
||||
int channel=0;
|
||||
Serial.println("Found devices:");
|
||||
for (int i=0; i < btDeviceList->getCount(); i++) {
|
||||
BTAdvertisedDevice *device=btDeviceList->getDevice(i);
|
||||
Serial.printf(" ----- %s %s %d\n", device->getAddress().toString().c_str(), device->getName().c_str(), device->getRSSI());
|
||||
std::map<int,std::string> channels=SerialBT.getChannels(device->getAddress());
|
||||
Serial.printf("scanned for services, found %d\n", channels.size());
|
||||
for(auto const &entry : channels) {
|
||||
Serial.printf(" channel %d (%s)\n", entry.first, entry.second.c_str());
|
||||
}
|
||||
if(channels.size() > 0) {
|
||||
addr = device->getAddress();
|
||||
channel=channels.begin()->first;
|
||||
}
|
||||
}
|
||||
if(addr) {
|
||||
Serial.printf("connecting to %s - %d\n", addr.toString().c_str(), channel);
|
||||
SerialBT.connect(addr, channel, sec_mask, role);
|
||||
}
|
||||
} else {
|
||||
Serial.println("Didn't find any devices");
|
||||
}
|
||||
} else {
|
||||
Serial.println("Error on discoverAsync f.e. not workin after a \"connect\"");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String sendData="Hi from esp32!\n";
|
||||
|
||||
void loop() {
|
||||
if(! SerialBT.isClosed() && SerialBT.connected()) {
|
||||
if( SerialBT.write((const uint8_t*) sendData.c_str(),sendData.length()) != sendData.length()) {
|
||||
Serial.println("tx: error");
|
||||
} else {
|
||||
Serial.printf("tx: %s",sendData.c_str());
|
||||
}
|
||||
if(SerialBT.available()) {
|
||||
Serial.print("rx: ");
|
||||
while(SerialBT.available()) {
|
||||
int c=SerialBT.read();
|
||||
if(c >= 0) {
|
||||
Serial.print((char) c);
|
||||
}
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
} else {
|
||||
Serial.println("not connected");
|
||||
}
|
||||
delay(1000);
|
||||
}
|
@ -29,6 +29,9 @@ BTAddress::BTAddress(esp_bd_addr_t address) {
|
||||
memcpy(m_address, address, ESP_BD_ADDR_LEN);
|
||||
} // BTAddress
|
||||
|
||||
BTAddress::BTAddress() {
|
||||
bzero(m_address, ESP_BD_ADDR_LEN);
|
||||
} // BTAddress
|
||||
|
||||
/**
|
||||
* @brief Create an address from a hex string
|
||||
@ -64,13 +67,20 @@ bool BTAddress::equals(BTAddress otherAddress) {
|
||||
return memcmp(otherAddress.getNative(), m_address, 6) == 0;
|
||||
} // equals
|
||||
|
||||
BTAddress::operator bool () const {
|
||||
for(int i = 0; i < ESP_BD_ADDR_LEN; i++){
|
||||
if(this->m_address[i])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} // operator ()
|
||||
|
||||
/**
|
||||
* @brief Return the native representation of the address.
|
||||
* @return The native representation of the address.
|
||||
*/
|
||||
esp_bd_addr_t *BTAddress::getNative() {
|
||||
return &m_address;
|
||||
esp_bd_addr_t *BTAddress::getNative() const {
|
||||
return const_cast<esp_bd_addr_t *>(&m_address);
|
||||
} // getNative
|
||||
|
||||
|
||||
@ -85,7 +95,7 @@ esp_bd_addr_t *BTAddress::getNative() {
|
||||
*
|
||||
* @return The string representation of the address.
|
||||
*/
|
||||
std::string BTAddress::toString() {
|
||||
std::string BTAddress::toString() const {
|
||||
auto size = 18;
|
||||
char *res = (char*)malloc(size);
|
||||
snprintf(res, size, "%02x:%02x:%02x:%02x:%02x:%02x", m_address[0], m_address[1], m_address[2], m_address[3], m_address[4], m_address[5]);
|
||||
|
@ -22,11 +22,14 @@
|
||||
*/
|
||||
class BTAddress {
|
||||
public:
|
||||
BTAddress();
|
||||
BTAddress(esp_bd_addr_t address);
|
||||
BTAddress(std::string stringAddress);
|
||||
bool equals(BTAddress otherAddress);
|
||||
esp_bd_addr_t* getNative();
|
||||
std::string toString();
|
||||
operator bool () const;
|
||||
|
||||
esp_bd_addr_t* getNative() const;
|
||||
std::string toString() const;
|
||||
|
||||
private:
|
||||
esp_bd_addr_t m_address;
|
||||
|
@ -16,14 +16,14 @@ public:
|
||||
virtual ~BTAdvertisedDevice() = default;
|
||||
|
||||
virtual BTAddress getAddress();
|
||||
virtual uint32_t getCOD();
|
||||
virtual std::string getName();
|
||||
virtual int8_t getRSSI();
|
||||
virtual uint32_t getCOD() const;
|
||||
virtual std::string getName() const;
|
||||
virtual int8_t getRSSI() const;
|
||||
|
||||
|
||||
virtual bool haveCOD();
|
||||
virtual bool haveName();
|
||||
virtual bool haveRSSI();
|
||||
virtual bool haveCOD() const;
|
||||
virtual bool haveName() const;
|
||||
virtual bool haveRSSI() const;
|
||||
|
||||
virtual std::string toString();
|
||||
};
|
||||
@ -35,14 +35,14 @@ public:
|
||||
|
||||
|
||||
BTAddress getAddress();
|
||||
uint32_t getCOD();
|
||||
std::string getName();
|
||||
int8_t getRSSI();
|
||||
uint32_t getCOD() const;
|
||||
std::string getName() const;
|
||||
int8_t getRSSI() const;
|
||||
|
||||
|
||||
bool haveCOD();
|
||||
bool haveName();
|
||||
bool haveRSSI();
|
||||
bool haveCOD() const;
|
||||
bool haveName() const;
|
||||
bool haveRSSI() const;
|
||||
|
||||
std::string toString();
|
||||
|
||||
@ -62,4 +62,4 @@ public:
|
||||
int8_t m_rssi;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@ -25,14 +25,14 @@ BTAdvertisedDeviceSet::BTAdvertisedDeviceSet() {
|
||||
} // BTAdvertisedDeviceSet
|
||||
|
||||
BTAddress BTAdvertisedDeviceSet::getAddress() { return m_address; }
|
||||
uint32_t BTAdvertisedDeviceSet::getCOD() { return m_cod; }
|
||||
std::string BTAdvertisedDeviceSet::getName() { return m_name; }
|
||||
int8_t BTAdvertisedDeviceSet::getRSSI() { return m_rssi; }
|
||||
uint32_t BTAdvertisedDeviceSet::getCOD() const { return m_cod; }
|
||||
std::string BTAdvertisedDeviceSet::getName() const { return m_name; }
|
||||
int8_t BTAdvertisedDeviceSet::getRSSI() const { return m_rssi; }
|
||||
|
||||
|
||||
bool BTAdvertisedDeviceSet::haveCOD() { return m_haveCOD; }
|
||||
bool BTAdvertisedDeviceSet::haveName() { return m_haveName; }
|
||||
bool BTAdvertisedDeviceSet::haveRSSI() { return m_haveRSSI; }
|
||||
bool BTAdvertisedDeviceSet::haveCOD() const { return m_haveCOD; }
|
||||
bool BTAdvertisedDeviceSet::haveName() const { return m_haveName; }
|
||||
bool BTAdvertisedDeviceSet::haveRSSI() const { return m_haveRSSI; }
|
||||
|
||||
/**
|
||||
* @brief Create a string representation of this device.
|
||||
|
@ -72,18 +72,30 @@ static esp_bt_pin_code_t _pin_code;
|
||||
static int _pin_len;
|
||||
static bool _isPinSet;
|
||||
static bool _enableSSP;
|
||||
static esp_spp_sec_t _sec_mask;
|
||||
static esp_spp_role_t _role;
|
||||
// start connect on ESP_SPP_DISCOVERY_COMP_EVT or save entry for getChannels
|
||||
static bool _doConnect;
|
||||
static std::map <int, std::string> sdpRecords;
|
||||
|
||||
static BTScanResultsSet scanResults;
|
||||
static BTAdvertisedDeviceCb advertisedDeviceCb = nullptr;
|
||||
|
||||
// _spp_event_group
|
||||
#define SPP_RUNNING 0x01
|
||||
#define SPP_CONNECTED 0x02
|
||||
#define SPP_CONGESTED 0x04
|
||||
// true until OPEN successful, changes to false on CLOSE
|
||||
#define SPP_DISCONNECTED 0x08
|
||||
// true until connect(), changes to true on CLOSE
|
||||
#define SPP_CLOSED 0x10
|
||||
|
||||
// _bt_event_group
|
||||
#define BT_DISCOVERY_RUNNING 0x01
|
||||
#define BT_DISCOVERY_COMPLETED 0x02
|
||||
|
||||
#define BT_SDP_RUNNING 0x04
|
||||
#define BT_SDP_COMPLETED 0x08
|
||||
|
||||
typedef struct {
|
||||
size_t len;
|
||||
@ -98,7 +110,7 @@ static char *bda2str(esp_bd_addr_t bda, char *str, size_t size)
|
||||
}
|
||||
|
||||
uint8_t *p = bda;
|
||||
sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
snprintf(str, size, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
p[0], p[1], p[2], p[3], p[4], p[5]);
|
||||
return str;
|
||||
}
|
||||
@ -280,13 +292,15 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
|
||||
|
||||
case ESP_SPP_CLOSE_EVT://Client connection closed
|
||||
if ((param->close.async == false && param->close.status == ESP_SPP_SUCCESS) || param->close.async) {
|
||||
log_i("ESP_SPP_CLOSE_EVT: %u", secondConnectionAttempt);
|
||||
log_i("ESP_SPP_CLOSE_EVT status:%d handle:%d close_by_remote:%d attempt %u", param->close.status,
|
||||
param->close.handle, param->close.async, secondConnectionAttempt);
|
||||
if(secondConnectionAttempt) {
|
||||
secondConnectionAttempt = false;
|
||||
} else {
|
||||
_spp_client = 0;
|
||||
xEventGroupSetBits(_spp_event_group, SPP_DISCONNECTED);
|
||||
xEventGroupSetBits(_spp_event_group, SPP_CONGESTED);
|
||||
xEventGroupSetBits(_spp_event_group, SPP_CLOSED);
|
||||
}
|
||||
xEventGroupClearBits(_spp_event_group, SPP_CONNECTED);
|
||||
} else {
|
||||
@ -333,13 +347,37 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
|
||||
break;
|
||||
|
||||
case ESP_SPP_DISCOVERY_COMP_EVT://discovery complete
|
||||
log_i("ESP_SPP_DISCOVERY_COMP_EVT");
|
||||
log_i("ESP_SPP_DISCOVERY_COMP_EVT num=%d", param->disc_comp.scn_num);
|
||||
if (param->disc_comp.status == ESP_SPP_SUCCESS) {
|
||||
log_i("ESP_SPP_DISCOVERY_COMP_EVT: spp connect to remote");
|
||||
esp_spp_connect(ESP_SPP_SEC_AUTHENTICATE, ESP_SPP_ROLE_MASTER, param->disc_comp.scn[0], _peer_bd_addr);
|
||||
for(int i=0; i < param->disc_comp.scn_num; i++) {
|
||||
log_d("ESP_SPP_DISCOVERY_COMP_EVT: spp [%d] channel: %d service name:%s", i, param->disc_comp.scn[i], param->disc_comp.service_name[0]);
|
||||
}
|
||||
if(_doConnect) {
|
||||
if(param->disc_comp.scn_num > 0) {
|
||||
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)
|
||||
char bda_str[18];
|
||||
log_i("ESP_SPP_DISCOVERY_COMP_EVT: spp connect to remote %s channel %d",
|
||||
bda2str(_peer_bd_addr, bda_str, sizeof(bda_str)),
|
||||
param->disc_comp.scn[0]);
|
||||
#endif
|
||||
xEventGroupClearBits(_spp_event_group, SPP_CLOSED);
|
||||
if(esp_spp_connect(_sec_mask, _role, param->disc_comp.scn[0], _peer_bd_addr) != ESP_OK) {
|
||||
log_e("ESP_SPP_DISCOVERY_COMP_EVT connect failed");
|
||||
xEventGroupSetBits(_spp_event_group, SPP_CLOSED);
|
||||
}
|
||||
} else {
|
||||
log_e("ESP_SPP_DISCOVERY_COMP_EVT remote doesn't offer an SPP channel");
|
||||
xEventGroupSetBits(_spp_event_group, SPP_CLOSED);
|
||||
}
|
||||
} else {
|
||||
for(int i=0; i < param->disc_comp.scn_num; i++) {
|
||||
sdpRecords[param->disc_comp.scn[i]] = param->disc_comp.service_name[0];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log_e("ESP_SPP_DISCOVERY_COMP_EVT failed!, status:%d", param->disc_comp.status);
|
||||
}
|
||||
xEventGroupSetBits(_bt_event_group, BT_SDP_COMPLETED);
|
||||
break;
|
||||
|
||||
case ESP_SPP_OPEN_EVT://Client connection open
|
||||
@ -360,10 +398,15 @@ static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
|
||||
break;
|
||||
|
||||
case ESP_SPP_CL_INIT_EVT://client initiated a connection
|
||||
log_i("ESP_SPP_CL_INIT_EVT");
|
||||
if (param->cl_init.status == ESP_SPP_SUCCESS) {
|
||||
log_i("ESP_SPP_CL_INIT_EVT handle:%d sec_id:%d", param->cl_init.handle, param->cl_init.sec_id);
|
||||
} else {
|
||||
log_i("ESP_SPP_CL_INIT_EVT status:%d", param->cl_init.status);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
log_i("ESP_SPP_* event unhandled %d", event);
|
||||
break;
|
||||
}
|
||||
if(custom_spp_callback)(*custom_spp_callback)(event, param);
|
||||
@ -377,7 +420,7 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
|
||||
{
|
||||
switch(event){
|
||||
case ESP_BT_GAP_DISC_RES_EVT: {
|
||||
log_i("ESP_BT_GAP_DISC_RES_EVT");
|
||||
log_i("ESP_BT_GAP_DISC_RES_EVT properties=%d", param->disc_res.num_prop);
|
||||
#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));
|
||||
@ -417,28 +460,29 @@ 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_d("ESP_BT_GAP_DEV_PROP_COD");
|
||||
if (param->disc_res.prop[i].len <= sizeof(int)) {
|
||||
uint32_t cod = 0;
|
||||
memcpy(&cod, param->disc_res.prop[i].val, param->disc_res.prop[i].len);
|
||||
advertisedDevice.setCOD(cod);
|
||||
log_d("ESP_BT_GAP_DEV_PROP_COD 0x%x", cod);
|
||||
} else {
|
||||
log_d("Value size larger than integer");
|
||||
log_d("ESP_BT_GAP_DEV_PROP_COD invalid COD: Value size larger than integer");
|
||||
}
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_DEV_PROP_RSSI:
|
||||
log_d("ESP_BT_GAP_DEV_PROP_RSSI");
|
||||
if (param->disc_res.prop[i].len <= sizeof(int)) {
|
||||
uint8_t rssi = 0;
|
||||
memcpy(&rssi, param->disc_res.prop[i].val, param->disc_res.prop[i].len);
|
||||
log_d("ESP_BT_GAP_DEV_PROP_RSSI %d", rssi);
|
||||
advertisedDevice.setRSSI(rssi);
|
||||
} else {
|
||||
log_d("Value size larger than integer");
|
||||
log_d("ESP_BT_GAP_DEV_PROP_RSSI invalid RSSI: Value size larger than integer");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
log_i("ESP_BT_GAP_DISC_RES_EVT unknown property [%d]:type:%d", i, param->disc_res.prop[i].type);
|
||||
break;
|
||||
}
|
||||
if (_isRemoteAddressSet)
|
||||
@ -455,11 +499,12 @@ 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_DISC_STATE_CHANGED_EVT:
|
||||
log_i("ESP_BT_GAP_DISC_STATE_CHANGED_EVT");
|
||||
if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STOPPED) {
|
||||
log_i("ESP_BT_GAP_DISC_STATE_CHANGED_EVT stopped");
|
||||
xEventGroupClearBits(_bt_event_group, BT_DISCOVERY_RUNNING);
|
||||
xEventGroupSetBits(_bt_event_group, BT_DISCOVERY_COMPLETED);
|
||||
} else { // ESP_BT_GAP_DISCOVERY_STARTED
|
||||
log_i("ESP_BT_GAP_DISC_STATE_CHANGED_EVT started");
|
||||
xEventGroupClearBits(_bt_event_group, BT_DISCOVERY_COMPLETED);
|
||||
xEventGroupSetBits(_bt_event_group, BT_DISCOVERY_RUNNING);
|
||||
}
|
||||
@ -522,7 +567,24 @@ static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
|
||||
log_i("ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_CONFIG_EIR_DATA_EVT:
|
||||
log_i("ESP_BT_GAP_CONFIG_EIR_DATA_EVT: stat:%d num:%d", param->config_eir_data.stat, param->config_eir_data.eir_type_num);
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_READ_REMOTE_NAME_EVT:
|
||||
if (param->read_rmt_name.stat == ESP_BT_STATUS_SUCCESS ) {
|
||||
log_i("ESP_BT_GAP_READ_REMOTE_NAME_EVT: %s", param->read_rmt_name.rmt_name);
|
||||
} else {
|
||||
log_i("ESP_BT_GAP_READ_REMOTE_NAME_EVT: no success stat:%d", param->read_rmt_name.stat);
|
||||
}
|
||||
break;
|
||||
|
||||
case ESP_BT_GAP_MODE_CHG_EVT:
|
||||
log_i("ESP_BT_GAP_MODE_CHG_EVT: mode: %d", param->mode_chg.mode);
|
||||
break;
|
||||
|
||||
default:
|
||||
log_i("ESP-BT_GAP_* unknown message: %d", event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -546,6 +608,7 @@ static bool _init_bt(const char *deviceName)
|
||||
xEventGroupClearBits(_spp_event_group, 0xFFFFFF);
|
||||
xEventGroupSetBits(_spp_event_group, SPP_CONGESTED);
|
||||
xEventGroupSetBits(_spp_event_group, SPP_DISCONNECTED);
|
||||
xEventGroupSetBits(_spp_event_group, SPP_CLOSED);
|
||||
}
|
||||
if (_spp_rx_queue == NULL){
|
||||
_spp_rx_queue = xQueueCreate(RX_QUEUE_SIZE, sizeof(uint8_t)); //initialize the queue
|
||||
@ -623,6 +686,7 @@ static bool _init_bt(const char *deviceName)
|
||||
esp_bt_dev_set_device_name(deviceName);
|
||||
|
||||
if (_isPinSet) {
|
||||
log_i("pin set");
|
||||
btSetPin();
|
||||
}
|
||||
|
||||
@ -690,7 +754,16 @@ 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) & SPP_CONNECTED) != 0;
|
||||
// wait for connected or closed
|
||||
EventBits_t rc = xEventGroupWaitBits(_spp_event_group, SPP_CONNECTED | SPP_CLOSED, pdFALSE, pdFALSE, xTicksToWait);
|
||||
if((rc & SPP_CONNECTED) != 0)
|
||||
return true;
|
||||
else if((rc & SPP_CLOSED) != 0) {
|
||||
log_d("connection closed!");
|
||||
return false;
|
||||
}
|
||||
log_d("timeout");
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool waitForDiscovered(int timeout) {
|
||||
@ -698,6 +771,11 @@ static bool waitForDiscovered(int timeout) {
|
||||
return (xEventGroupWaitBits(_spp_event_group, BT_DISCOVERY_COMPLETED, pdFALSE, pdTRUE, xTicksToWait) & BT_DISCOVERY_COMPLETED) != 0;
|
||||
}
|
||||
|
||||
static bool waitForSDPRecord(int timeout) {
|
||||
TickType_t xTicksToWait = timeout / portTICK_PERIOD_MS;
|
||||
return (xEventGroupWaitBits(_bt_event_group, BT_SDP_COMPLETED, pdFALSE, pdTRUE, xTicksToWait) & BT_SDP_COMPLETED) != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Serial Bluetooth Arduino
|
||||
*
|
||||
@ -713,6 +791,9 @@ BluetoothSerial::~BluetoothSerial(void)
|
||||
_stop_bt();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Param isMaster set to true if you want to connect to an other device
|
||||
*/
|
||||
bool BluetoothSerial::begin(String localName, bool isMaster)
|
||||
{
|
||||
_isMaster = isMaster;
|
||||
@ -733,7 +814,7 @@ int BluetoothSerial::available(void)
|
||||
int BluetoothSerial::peek(void)
|
||||
{
|
||||
uint8_t c;
|
||||
if (_spp_rx_queue && xQueuePeek(_spp_rx_queue, &c, 0)){
|
||||
if (_spp_rx_queue && xQueuePeek(_spp_rx_queue, &c, this->timeoutTicks)){
|
||||
return c;
|
||||
}
|
||||
return -1;
|
||||
@ -744,16 +825,24 @@ bool BluetoothSerial::hasClient(void)
|
||||
return _spp_client > 0;
|
||||
}
|
||||
|
||||
int BluetoothSerial::read(void)
|
||||
int BluetoothSerial::read()
|
||||
{
|
||||
|
||||
uint8_t c = 0;
|
||||
if (_spp_rx_queue && xQueueReceive(_spp_rx_queue, &c, 0)){
|
||||
if (_spp_rx_queue && xQueueReceive(_spp_rx_queue, &c, this->timeoutTicks)){
|
||||
return c;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set timeout for read / peek
|
||||
*/
|
||||
void BluetoothSerial::setTimeout(int timeoutMS)
|
||||
{
|
||||
this->timeoutTicks=timeoutMS / portTICK_PERIOD_MS;
|
||||
}
|
||||
|
||||
size_t BluetoothSerial::write(uint8_t c)
|
||||
{
|
||||
return write(&c, 1);
|
||||
@ -812,6 +901,7 @@ void BluetoothSerial::enableSSP() {
|
||||
* Use fixed pin code
|
||||
*/
|
||||
bool BluetoothSerial::setPin(const char *pin) {
|
||||
log_i("pin: %s", pin);
|
||||
bool isEmpty = !(pin && *pin);
|
||||
if (isEmpty && !_isPinSet) {
|
||||
return true; // nothing to do
|
||||
@ -831,13 +921,18 @@ bool BluetoothSerial::setPin(const char *pin) {
|
||||
|
||||
bool BluetoothSerial::connect(String remoteName)
|
||||
{
|
||||
bool retval = false;
|
||||
|
||||
if (!isReady(true, READY_TIMEOUT)) return false;
|
||||
if (remoteName && remoteName.length() < 1) {
|
||||
log_e("No remote name is provided");
|
||||
return false;
|
||||
}
|
||||
disconnect();
|
||||
_doConnect = true;
|
||||
_isRemoteAddressSet = false;
|
||||
_sec_mask = ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE;
|
||||
_role = ESP_SPP_ROLE_MASTER;
|
||||
strncpy(_remote_name, remoteName.c_str(), ESP_BT_GAP_MAX_BDNAME_LEN);
|
||||
_remote_name[ESP_BT_GAP_MAX_BDNAME_LEN] = 0;
|
||||
log_i("master : remoteName");
|
||||
@ -847,33 +942,78 @@ bool BluetoothSerial::connect(String remoteName)
|
||||
#else
|
||||
esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
|
||||
#endif
|
||||
xEventGroupClearBits(_spp_event_group, SPP_CLOSED);
|
||||
if (esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, INQ_LEN, INQ_NUM_RSPS) == ESP_OK) {
|
||||
return waitForConnect(SCAN_TIMEOUT);
|
||||
retval = waitForConnect(SCAN_TIMEOUT);
|
||||
}
|
||||
return false;
|
||||
if (retval == false) {
|
||||
_isRemoteAddressSet = false;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool BluetoothSerial::connect(uint8_t remoteAddress[])
|
||||
/**
|
||||
* @Param channel: specify channel or 0 for auto-detect
|
||||
* @Param sec_mask:
|
||||
* ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE
|
||||
* ESP_SPP_SEC_NONE
|
||||
* @Param role:
|
||||
* ESP_SPP_ROLE_MASTER master can handle up to 7 connections to slaves
|
||||
* ESP_SPP_ROLE_SLAVE can only have one connection to a master
|
||||
*/
|
||||
bool BluetoothSerial::connect(uint8_t remoteAddress[], int channel, esp_spp_sec_t sec_mask, esp_spp_role_t role)
|
||||
{
|
||||
bool retval = false;
|
||||
if (!isReady(true, READY_TIMEOUT)) return false;
|
||||
if (!remoteAddress) {
|
||||
log_e("No remote address is provided");
|
||||
return false;
|
||||
}
|
||||
disconnect();
|
||||
_doConnect = true;
|
||||
_remote_name[0] = 0;
|
||||
_isRemoteAddressSet = true;
|
||||
_sec_mask = sec_mask;
|
||||
_role = role;
|
||||
memcpy(_peer_bd_addr, remoteAddress, ESP_BD_ADDR_LEN);
|
||||
log_i("master : remoteAddress");
|
||||
if (esp_spp_start_discovery(_peer_bd_addr) == ESP_OK) {
|
||||
return waitForConnect(READY_TIMEOUT);
|
||||
xEventGroupClearBits(_spp_event_group, SPP_CLOSED);
|
||||
if (channel > 0) {
|
||||
#if (ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)
|
||||
char bda_str[18];
|
||||
log_i("spp connect to remote %s channel %d",
|
||||
bda2str(_peer_bd_addr, bda_str, sizeof(bda_str)),
|
||||
channel);
|
||||
#endif
|
||||
if(esp_spp_connect(sec_mask, role, channel, _peer_bd_addr) != ESP_OK ) {
|
||||
log_e("spp connect failed");
|
||||
retval = false;
|
||||
} else {
|
||||
retval = waitForConnect(READY_TIMEOUT);
|
||||
if(retval) {
|
||||
log_i("connected");
|
||||
} else {
|
||||
if(this->isClosed()) {
|
||||
log_e("connect failed");
|
||||
} else {
|
||||
log_e("connect timed out after %dms", READY_TIMEOUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else if (esp_spp_start_discovery(_peer_bd_addr) == ESP_OK) {
|
||||
retval = waitForConnect(READY_TIMEOUT);
|
||||
}
|
||||
|
||||
if (!retval) {
|
||||
_isRemoteAddressSet = false;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool BluetoothSerial::connect()
|
||||
{
|
||||
if (!isReady(true, READY_TIMEOUT)) return false;
|
||||
_doConnect = true;
|
||||
if (_isRemoteAddressSet){
|
||||
disconnect();
|
||||
// use resolved or set address first
|
||||
@ -924,6 +1064,13 @@ bool BluetoothSerial::connected(int timeout) {
|
||||
return waitForConnect(timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* true if a connection terminated or a connection attempt failed
|
||||
*/
|
||||
bool BluetoothSerial::isClosed() {
|
||||
return xEventGroupGetBits(_spp_event_group) & SPP_CLOSED;
|
||||
}
|
||||
|
||||
bool BluetoothSerial::isReady(bool checkMaster, int timeout) {
|
||||
if (checkMaster && !_isMaster) {
|
||||
log_e("Master mode is not active. Call begin(localName, true) to enable Master mode");
|
||||
@ -956,6 +1103,7 @@ BTScanResults* BluetoothSerial::discover(int timeoutMs) {
|
||||
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
|
||||
if (esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, timeout, 0) == ESP_OK) {
|
||||
waitForDiscovered(timeoutMs);
|
||||
log_i("gap_cancel_discovery()");
|
||||
esp_bt_gap_cancel_discovery();
|
||||
}
|
||||
return &scanResults;
|
||||
@ -1008,4 +1156,31 @@ BluetoothSerial::operator bool() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* SDP scan address
|
||||
* esp_spp_start_discovery doesn't tell us the btAddress in the callback, so we have to wait until it's finished
|
||||
*/
|
||||
std::map<int, std::string> BluetoothSerial::getChannels(const BTAddress &remoteAddress) {
|
||||
if(xEventGroupGetBits(_bt_event_group) & BT_SDP_RUNNING) {
|
||||
log_e("getChannels failed - already running");
|
||||
}
|
||||
xEventGroupSetBits(_bt_event_group, BT_SDP_RUNNING);
|
||||
xEventGroupClearBits(_bt_event_group, BT_SDP_COMPLETED);
|
||||
_doConnect = false;
|
||||
sdpRecords.clear();
|
||||
log_d("esp_spp_start_discovery");
|
||||
if (esp_spp_start_discovery(*remoteAddress.getNative()) != ESP_OK) {
|
||||
log_e("esp_spp_start_discovery failed");
|
||||
} else {
|
||||
if(! waitForSDPRecord(READY_TIMEOUT)) {
|
||||
log_e("getChannels failed timeout");
|
||||
}
|
||||
log_d("esp_spp_start_discovery wait for BT_SDP_COMPLETED done (%dms)", READY_TIMEOUT);
|
||||
}
|
||||
log_d("esp_spp_start_discovery done, found %d services", sdpRecords.size());
|
||||
xEventGroupClearBits(_bt_event_group, BT_SDP_RUNNING);
|
||||
return sdpRecords;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <esp_gap_bt_api.h>
|
||||
#include <esp_spp_api.h>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include "BTScan.h"
|
||||
|
||||
typedef std::function<void(const uint8_t *buffer, size_t size)> BluetoothSerialDataCb;
|
||||
@ -50,6 +51,7 @@ class BluetoothSerial: public Stream
|
||||
size_t write(const uint8_t *buffer, size_t size);
|
||||
void flush();
|
||||
void end(void);
|
||||
void setTimeout(int timeoutMS);
|
||||
void onData(BluetoothSerialDataCb cb);
|
||||
esp_err_t register_callback(esp_spp_cb_t * callback);
|
||||
|
||||
@ -60,9 +62,12 @@ class BluetoothSerial: public Stream
|
||||
void enableSSP();
|
||||
bool setPin(const char *pin);
|
||||
bool connect(String remoteName);
|
||||
bool connect(uint8_t remoteAddress[]);
|
||||
bool connect(uint8_t remoteAddress[], int channel=0, esp_spp_sec_t sec_mask=(ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE), esp_spp_role_t role=ESP_SPP_ROLE_MASTER);
|
||||
bool connect(const BTAddress &remoteAddress, int channel=0, esp_spp_sec_t sec_mask=(ESP_SPP_SEC_ENCRYPT|ESP_SPP_SEC_AUTHENTICATE), esp_spp_role_t role=ESP_SPP_ROLE_MASTER) {
|
||||
return connect(*remoteAddress.getNative(), channel, sec_mask); };
|
||||
bool connect();
|
||||
bool connected(int timeout=0);
|
||||
bool isClosed();
|
||||
bool isReady(bool checkMaster=false, int timeout=0);
|
||||
bool disconnect();
|
||||
bool unpairDevice(uint8_t remoteAddress[]);
|
||||
@ -73,6 +78,8 @@ class BluetoothSerial: public Stream
|
||||
void discoverClear();
|
||||
BTScanResults* getScanResults();
|
||||
|
||||
std::map<int, std::string> getChannels(const BTAddress &remoteAddress);
|
||||
|
||||
const int INQ_TIME = 1280; // Inquire Time unit 1280 ms
|
||||
const int MIN_INQ_TIME = (ESP_BT_GAP_MIN_INQ_LEN * INQ_TIME);
|
||||
const int MAX_INQ_TIME = (ESP_BT_GAP_MAX_INQ_LEN * INQ_TIME);
|
||||
@ -80,7 +87,7 @@ class BluetoothSerial: public Stream
|
||||
operator bool() const;
|
||||
private:
|
||||
String local_name;
|
||||
|
||||
int timeoutTicks=0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -20,6 +20,22 @@ DNSServer::DNSServer()
|
||||
_port = 0;
|
||||
}
|
||||
|
||||
DNSServer::~DNSServer()
|
||||
{
|
||||
if (_dnsHeader) {
|
||||
free(_dnsHeader);
|
||||
_dnsHeader = NULL;
|
||||
}
|
||||
if (_dnsQuestion) {
|
||||
free(_dnsQuestion);
|
||||
_dnsQuestion = NULL;
|
||||
}
|
||||
if (_buffer) {
|
||||
free(_buffer);
|
||||
_buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool DNSServer::start(const uint16_t &port, const String &domainName,
|
||||
const IPAddress &resolvedIP)
|
||||
{
|
||||
|
@ -76,6 +76,7 @@ class DNSServer
|
||||
{
|
||||
public:
|
||||
DNSServer();
|
||||
~DNSServer();
|
||||
void processNextRequest();
|
||||
void setErrorReplyCode(const DNSReplyCode &replyCode);
|
||||
void setTTL(const uint32_t &ttl);
|
||||
|
@ -6,22 +6,35 @@
|
||||
// Ensure ESP32 Wrover Module or other board with PSRAM is selected
|
||||
// Partial images will be transmitted if image exceeds buffer size
|
||||
//
|
||||
// You must select partition scheme from the board menu that has at least 3MB APP space.
|
||||
// Face Recognition is DISABLED for ESP32 and ESP32-S2, because it takes up from 15
|
||||
// seconds to process single frame. Face Detection is ENABLED if PSRAM is enabled as well
|
||||
|
||||
// ===================
|
||||
// Select camera model
|
||||
#define CAMERA_MODEL_WROVER_KIT // Has PSRAM
|
||||
// ===================
|
||||
//#define CAMERA_MODEL_WROVER_KIT // Has PSRAM
|
||||
//#define CAMERA_MODEL_ESP_EYE // Has PSRAM
|
||||
//#define CAMERA_MODEL_ESP32S3_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_M5STACK_UNITCAM // No PSRAM
|
||||
//#define CAMERA_MODEL_AI_THINKER // Has PSRAM
|
||||
#define CAMERA_MODEL_AI_THINKER // Has PSRAM
|
||||
//#define CAMERA_MODEL_TTGO_T_JOURNAL // No PSRAM
|
||||
// ** Espressif Internal Boards **
|
||||
//#define CAMERA_MODEL_ESP32_CAM_BOARD
|
||||
//#define CAMERA_MODEL_ESP32S2_CAM_BOARD
|
||||
//#define CAMERA_MODEL_ESP32S3_CAM_LCD
|
||||
|
||||
#include "camera_pins.h"
|
||||
|
||||
const char* ssid = "*********";
|
||||
const char* password = "*********";
|
||||
// ===========================
|
||||
// Enter your WiFi credentials
|
||||
// ===========================
|
||||
const char* ssid = "**********";
|
||||
const char* password = "**********";
|
||||
|
||||
void startCameraServer();
|
||||
|
||||
@ -50,19 +63,32 @@ void setup() {
|
||||
config.pin_pwdn = PWDN_GPIO_NUM;
|
||||
config.pin_reset = RESET_GPIO_NUM;
|
||||
config.xclk_freq_hz = 20000000;
|
||||
config.pixel_format = PIXFORMAT_JPEG;
|
||||
config.frame_size = FRAMESIZE_UXGA;
|
||||
config.pixel_format = PIXFORMAT_JPEG; // for streaming
|
||||
//config.pixel_format = PIXFORMAT_RGB565; // for face detection/recognition
|
||||
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
|
||||
config.fb_location = CAMERA_FB_IN_PSRAM;
|
||||
config.jpeg_quality = 12;
|
||||
config.fb_count = 1;
|
||||
|
||||
// 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;
|
||||
config.fb_count = 2;
|
||||
if(config.pixel_format == PIXFORMAT_JPEG){
|
||||
if(psramFound()){
|
||||
config.jpeg_quality = 10;
|
||||
config.fb_count = 2;
|
||||
config.grab_mode = CAMERA_GRAB_LATEST;
|
||||
} else {
|
||||
// Limit the frame size when PSRAM is not available
|
||||
config.frame_size = FRAMESIZE_SVGA;
|
||||
config.fb_location = CAMERA_FB_IN_DRAM;
|
||||
}
|
||||
} else {
|
||||
config.frame_size = FRAMESIZE_SVGA;
|
||||
config.jpeg_quality = 12;
|
||||
config.fb_count = 1;
|
||||
config.fb_location = CAMERA_FB_IN_DRAM;
|
||||
// Best option for face detection/recognition
|
||||
config.frame_size = FRAMESIZE_240X240;
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
config.fb_count = 2;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(CAMERA_MODEL_ESP_EYE)
|
||||
@ -85,14 +111,21 @@ void setup() {
|
||||
s->set_saturation(s, -2); // lower the saturation
|
||||
}
|
||||
// drop down frame size for higher initial frame rate
|
||||
s->set_framesize(s, FRAMESIZE_QVGA);
|
||||
if(config.pixel_format == PIXFORMAT_JPEG){
|
||||
s->set_framesize(s, FRAMESIZE_QVGA);
|
||||
}
|
||||
|
||||
#if defined(CAMERA_MODEL_M5STACK_WIDE) || defined(CAMERA_MODEL_M5STACK_ESP32CAM)
|
||||
s->set_vflip(s, 1);
|
||||
s->set_hmirror(s, 1);
|
||||
#endif
|
||||
|
||||
#if defined(CAMERA_MODEL_ESP32S3_EYE)
|
||||
s->set_vflip(s, 1);
|
||||
#endif
|
||||
|
||||
WiFi.begin(ssid, password);
|
||||
WiFi.setSleep(false);
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
@ -109,6 +142,6 @@ void setup() {
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// put your main code here, to run repeatedly:
|
||||
// Do nothing. Everything is done in another task by the web server
|
||||
delay(10000);
|
||||
}
|
||||
|
@ -28,14 +28,37 @@
|
||||
static const char *TAG = "camera_httpd";
|
||||
#endif
|
||||
|
||||
// Face Detection will not work on boards without (or with disabled) PSRAM
|
||||
#ifdef BOARD_HAS_PSRAM
|
||||
#define CONFIG_ESP_FACE_DETECT_ENABLED 1
|
||||
// Face Recognition takes upward from 15 seconds per frame on chips other than ESP32S3
|
||||
// Makes no sense to have it enabled for them
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
#define CONFIG_ESP_FACE_RECOGNITION_ENABLED 1
|
||||
#else
|
||||
#define CONFIG_ESP_FACE_RECOGNITION_ENABLED 0
|
||||
#endif
|
||||
#else
|
||||
#define CONFIG_ESP_FACE_DETECT_ENABLED 0
|
||||
#define CONFIG_ESP_FACE_RECOGNITION_ENABLED 0
|
||||
#endif
|
||||
|
||||
#if CONFIG_ESP_FACE_DETECT_ENABLED
|
||||
|
||||
#include "fd_forward.h"
|
||||
#include <vector>
|
||||
#include "human_face_detect_msr01.hpp"
|
||||
#include "human_face_detect_mnp01.hpp"
|
||||
|
||||
#define TWO_STAGE 1 /*<! 1: detect by two-stage which is more accurate but slower(with keypoints). */
|
||||
/*<! 0: detect by one-stage which is less accurate but faster(without keypoints). */
|
||||
|
||||
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
|
||||
#include "fr_forward.h"
|
||||
#include "face_recognition_tool.hpp"
|
||||
#include "face_recognition_112_v1_s16.hpp"
|
||||
#include "face_recognition_112_v1_s8.hpp"
|
||||
|
||||
#define QUANT_TYPE 0 //if set to 1 => very large firmware, very slow, reboots when streaming...
|
||||
|
||||
#define ENROLL_CONFIRM_TIMES 5
|
||||
#define FACE_ID_SAVE_NUMBER 7
|
||||
#endif
|
||||
|
||||
@ -77,12 +100,24 @@ httpd_handle_t camera_httpd = NULL;
|
||||
|
||||
static int8_t detection_enabled = 0;
|
||||
|
||||
static mtmn_config_t mtmn_config = {0};
|
||||
// #if TWO_STAGE
|
||||
// static HumanFaceDetectMSR01 s1(0.1F, 0.5F, 10, 0.2F);
|
||||
// static HumanFaceDetectMNP01 s2(0.5F, 0.3F, 5);
|
||||
// #else
|
||||
// static HumanFaceDetectMSR01 s1(0.3F, 0.5F, 10, 0.2F);
|
||||
// #endif
|
||||
|
||||
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
|
||||
static int8_t recognition_enabled = 0;
|
||||
static int8_t is_enrolling = 0;
|
||||
static face_id_list id_list = {0};
|
||||
|
||||
#if QUANT_TYPE
|
||||
// S16 model
|
||||
FaceRecognition112V1S16 recognizer;
|
||||
#else
|
||||
// S8 model
|
||||
FaceRecognition112V1S8 recognizer;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@ -113,6 +148,7 @@ static ra_filter_t *ra_filter_init(ra_filter_t *filter, size_t sample_size)
|
||||
return filter;
|
||||
}
|
||||
|
||||
/* unused function triggers error
|
||||
static int ra_filter_run(ra_filter_t *filter, int value)
|
||||
{
|
||||
if (!filter->values)
|
||||
@ -130,21 +166,16 @@ static int ra_filter_run(ra_filter_t *filter, int value)
|
||||
}
|
||||
return filter->sum / filter->count;
|
||||
}
|
||||
*/
|
||||
|
||||
#if CONFIG_ESP_FACE_DETECT_ENABLED
|
||||
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
|
||||
static void rgb_print(dl_matrix3du_t *image_matrix, uint32_t color, const char *str)
|
||||
static void rgb_print(fb_data_t *fb, uint32_t color, const char *str)
|
||||
{
|
||||
fb_data_t fb;
|
||||
fb.width = image_matrix->w;
|
||||
fb.height = image_matrix->h;
|
||||
fb.data = image_matrix->item;
|
||||
fb.bytes_per_pixel = 3;
|
||||
fb.format = FB_BGR888;
|
||||
fb_gfx_print(&fb, (fb.width - (strlen(str) * 14)) / 2, 10, color, str);
|
||||
fb_gfx_print(fb, (fb->width - (strlen(str) * 14)) / 2, 10, color, str);
|
||||
}
|
||||
|
||||
static int rgb_printf(dl_matrix3du_t *image_matrix, uint32_t color, const char *format, ...)
|
||||
static int rgb_printf(fb_data_t *fb, uint32_t color, const char *format, ...)
|
||||
{
|
||||
char loc_buf[64];
|
||||
char *temp = loc_buf;
|
||||
@ -165,7 +196,7 @@ static int rgb_printf(dl_matrix3du_t *image_matrix, uint32_t color, const char *
|
||||
}
|
||||
vsnprintf(temp, len + 1, format, arg);
|
||||
va_end(arg);
|
||||
rgb_print(image_matrix, color, temp);
|
||||
rgb_print(fb, color, temp);
|
||||
if (len > 64)
|
||||
{
|
||||
free(temp);
|
||||
@ -173,9 +204,9 @@ static int rgb_printf(dl_matrix3du_t *image_matrix, uint32_t color, const char *
|
||||
return len;
|
||||
}
|
||||
#endif
|
||||
static void draw_face_boxes(dl_matrix3du_t *image_matrix, box_array_t *boxes, int face_id)
|
||||
static void draw_face_boxes(fb_data_t *fb, std::list<dl::detect::result_t> *results, int face_id)
|
||||
{
|
||||
int x, y, w, h, i;
|
||||
int x, y, w, h;
|
||||
uint32_t color = FACE_COLOR_YELLOW;
|
||||
if (face_id < 0)
|
||||
{
|
||||
@ -185,89 +216,64 @@ static void draw_face_boxes(dl_matrix3du_t *image_matrix, box_array_t *boxes, in
|
||||
{
|
||||
color = FACE_COLOR_GREEN;
|
||||
}
|
||||
fb_data_t fb;
|
||||
fb.width = image_matrix->w;
|
||||
fb.height = image_matrix->h;
|
||||
fb.data = image_matrix->item;
|
||||
fb.bytes_per_pixel = 3;
|
||||
fb.format = FB_BGR888;
|
||||
for (i = 0; i < boxes->len; i++)
|
||||
if(fb->bytes_per_pixel == 2){
|
||||
//color = ((color >> 8) & 0xF800) | ((color >> 3) & 0x07E0) | (color & 0x001F);
|
||||
color = ((color >> 16) & 0x001F) | ((color >> 3) & 0x07E0) | ((color << 8) & 0xF800);
|
||||
}
|
||||
int i = 0;
|
||||
for (std::list<dl::detect::result_t>::iterator prediction = results->begin(); prediction != results->end(); prediction++, i++)
|
||||
{
|
||||
// rectangle box
|
||||
x = (int)boxes->box[i].box_p[0];
|
||||
y = (int)boxes->box[i].box_p[1];
|
||||
w = (int)boxes->box[i].box_p[2] - x + 1;
|
||||
h = (int)boxes->box[i].box_p[3] - y + 1;
|
||||
fb_gfx_drawFastHLine(&fb, x, y, w, color);
|
||||
fb_gfx_drawFastHLine(&fb, x, y + h - 1, w, color);
|
||||
fb_gfx_drawFastVLine(&fb, x, y, h, color);
|
||||
fb_gfx_drawFastVLine(&fb, x + w - 1, y, h, color);
|
||||
#if 0
|
||||
// landmark
|
||||
x = (int)prediction->box[0];
|
||||
y = (int)prediction->box[1];
|
||||
w = (int)prediction->box[2] - x + 1;
|
||||
h = (int)prediction->box[3] - y + 1;
|
||||
if((x + w) > fb->width){
|
||||
w = fb->width - x;
|
||||
}
|
||||
if((y + h) > fb->height){
|
||||
h = fb->height - y;
|
||||
}
|
||||
fb_gfx_drawFastHLine(fb, x, y, w, color);
|
||||
fb_gfx_drawFastHLine(fb, x, y + h - 1, w, color);
|
||||
fb_gfx_drawFastVLine(fb, x, y, h, color);
|
||||
fb_gfx_drawFastVLine(fb, x + w - 1, y, h, color);
|
||||
#if TWO_STAGE
|
||||
// landmarks (left eye, mouth left, nose, right eye, mouth right)
|
||||
int x0, y0, j;
|
||||
for (j = 0; j < 10; j+=2) {
|
||||
x0 = (int)boxes->landmark[i].landmark_p[j];
|
||||
y0 = (int)boxes->landmark[i].landmark_p[j+1];
|
||||
fb_gfx_fillRect(&fb, x0, y0, 3, 3, color);
|
||||
x0 = (int)prediction->keypoint[j];
|
||||
y0 = (int)prediction->keypoint[j+1];
|
||||
fb_gfx_fillRect(fb, x0, y0, 3, 3, color);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
|
||||
static int run_face_recognition(dl_matrix3du_t *image_matrix, box_array_t *net_boxes)
|
||||
static int run_face_recognition(fb_data_t *fb, std::list<dl::detect::result_t> *results)
|
||||
{
|
||||
dl_matrix3du_t *aligned_face = NULL;
|
||||
int matched_id = 0;
|
||||
std::vector<int> landmarks = results->front().keypoint;
|
||||
int id = -1;
|
||||
|
||||
aligned_face = dl_matrix3du_alloc(1, FACE_WIDTH, FACE_HEIGHT, 3);
|
||||
if (!aligned_face)
|
||||
{
|
||||
ESP_LOGE(TAG, "Could not allocate face recognition buffer");
|
||||
return matched_id;
|
||||
}
|
||||
if (align_face(net_boxes, image_matrix, aligned_face) == ESP_OK)
|
||||
{
|
||||
if (is_enrolling == 1)
|
||||
{
|
||||
int8_t left_sample_face = enroll_face(&id_list, aligned_face);
|
||||
Tensor<uint8_t> tensor;
|
||||
tensor.set_element((uint8_t *)fb->data).set_shape({fb->height, fb->width, 3}).set_auto_free(false);
|
||||
|
||||
if (left_sample_face == (ENROLL_CONFIRM_TIMES - 1))
|
||||
{
|
||||
ESP_LOGD(TAG, "Enrolling Face ID: %d", id_list.tail);
|
||||
}
|
||||
ESP_LOGD(TAG, "Enrolling Face ID: %d sample %d", id_list.tail, ENROLL_CONFIRM_TIMES - left_sample_face);
|
||||
rgb_printf(image_matrix, FACE_COLOR_CYAN, "ID[%u] Sample[%u]", id_list.tail, ENROLL_CONFIRM_TIMES - left_sample_face);
|
||||
if (left_sample_face == 0)
|
||||
{
|
||||
is_enrolling = 0;
|
||||
ESP_LOGD(TAG, "Enrolled Face ID: %d", id_list.tail);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
matched_id = recognize_face(&id_list, aligned_face);
|
||||
if (matched_id >= 0)
|
||||
{
|
||||
ESP_LOGW(TAG, "Match Face ID: %u", matched_id);
|
||||
rgb_printf(image_matrix, FACE_COLOR_GREEN, "Hello Subject %u", matched_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGW(TAG, "No Match Found");
|
||||
rgb_print(image_matrix, FACE_COLOR_RED, "Intruder Alert!");
|
||||
matched_id = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGW(TAG, "Face Not Aligned");
|
||||
//rgb_print(image_matrix, FACE_COLOR_YELLOW, "Human Detected");
|
||||
int enrolled_count = recognizer.get_enrolled_id_num();
|
||||
|
||||
if (enrolled_count < FACE_ID_SAVE_NUMBER && is_enrolling){
|
||||
id = recognizer.enroll_id(tensor, landmarks, "", true);
|
||||
ESP_LOGI(TAG, "Enrolled ID: %d", id);
|
||||
rgb_printf(fb, FACE_COLOR_CYAN, "ID[%u]", id);
|
||||
}
|
||||
|
||||
dl_matrix3du_free(aligned_face);
|
||||
return matched_id;
|
||||
face_info_t recognize = recognizer.recognize(tensor, landmarks);
|
||||
if(recognize.id >= 0){
|
||||
rgb_printf(fb, FACE_COLOR_GREEN, "ID[%u]: %.2f", recognize.id, recognize.similarity);
|
||||
} else {
|
||||
rgb_print(fb, FACE_COLOR_RED, "Intruder Alert!");
|
||||
}
|
||||
return recognize.id;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@ -290,7 +296,9 @@ static esp_err_t bmp_handler(httpd_req_t *req)
|
||||
{
|
||||
camera_fb_t *fb = NULL;
|
||||
esp_err_t res = ESP_OK;
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
uint64_t fr_start = esp_timer_get_time();
|
||||
#endif
|
||||
fb = esp_camera_fb_get();
|
||||
if (!fb)
|
||||
{
|
||||
@ -319,7 +327,9 @@ static esp_err_t bmp_handler(httpd_req_t *req)
|
||||
}
|
||||
res = httpd_resp_send(req, (const char *)buf, buf_len);
|
||||
free(buf);
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
uint64_t fr_end = esp_timer_get_time();
|
||||
#endif
|
||||
ESP_LOGI(TAG, "BMP: %llums, %uB", (uint64_t)((fr_end - fr_start) / 1000), buf_len);
|
||||
return res;
|
||||
}
|
||||
@ -343,7 +353,9 @@ static esp_err_t capture_handler(httpd_req_t *req)
|
||||
{
|
||||
camera_fb_t *fb = NULL;
|
||||
esp_err_t res = ESP_OK;
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
int64_t fr_start = esp_timer_get_time();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_LED_ILLUMINATOR_ENABLED
|
||||
enable_led(true);
|
||||
@ -373,15 +385,21 @@ static esp_err_t capture_handler(httpd_req_t *req)
|
||||
size_t out_len, out_width, out_height;
|
||||
uint8_t *out_buf;
|
||||
bool s;
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
bool detected = false;
|
||||
#endif
|
||||
int face_id = 0;
|
||||
if (!detection_enabled || fb->width > 400)
|
||||
{
|
||||
#endif
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
size_t fb_len = 0;
|
||||
#endif
|
||||
if (fb->format == PIXFORMAT_JPEG)
|
||||
{
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
fb_len = fb->len;
|
||||
#endif
|
||||
res = httpd_resp_send(req, (const char *)fb->buf, fb->len);
|
||||
}
|
||||
else
|
||||
@ -389,68 +407,110 @@ static esp_err_t capture_handler(httpd_req_t *req)
|
||||
jpg_chunking_t jchunk = {req, 0};
|
||||
res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk) ? ESP_OK : ESP_FAIL;
|
||||
httpd_resp_send_chunk(req, NULL, 0);
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
fb_len = jchunk.len;
|
||||
#endif
|
||||
}
|
||||
esp_camera_fb_return(fb);
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
int64_t fr_end = esp_timer_get_time();
|
||||
#endif
|
||||
ESP_LOGI(TAG, "JPG: %uB %ums", (uint32_t)(fb_len), (uint32_t)((fr_end - fr_start) / 1000));
|
||||
return res;
|
||||
#if CONFIG_ESP_FACE_DETECT_ENABLED
|
||||
}
|
||||
|
||||
dl_matrix3du_t *image_matrix = dl_matrix3du_alloc(1, fb->width, fb->height, 3);
|
||||
if (!image_matrix)
|
||||
{
|
||||
esp_camera_fb_return(fb);
|
||||
ESP_LOGE(TAG, "dl_matrix3du_alloc failed");
|
||||
httpd_resp_send_500(req);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
out_buf = image_matrix->item;
|
||||
out_len = fb->width * fb->height * 3;
|
||||
out_width = fb->width;
|
||||
out_height = fb->height;
|
||||
|
||||
s = fmt2rgb888(fb->buf, fb->len, fb->format, out_buf);
|
||||
esp_camera_fb_return(fb);
|
||||
if (!s)
|
||||
{
|
||||
dl_matrix3du_free(image_matrix);
|
||||
ESP_LOGE(TAG, "to rgb888 failed");
|
||||
httpd_resp_send_500(req);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
box_array_t *net_boxes = face_detect(image_matrix, &mtmn_config);
|
||||
|
||||
if (net_boxes)
|
||||
{
|
||||
detected = true;
|
||||
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
|
||||
if (recognition_enabled)
|
||||
{
|
||||
face_id = run_face_recognition(image_matrix, net_boxes);
|
||||
}
|
||||
#endif
|
||||
draw_face_boxes(image_matrix, net_boxes, face_id);
|
||||
dl_lib_free(net_boxes->score);
|
||||
dl_lib_free(net_boxes->box);
|
||||
if (net_boxes->landmark != NULL)
|
||||
dl_lib_free(net_boxes->landmark);
|
||||
dl_lib_free(net_boxes);
|
||||
}
|
||||
|
||||
jpg_chunking_t jchunk = {req, 0};
|
||||
s = fmt2jpg_cb(out_buf, out_len, out_width, out_height, PIXFORMAT_RGB888, 90, jpg_encode_stream, &jchunk);
|
||||
dl_matrix3du_free(image_matrix);
|
||||
if (!s)
|
||||
|
||||
if (fb->format == PIXFORMAT_RGB565
|
||||
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
|
||||
&& !recognition_enabled
|
||||
#endif
|
||||
){
|
||||
#if TWO_STAGE
|
||||
HumanFaceDetectMSR01 s1(0.1F, 0.5F, 10, 0.2F);
|
||||
HumanFaceDetectMNP01 s2(0.5F, 0.3F, 5);
|
||||
std::list<dl::detect::result_t> &candidates = s1.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3});
|
||||
std::list<dl::detect::result_t> &results = s2.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3}, candidates);
|
||||
#else
|
||||
HumanFaceDetectMSR01 s1(0.3F, 0.5F, 10, 0.2F);
|
||||
std::list<dl::detect::result_t> &results = s1.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3});
|
||||
#endif
|
||||
if (results.size() > 0) {
|
||||
fb_data_t rfb;
|
||||
rfb.width = fb->width;
|
||||
rfb.height = fb->height;
|
||||
rfb.data = fb->buf;
|
||||
rfb.bytes_per_pixel = 2;
|
||||
rfb.format = FB_RGB565;
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
detected = true;
|
||||
#endif
|
||||
draw_face_boxes(&rfb, &results, face_id);
|
||||
}
|
||||
s = fmt2jpg_cb(fb->buf, fb->len, fb->width, fb->height, PIXFORMAT_RGB565, 90, jpg_encode_stream, &jchunk);
|
||||
esp_camera_fb_return(fb);
|
||||
} else
|
||||
{
|
||||
ESP_LOGE(TAG, "JPEG compression failed");
|
||||
return ESP_FAIL;
|
||||
out_len = fb->width * fb->height * 3;
|
||||
out_width = fb->width;
|
||||
out_height = fb->height;
|
||||
out_buf = (uint8_t*)malloc(out_len);
|
||||
if (!out_buf) {
|
||||
ESP_LOGE(TAG, "out_buf malloc failed");
|
||||
httpd_resp_send_500(req);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
s = fmt2rgb888(fb->buf, fb->len, fb->format, out_buf);
|
||||
esp_camera_fb_return(fb);
|
||||
if (!s) {
|
||||
free(out_buf);
|
||||
ESP_LOGE(TAG, "to rgb888 failed");
|
||||
httpd_resp_send_500(req);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
fb_data_t rfb;
|
||||
rfb.width = out_width;
|
||||
rfb.height = out_height;
|
||||
rfb.data = out_buf;
|
||||
rfb.bytes_per_pixel = 3;
|
||||
rfb.format = FB_BGR888;
|
||||
|
||||
#if TWO_STAGE
|
||||
HumanFaceDetectMSR01 s1(0.1F, 0.5F, 10, 0.2F);
|
||||
HumanFaceDetectMNP01 s2(0.5F, 0.3F, 5);
|
||||
std::list<dl::detect::result_t> &candidates = s1.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3});
|
||||
std::list<dl::detect::result_t> &results = s2.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3}, candidates);
|
||||
#else
|
||||
HumanFaceDetectMSR01 s1(0.3F, 0.5F, 10, 0.2F);
|
||||
std::list<dl::detect::result_t> &results = s1.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3});
|
||||
#endif
|
||||
|
||||
if (results.size() > 0) {
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
detected = true;
|
||||
#endif
|
||||
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
|
||||
if (recognition_enabled) {
|
||||
face_id = run_face_recognition(&rfb, &results);
|
||||
}
|
||||
#endif
|
||||
draw_face_boxes(&rfb, &results, face_id);
|
||||
}
|
||||
|
||||
s = fmt2jpg_cb(out_buf, out_len, out_width, out_height, PIXFORMAT_RGB888, 90, jpg_encode_stream, &jchunk);
|
||||
free(out_buf);
|
||||
}
|
||||
|
||||
if (!s) {
|
||||
ESP_LOGE(TAG, "JPEG compression failed");
|
||||
httpd_resp_send_500(req);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
int64_t fr_end = esp_timer_get_time();
|
||||
#endif
|
||||
ESP_LOGI(TAG, "FACE: %uB %ums %s%d", (uint32_t)(jchunk.len), (uint32_t)((fr_end - fr_start) / 1000), detected ? "DETECTED " : "", face_id);
|
||||
return res;
|
||||
#endif
|
||||
@ -465,14 +525,24 @@ static esp_err_t stream_handler(httpd_req_t *req)
|
||||
uint8_t *_jpg_buf = NULL;
|
||||
char *part_buf[128];
|
||||
#if CONFIG_ESP_FACE_DETECT_ENABLED
|
||||
dl_matrix3du_t *image_matrix = NULL;
|
||||
bool detected = false;
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
bool detected = false;
|
||||
int64_t fr_ready = 0;
|
||||
int64_t fr_recognize = 0;
|
||||
int64_t fr_encode = 0;
|
||||
int64_t fr_face = 0;
|
||||
int64_t fr_start = 0;
|
||||
#endif
|
||||
int face_id = 0;
|
||||
int64_t fr_start = 0;
|
||||
int64_t fr_ready = 0;
|
||||
int64_t fr_face = 0;
|
||||
int64_t fr_recognize = 0;
|
||||
int64_t fr_encode = 0;
|
||||
size_t out_len = 0, out_width = 0, out_height = 0;
|
||||
uint8_t *out_buf = NULL;
|
||||
bool s = false;
|
||||
#if TWO_STAGE
|
||||
HumanFaceDetectMSR01 s1(0.1F, 0.5F, 10, 0.2F);
|
||||
HumanFaceDetectMNP01 s2(0.5F, 0.3F, 5);
|
||||
#else
|
||||
HumanFaceDetectMSR01 s1(0.3F, 0.5F, 10, 0.2F);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static int64_t last_frame = 0;
|
||||
@ -498,7 +568,9 @@ static esp_err_t stream_handler(httpd_req_t *req)
|
||||
while (true)
|
||||
{
|
||||
#if CONFIG_ESP_FACE_DETECT_ENABLED
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
detected = false;
|
||||
#endif
|
||||
face_id = 0;
|
||||
#endif
|
||||
|
||||
@ -513,11 +585,13 @@ static esp_err_t stream_handler(httpd_req_t *req)
|
||||
_timestamp.tv_sec = fb->timestamp.tv_sec;
|
||||
_timestamp.tv_usec = fb->timestamp.tv_usec;
|
||||
#if CONFIG_ESP_FACE_DETECT_ENABLED
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
fr_start = esp_timer_get_time();
|
||||
fr_ready = fr_start;
|
||||
fr_face = fr_start;
|
||||
fr_encode = fr_start;
|
||||
fr_recognize = fr_start;
|
||||
fr_face = fr_start;
|
||||
#endif
|
||||
if (!detection_enabled || fb->width > 400)
|
||||
{
|
||||
#endif
|
||||
@ -541,65 +615,112 @@ static esp_err_t stream_handler(httpd_req_t *req)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
image_matrix = dl_matrix3du_alloc(1, fb->width, fb->height, 3);
|
||||
|
||||
if (!image_matrix)
|
||||
{
|
||||
ESP_LOGE(TAG, "dl_matrix3du_alloc failed");
|
||||
res = ESP_FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!fmt2rgb888(fb->buf, fb->len, fb->format, image_matrix->item))
|
||||
{
|
||||
ESP_LOGE(TAG, "fmt2rgb888 failed");
|
||||
if (fb->format == PIXFORMAT_RGB565
|
||||
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
|
||||
&& !recognition_enabled
|
||||
#endif
|
||||
){
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
fr_ready = esp_timer_get_time();
|
||||
#endif
|
||||
#if TWO_STAGE
|
||||
std::list<dl::detect::result_t> &candidates = s1.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3});
|
||||
std::list<dl::detect::result_t> &results = s2.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3}, candidates);
|
||||
#else
|
||||
std::list<dl::detect::result_t> &results = s1.infer((uint16_t *)fb->buf, {(int)fb->height, (int)fb->width, 3});
|
||||
#endif
|
||||
#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
fr_face = esp_timer_get_time();
|
||||
fr_recognize = fr_face;
|
||||
#endif
|
||||
if (results.size() > 0) {
|
||||
fb_data_t rfb;
|
||||
rfb.width = fb->width;
|
||||
rfb.height = fb->height;
|
||||
rfb.data = fb->buf;
|
||||
rfb.bytes_per_pixel = 2;
|
||||
rfb.format = FB_RGB565;
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
detected = true;
|
||||
#endif
|
||||
draw_face_boxes(&rfb, &results, face_id);
|
||||
}
|
||||
s = fmt2jpg(fb->buf, fb->len, fb->width, fb->height, PIXFORMAT_RGB565, 80, &_jpg_buf, &_jpg_buf_len);
|
||||
esp_camera_fb_return(fb);
|
||||
fb = NULL;
|
||||
if (!s) {
|
||||
ESP_LOGE(TAG, "fmt2jpg failed");
|
||||
res = ESP_FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
fr_ready = esp_timer_get_time();
|
||||
box_array_t *net_boxes = NULL;
|
||||
if (detection_enabled)
|
||||
{
|
||||
net_boxes = face_detect(image_matrix, &mtmn_config);
|
||||
}
|
||||
fr_face = esp_timer_get_time();
|
||||
fr_recognize = fr_face;
|
||||
if (net_boxes || fb->format != PIXFORMAT_JPEG)
|
||||
{
|
||||
if (net_boxes)
|
||||
{
|
||||
detected = true;
|
||||
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
|
||||
if (recognition_enabled)
|
||||
{
|
||||
face_id = run_face_recognition(image_matrix, net_boxes);
|
||||
}
|
||||
fr_recognize = esp_timer_get_time();
|
||||
#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
fr_encode = esp_timer_get_time();
|
||||
#endif
|
||||
draw_face_boxes(image_matrix, net_boxes, face_id);
|
||||
dl_lib_free(net_boxes->score);
|
||||
dl_lib_free(net_boxes->box);
|
||||
if (net_boxes->landmark != NULL)
|
||||
dl_lib_free(net_boxes->landmark);
|
||||
dl_lib_free(net_boxes);
|
||||
} else
|
||||
{
|
||||
out_len = fb->width * fb->height * 3;
|
||||
out_width = fb->width;
|
||||
out_height = fb->height;
|
||||
out_buf = (uint8_t*)malloc(out_len);
|
||||
if (!out_buf) {
|
||||
ESP_LOGE(TAG, "out_buf malloc failed");
|
||||
res = ESP_FAIL;
|
||||
} else {
|
||||
s = fmt2rgb888(fb->buf, fb->len, fb->format, out_buf);
|
||||
esp_camera_fb_return(fb);
|
||||
fb = NULL;
|
||||
if (!s) {
|
||||
free(out_buf);
|
||||
ESP_LOGE(TAG, "to rgb888 failed");
|
||||
res = ESP_FAIL;
|
||||
} else {
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
fr_ready = esp_timer_get_time();
|
||||
#endif
|
||||
|
||||
fb_data_t rfb;
|
||||
rfb.width = out_width;
|
||||
rfb.height = out_height;
|
||||
rfb.data = out_buf;
|
||||
rfb.bytes_per_pixel = 3;
|
||||
rfb.format = FB_BGR888;
|
||||
|
||||
#if TWO_STAGE
|
||||
std::list<dl::detect::result_t> &candidates = s1.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3});
|
||||
std::list<dl::detect::result_t> &results = s2.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3}, candidates);
|
||||
#else
|
||||
std::list<dl::detect::result_t> &results = s1.infer((uint8_t *)out_buf, {(int)out_height, (int)out_width, 3});
|
||||
#endif
|
||||
|
||||
#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
fr_face = esp_timer_get_time();
|
||||
fr_recognize = fr_face;
|
||||
#endif
|
||||
|
||||
if (results.size() > 0) {
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
detected = true;
|
||||
#endif
|
||||
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
|
||||
if (recognition_enabled) {
|
||||
face_id = run_face_recognition(&rfb, &results);
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
fr_recognize = esp_timer_get_time();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
draw_face_boxes(&rfb, &results, face_id);
|
||||
}
|
||||
if (!fmt2jpg(image_matrix->item, fb->width * fb->height * 3, fb->width, fb->height, PIXFORMAT_RGB888, 90, &_jpg_buf, &_jpg_buf_len))
|
||||
{
|
||||
s = fmt2jpg(out_buf, out_len, out_width, out_height, PIXFORMAT_RGB888, 90, &_jpg_buf, &_jpg_buf_len);
|
||||
free(out_buf);
|
||||
if (!s) {
|
||||
ESP_LOGE(TAG, "fmt2jpg failed");
|
||||
res = ESP_FAIL;
|
||||
}
|
||||
esp_camera_fb_return(fb);
|
||||
fb = NULL;
|
||||
#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
fr_encode = esp_timer_get_time();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
_jpg_buf = fb->buf;
|
||||
_jpg_buf_len = fb->len;
|
||||
}
|
||||
fr_encode = esp_timer_get_time();
|
||||
}
|
||||
dl_matrix3du_free(image_matrix);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -630,11 +751,12 @@ static esp_err_t stream_handler(httpd_req_t *req)
|
||||
}
|
||||
if (res != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "send frame failed failed");
|
||||
break;
|
||||
}
|
||||
int64_t fr_end = esp_timer_get_time();
|
||||
|
||||
#if CONFIG_ESP_FACE_DETECT_ENABLED
|
||||
#if CONFIG_ESP_FACE_DETECT_ENABLED && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
int64_t ready_time = (fr_ready - fr_start) / 1000;
|
||||
int64_t face_time = (fr_face - fr_ready) / 1000;
|
||||
int64_t recognize_time = (fr_recognize - fr_face) / 1000;
|
||||
@ -643,9 +765,10 @@ static esp_err_t stream_handler(httpd_req_t *req)
|
||||
#endif
|
||||
|
||||
int64_t frame_time = fr_end - last_frame;
|
||||
last_frame = fr_end;
|
||||
frame_time /= 1000;
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
uint32_t avg_frame_time = ra_filter_run(&ra_filter, frame_time);
|
||||
#endif
|
||||
ESP_LOGI(TAG, "MJPG: %uB %ums (%.1ffps), AVG: %ums (%.1ffps)"
|
||||
#if CONFIG_ESP_FACE_DETECT_ENABLED
|
||||
", %u+%u+%u+%u=%u %s%d"
|
||||
@ -667,7 +790,6 @@ static esp_err_t stream_handler(httpd_req_t *req)
|
||||
enable_led(false);
|
||||
#endif
|
||||
|
||||
last_frame = 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -784,8 +906,10 @@ static esp_err_t cmd_handler(httpd_req_t *req)
|
||||
#endif
|
||||
}
|
||||
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
|
||||
else if (!strcmp(variable, "face_enroll"))
|
||||
is_enrolling = val;
|
||||
else if (!strcmp(variable, "face_enroll")){
|
||||
is_enrolling = !is_enrolling;
|
||||
ESP_LOGI(TAG, "Enrolling: %s", is_enrolling?"true":"false");
|
||||
}
|
||||
else if (!strcmp(variable, "face_recognize")) {
|
||||
recognition_enabled = val;
|
||||
if (recognition_enabled) {
|
||||
@ -1150,26 +1274,11 @@ void startCameraServer()
|
||||
|
||||
ra_filter_init(&ra_filter, 20);
|
||||
|
||||
#if CONFIG_ESP_FACE_DETECT_ENABLED
|
||||
|
||||
mtmn_config.type = FAST;
|
||||
mtmn_config.min_face = 80;
|
||||
mtmn_config.pyramid = 0.707;
|
||||
mtmn_config.pyramid_times = 4;
|
||||
mtmn_config.p_threshold.score = 0.6;
|
||||
mtmn_config.p_threshold.nms = 0.7;
|
||||
mtmn_config.p_threshold.candidate_number = 20;
|
||||
mtmn_config.r_threshold.score = 0.7;
|
||||
mtmn_config.r_threshold.nms = 0.7;
|
||||
mtmn_config.r_threshold.candidate_number = 10;
|
||||
mtmn_config.o_threshold.score = 0.7;
|
||||
mtmn_config.o_threshold.nms = 0.7;
|
||||
mtmn_config.o_threshold.candidate_number = 1;
|
||||
|
||||
#if CONFIG_ESP_FACE_RECOGNITION_ENABLED
|
||||
face_id_init(&id_list, FACE_ID_SAVE_NUMBER, ENROLL_CONFIRM_TIMES);
|
||||
#endif
|
||||
recognizer.set_partition(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "fr");
|
||||
|
||||
// load ids from flash partition
|
||||
recognizer.set_ids_from_flash();
|
||||
#endif
|
||||
ESP_LOGI(TAG, "Starting web server on port: '%d'", config.server_port);
|
||||
if (httpd_start(&camera_httpd, &config) == ESP_OK)
|
||||
|
@ -170,6 +170,104 @@
|
||||
#define HREF_GPIO_NUM 26
|
||||
#define PCLK_GPIO_NUM 21
|
||||
|
||||
|
||||
#elif defined(CAMERA_MODEL_ESP32_CAM_BOARD)
|
||||
// The 18 pin header on the board has Y5 and Y3 swapped
|
||||
#define USE_BOARD_HEADER 0
|
||||
#define PWDN_GPIO_NUM 32
|
||||
#define RESET_GPIO_NUM 33
|
||||
#define XCLK_GPIO_NUM 4
|
||||
#define SIOD_GPIO_NUM 18
|
||||
#define SIOC_GPIO_NUM 23
|
||||
|
||||
#define Y9_GPIO_NUM 36
|
||||
#define Y8_GPIO_NUM 19
|
||||
#define Y7_GPIO_NUM 21
|
||||
#define Y6_GPIO_NUM 39
|
||||
#if USE_BOARD_HEADER
|
||||
#define Y5_GPIO_NUM 13
|
||||
#else
|
||||
#define Y5_GPIO_NUM 35
|
||||
#endif
|
||||
#define Y4_GPIO_NUM 14
|
||||
#if USE_BOARD_HEADER
|
||||
#define Y3_GPIO_NUM 35
|
||||
#else
|
||||
#define Y3_GPIO_NUM 13
|
||||
#endif
|
||||
#define Y2_GPIO_NUM 34
|
||||
#define VSYNC_GPIO_NUM 5
|
||||
#define HREF_GPIO_NUM 27
|
||||
#define PCLK_GPIO_NUM 25
|
||||
|
||||
#elif defined(CAMERA_MODEL_ESP32S3_CAM_LCD)
|
||||
#define PWDN_GPIO_NUM -1
|
||||
#define RESET_GPIO_NUM -1
|
||||
#define XCLK_GPIO_NUM 40
|
||||
#define SIOD_GPIO_NUM 17
|
||||
#define SIOC_GPIO_NUM 18
|
||||
|
||||
#define Y9_GPIO_NUM 39
|
||||
#define Y8_GPIO_NUM 41
|
||||
#define Y7_GPIO_NUM 42
|
||||
#define Y6_GPIO_NUM 12
|
||||
#define Y5_GPIO_NUM 3
|
||||
#define Y4_GPIO_NUM 14
|
||||
#define Y3_GPIO_NUM 47
|
||||
#define Y2_GPIO_NUM 13
|
||||
#define VSYNC_GPIO_NUM 21
|
||||
#define HREF_GPIO_NUM 38
|
||||
#define PCLK_GPIO_NUM 11
|
||||
|
||||
#elif defined(CAMERA_MODEL_ESP32S2_CAM_BOARD)
|
||||
// The 18 pin header on the board has Y5 and Y3 swapped
|
||||
#define USE_BOARD_HEADER 0
|
||||
#define PWDN_GPIO_NUM 1
|
||||
#define RESET_GPIO_NUM 2
|
||||
#define XCLK_GPIO_NUM 42
|
||||
#define SIOD_GPIO_NUM 41
|
||||
#define SIOC_GPIO_NUM 18
|
||||
|
||||
#define Y9_GPIO_NUM 16
|
||||
#define Y8_GPIO_NUM 39
|
||||
#define Y7_GPIO_NUM 40
|
||||
#define Y6_GPIO_NUM 15
|
||||
#if USE_BOARD_HEADER
|
||||
#define Y5_GPIO_NUM 12
|
||||
#else
|
||||
#define Y5_GPIO_NUM 13
|
||||
#endif
|
||||
#define Y4_GPIO_NUM 5
|
||||
#if USE_BOARD_HEADER
|
||||
#define Y3_GPIO_NUM 13
|
||||
#else
|
||||
#define Y3_GPIO_NUM 12
|
||||
#endif
|
||||
#define Y2_GPIO_NUM 14
|
||||
#define VSYNC_GPIO_NUM 38
|
||||
#define HREF_GPIO_NUM 4
|
||||
#define PCLK_GPIO_NUM 3
|
||||
|
||||
#elif defined(CAMERA_MODEL_ESP32S3_EYE)
|
||||
#define PWDN_GPIO_NUM -1
|
||||
#define RESET_GPIO_NUM -1
|
||||
#define XCLK_GPIO_NUM 15
|
||||
#define SIOD_GPIO_NUM 4
|
||||
#define SIOC_GPIO_NUM 5
|
||||
|
||||
#define Y2_GPIO_NUM 11
|
||||
#define Y3_GPIO_NUM 9
|
||||
#define Y4_GPIO_NUM 8
|
||||
#define Y5_GPIO_NUM 10
|
||||
#define Y6_GPIO_NUM 12
|
||||
#define Y7_GPIO_NUM 18
|
||||
#define Y8_GPIO_NUM 17
|
||||
#define Y9_GPIO_NUM 16
|
||||
|
||||
#define VSYNC_GPIO_NUM 6
|
||||
#define HREF_GPIO_NUM 7
|
||||
#define PCLK_GPIO_NUM 13
|
||||
|
||||
#else
|
||||
#error "Camera model not selected"
|
||||
#endif
|
||||
|
@ -0,0 +1,5 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x3d0000,
|
||||
fr, data, , 0x3e0000, 0x20000,
|
|
@ -30,7 +30,7 @@
|
||||
|
||||
#define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */
|
||||
|
||||
void print_reset_reason(RESET_REASON reason)
|
||||
void print_reset_reason(int reason)
|
||||
{
|
||||
switch ( reason)
|
||||
{
|
||||
@ -53,7 +53,7 @@ void print_reset_reason(RESET_REASON reason)
|
||||
}
|
||||
}
|
||||
|
||||
void verbose_print_reset_reason(RESET_REASON reason)
|
||||
void verbose_print_reset_reason(int reason)
|
||||
{
|
||||
switch ( reason)
|
||||
{
|
||||
|
@ -30,8 +30,6 @@ void setup() {
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static uint32_t count = 0;
|
||||
|
||||
if (touch1detected) {
|
||||
touch1detected = false;
|
||||
if (touchInterruptGetLastStatus(T1)) {
|
||||
|
@ -57,24 +57,25 @@ extern void tcpipInit();
|
||||
static eth_clock_mode_t eth_clock_mode = ETH_CLK_MODE;
|
||||
|
||||
#if CONFIG_ETH_RMII_CLK_INPUT
|
||||
/*
|
||||
static void emac_config_apll_clock(void)
|
||||
{
|
||||
/* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) */
|
||||
// apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2)
|
||||
rtc_xtal_freq_t rtc_xtal_freq = rtc_clk_xtal_freq_get();
|
||||
switch (rtc_xtal_freq) {
|
||||
case RTC_XTAL_FREQ_40M: // Recommended
|
||||
/* 50 MHz = 40MHz * (4 + 6) / (2 * (2 + 2) = 50.000 */
|
||||
/* sdm0 = 0, sdm1 = 0, sdm2 = 6, o_div = 2 */
|
||||
// 50 MHz = 40MHz * (4 + 6) / (2 * (2 + 2) = 50.000
|
||||
// sdm0 = 0, sdm1 = 0, sdm2 = 6, o_div = 2
|
||||
rtc_clk_apll_enable(true, 0, 0, 6, 2);
|
||||
break;
|
||||
case RTC_XTAL_FREQ_26M:
|
||||
/* 50 MHz = 26MHz * (4 + 15 + 118 / 256 + 39/65536) / ((3 + 2) * 2) = 49.999992 */
|
||||
/* sdm0 = 39, sdm1 = 118, sdm2 = 15, o_div = 3 */
|
||||
// 50 MHz = 26MHz * (4 + 15 + 118 / 256 + 39/65536) / ((3 + 2) * 2) = 49.999992
|
||||
// sdm0 = 39, sdm1 = 118, sdm2 = 15, o_div = 3
|
||||
rtc_clk_apll_enable(true, 39, 118, 15, 3);
|
||||
break;
|
||||
case RTC_XTAL_FREQ_24M:
|
||||
/* 50 MHz = 24MHz * (4 + 12 + 255 / 256 + 255/65536) / ((2 + 2) * 2) = 49.499977 */
|
||||
/* sdm0 = 255, sdm1 = 255, sdm2 = 12, o_div = 2 */
|
||||
// 50 MHz = 24MHz * (4 + 12 + 255 / 256 + 255/65536) / ((2 + 2) * 2) = 49.499977
|
||||
// sdm0 = 255, sdm1 = 255, sdm2 = 12, o_div = 2
|
||||
rtc_clk_apll_enable(true, 255, 255, 12, 2);
|
||||
break;
|
||||
default: // Assume we have a 40M xtal
|
||||
@ -82,8 +83,10 @@ static void emac_config_apll_clock(void)
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
|
||||
/*
|
||||
static esp_err_t on_lowlevel_init_done(esp_eth_handle_t eth_handle){
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
if(eth_clock_mode > ETH_CLOCK_GPIO17_OUT){
|
||||
@ -123,7 +126,7 @@ static esp_err_t on_lowlevel_init_done(esp_eth_handle_t eth_handle){
|
||||
//gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_EMAC_TX_CLK);
|
||||
//PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[0]);
|
||||
pinMode(0, INPUT);
|
||||
pinMode(0, FUNCTION_6);
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[0], 5);
|
||||
EMAC_EXT.ex_clk_ctrl.ext_en = 1;
|
||||
EMAC_EXT.ex_clk_ctrl.int_en = 0;
|
||||
EMAC_EXT.ex_oscclk_conf.clk_sel = 1;
|
||||
@ -135,7 +138,7 @@ static esp_err_t on_lowlevel_init_done(esp_eth_handle_t eth_handle){
|
||||
//gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
|
||||
//PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[0]);
|
||||
pinMode(0, OUTPUT);
|
||||
pinMode(0, FUNCTION_2);
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[0], 1);
|
||||
// Choose the APLL clock to output on GPIO
|
||||
REG_WRITE(PIN_CTRL, 6);
|
||||
#endif
|
||||
@ -145,7 +148,7 @@ static esp_err_t on_lowlevel_init_done(esp_eth_handle_t eth_handle){
|
||||
//gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO16_U, FUNC_GPIO16_EMAC_CLK_OUT);
|
||||
//PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[16]);
|
||||
pinMode(16, OUTPUT);
|
||||
pinMode(16, FUNCTION_6);
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[16], 5);
|
||||
#endif
|
||||
} else if(eth_clock_mode == ETH_CLOCK_GPIO17_OUT){
|
||||
#if CONFIG_ETH_RMII_CLK_OUT_GPIO != 17
|
||||
@ -153,7 +156,7 @@ static esp_err_t on_lowlevel_init_done(esp_eth_handle_t eth_handle){
|
||||
//gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO17_U, FUNC_GPIO17_EMAC_CLK_OUT_180);
|
||||
//PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[17]);
|
||||
pinMode(17, OUTPUT);
|
||||
pinMode(17, FUNCTION_6);
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[17], 5);
|
||||
#endif
|
||||
}
|
||||
#if CONFIG_ETH_RMII_CLK_INPUT
|
||||
@ -168,7 +171,7 @@ static esp_err_t on_lowlevel_init_done(esp_eth_handle_t eth_handle){
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
@ -404,7 +407,7 @@ bool ETHClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, I
|
||||
esp_err_t err = ESP_OK;
|
||||
tcpip_adapter_ip_info_t info;
|
||||
|
||||
if(local_ip != (uint32_t)0x00000000 && local_ip != INADDR_NONE){
|
||||
if(static_cast<uint32_t>(local_ip) != 0){
|
||||
info.ip.addr = static_cast<uint32_t>(local_ip);
|
||||
info.gw.addr = static_cast<uint32_t>(gateway);
|
||||
info.netmask.addr = static_cast<uint32_t>(subnet);
|
||||
@ -440,13 +443,13 @@ bool ETHClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, I
|
||||
ip_addr_t d;
|
||||
d.type = IPADDR_TYPE_V4;
|
||||
|
||||
if(dns1 != (uint32_t)0x00000000 && dns1 != INADDR_NONE) {
|
||||
if(static_cast<uint32_t>(dns1) != 0) {
|
||||
// Set DNS1-Server
|
||||
d.u_addr.ip4.addr = static_cast<uint32_t>(dns1);
|
||||
dns_setserver(0, &d);
|
||||
}
|
||||
|
||||
if(dns2 != (uint32_t)0x00000000 && dns2 != INADDR_NONE) {
|
||||
if(static_cast<uint32_t>(dns2) != 0) {
|
||||
// Set DNS2-Server
|
||||
d.u_addr.ip4.addr = static_cast<uint32_t>(dns2);
|
||||
dns_setserver(1, &d);
|
||||
|
@ -130,6 +130,15 @@ size_t File::size() const
|
||||
return _p->size();
|
||||
}
|
||||
|
||||
bool File::setBufferSize(size_t size)
|
||||
{
|
||||
if (!*this) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _p->setBufferSize(size);
|
||||
}
|
||||
|
||||
void File::close()
|
||||
{
|
||||
if (_p) {
|
||||
|
@ -70,6 +70,7 @@ public:
|
||||
}
|
||||
size_t position() const;
|
||||
size_t size() const;
|
||||
bool setBufferSize(size_t size);
|
||||
void close();
|
||||
operator bool() const;
|
||||
time_t getLastWrite();
|
||||
|
@ -36,6 +36,7 @@ public:
|
||||
virtual bool seek(uint32_t pos, SeekMode mode) = 0;
|
||||
virtual size_t position() const = 0;
|
||||
virtual size_t size() const = 0;
|
||||
virtual bool setBufferSize(size_t size) = 0;
|
||||
virtual void close() = 0;
|
||||
virtual time_t getLastWrite() = 0;
|
||||
virtual const char* path() const = 0;
|
||||
|
@ -13,11 +13,10 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include "vfs_api.h"
|
||||
#include <stdio_ext.h>
|
||||
|
||||
using namespace fs;
|
||||
|
||||
#define READ_SIZE_SWITCH 128 //swithc to read func when read size > 128bytes
|
||||
#define DEFAULT_FILE_BUFFER_SIZE 4096
|
||||
|
||||
FileImplPtr VFSImpl::open(const char* fpath, const char* mode, const bool create)
|
||||
{
|
||||
@ -283,6 +282,10 @@ VFSFileImpl::VFSFileImpl(VFSImpl* fs, const char* fpath, const char* mode)
|
||||
if(!_f) {
|
||||
log_e("fopen(%s) failed", temp);
|
||||
}
|
||||
if(_f && (_stat.st_blksize == 0))
|
||||
{
|
||||
setvbuf(_f,NULL,_IOFBF,DEFAULT_FILE_BUFFER_SIZE);
|
||||
}
|
||||
} else if(S_ISDIR(_stat.st_mode)) {
|
||||
_isDirectory = true;
|
||||
_d = opendir(temp);
|
||||
@ -310,6 +313,10 @@ VFSFileImpl::VFSFileImpl(VFSImpl* fs, const char* fpath, const char* mode)
|
||||
if(!_f) {
|
||||
log_e("fopen(%s) failed", temp);
|
||||
}
|
||||
if(_f && (_stat.st_blksize == 0))
|
||||
{
|
||||
setvbuf(_f,NULL,_IOFBF,DEFAULT_FILE_BUFFER_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(temp);
|
||||
@ -377,28 +384,7 @@ size_t VFSFileImpl::read(uint8_t* buf, size_t size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
//ERASE BYTEBUFFER and use read when size > READ_SIZE_SWITCH always
|
||||
if(size > READ_SIZE_SWITCH)
|
||||
{
|
||||
//check some data in buffer exists –> clear buffer and move pointer to deleted data
|
||||
size_t bytesinbuf = __fpending(_f);
|
||||
if (bytesinbuf && (bytesinbuf != 128)) //buffer lenght is 128 bytes
|
||||
{
|
||||
fpurge(_f);
|
||||
lseek(fileno(_f),(-128+bytesinbuf),SEEK_CUR);
|
||||
}
|
||||
|
||||
int res = ::read(fileno(_f), buf, size);
|
||||
if (res < 0) {
|
||||
// an error occurred
|
||||
return 0;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
else
|
||||
{
|
||||
return fread(buf, 1, size, _f);
|
||||
}
|
||||
return fread(buf, 1, size, _f);
|
||||
}
|
||||
|
||||
void VFSFileImpl::flush()
|
||||
@ -439,6 +425,19 @@ size_t VFSFileImpl::size() const
|
||||
return _stat.st_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change size of files internal buffer used for read / write operations.
|
||||
* Need to be called right after opening file before any other operation!
|
||||
*/
|
||||
bool VFSFileImpl::setBufferSize(size_t size)
|
||||
{
|
||||
if(_isDirectory || !_f) {
|
||||
return 0;
|
||||
}
|
||||
int res = setvbuf(_f,NULL,_IOFBF,size);
|
||||
return res == 0;
|
||||
}
|
||||
|
||||
const char* VFSFileImpl::path() const
|
||||
{
|
||||
return (const char*) _path;
|
||||
|
@ -65,10 +65,11 @@ public:
|
||||
bool seek(uint32_t pos, SeekMode mode) override;
|
||||
size_t position() const override;
|
||||
size_t size() const override;
|
||||
bool setBufferSize(size_t size);
|
||||
void close() override;
|
||||
const char* path() const override;
|
||||
const char* name() const override;
|
||||
time_t getLastWrite() override;
|
||||
time_t getLastWrite() override;
|
||||
boolean isDirectory(void) override;
|
||||
FileImplPtr openNextFile(const char* mode) override;
|
||||
void rewindDirectory(void) override;
|
||||
|
@ -276,7 +276,7 @@ protected:
|
||||
/// request handling
|
||||
String _host;
|
||||
uint16_t _port = 0;
|
||||
int32_t _connectTimeout = -1;
|
||||
int32_t _connectTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT;
|
||||
bool _reuse = true;
|
||||
uint16_t _tcpTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT;
|
||||
bool _useHTTP10 = false;
|
||||
|
@ -988,7 +988,6 @@ void I2SClass::_post_read_data_fix(void *input, size_t *size){
|
||||
// bytes_written - number of bytes used from original buffer
|
||||
// actual_bytes_written - number of bytes written by i2s_write after fix
|
||||
void I2SClass::_fix_and_write(void *output, size_t size, size_t *bytes_written, size_t *actual_bytes_written){
|
||||
long start = millis();
|
||||
ulong src_ptr = 0;
|
||||
uint8_t* buff = NULL;
|
||||
size_t buff_size = size;
|
||||
|
@ -1,2 +1,2 @@
|
||||
Import("env")
|
||||
env.Replace( MKSPIFFSTOOL=env.get("PROJECT_DIR") + '/mklittlefs' )
|
||||
env.Replace( MKSPIFFSTOOL=env.get("PROJECT_DIR") + '/mklittlefs' ) # PlatformIO now believes it has actually created a SPIFFS
|
||||
|
@ -16,17 +16,6 @@ framework = arduino
|
||||
|
||||
[env:esp32]
|
||||
platform = espressif32
|
||||
;platform = https://github.com/platformio/platform-espressif32.git
|
||||
;board_build.mcu = esp32
|
||||
platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git
|
||||
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-D=${PIOENV}
|
||||
;-D CONFIG_LITTLEFS_FOR_IDF_3_2
|
||||
|
||||
lib_deps = https://github.com/lorol/LITTLEFS.git
|
||||
|
||||
board = esp32dev
|
||||
;board_build.partitions = partitions_custom.csv
|
||||
monitor_filters = esp32_exception_decoder
|
||||
|
@ -1,10 +1,13 @@
|
||||
# ESP RainMaker Examples
|
||||
|
||||
While building any examples for ESP RainMaker, take care of the following:
|
||||
|
||||
1. Change partition scheme in Arduino IDE to RainMaker (Tools -> Partition Scheme -> RainMaker).
|
||||
2. Once ESP RainMaker gets started, compulsorily call `WiFi.beginProvision()` which is responsible for user-node mapping.
|
||||
3. Use appropriate provisioning scheme as per the board.
|
||||
3. Use the appropriate provisioning scheme as per the board.
|
||||
- ESP32 Board: BLE Provisioning
|
||||
- ESP32S2 Board: SoftAP Provisioning
|
||||
4. Set debug level to Info (Tools -> Core Debug Level -> Info). This is recommended, but not mandatory.
|
||||
- ESP32-C3 Board: BLE Provisioning
|
||||
- ESP32-S3 Board: BLE Provisioning
|
||||
- ESP32-S2 Board: SoftAP Provisioning
|
||||
4. Set debug level to Info (Tools -> Core Debug Level -> Info). This is recommended debug level but not mandatory to run RainMaker.
|
||||
|
||||
|
@ -9,10 +9,15 @@ const char *service_name = "PROV_1234";
|
||||
const char *pop = "abcd1234";
|
||||
|
||||
//GPIO for push button
|
||||
static int gpio_0 = 0;
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
static int gpio_0 = 9;
|
||||
static int gpio_dimmer = 7;
|
||||
#else
|
||||
//GPIO for virtual device
|
||||
static int gpio_0 = 0;
|
||||
static int gpio_dimmer = 16;
|
||||
/* Variable for reading pin status*/
|
||||
#endif
|
||||
|
||||
bool dimmer_state = true;
|
||||
|
||||
// The framework provides some standard device types like switch, lightbulb, fan, temperature sensor.
|
||||
@ -23,14 +28,15 @@ void sysProvEvent(arduino_event_t *sys_event)
|
||||
{
|
||||
switch (sys_event->event_id) {
|
||||
case ARDUINO_EVENT_PROV_START:
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on BLE\n", service_name, pop);
|
||||
printQR(service_name, pop, "ble");
|
||||
#else
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on SoftAP\n", service_name, pop);
|
||||
printQR(service_name, pop, "softap");
|
||||
#else
|
||||
Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on BLE\n", service_name, pop);
|
||||
printQR(service_name, pop, "ble");
|
||||
#endif
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,10 +95,10 @@ void setup()
|
||||
RMaker.start();
|
||||
|
||||
WiFi.onEvent(sysProvEvent);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
WiFiProv.beginProvision(WIFI_PROV_SCHEME_BLE, WIFI_PROV_SCHEME_HANDLER_FREE_BTDM, WIFI_PROV_SECURITY_1, pop, service_name);
|
||||
#else
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
WiFiProv.beginProvision(WIFI_PROV_SCHEME_SOFTAP, WIFI_PROV_SCHEME_HANDLER_NONE, WIFI_PROV_SECURITY_1, pop, service_name);
|
||||
#else
|
||||
WiFiProv.beginProvision(WIFI_PROV_SCHEME_BLE, WIFI_PROV_SCHEME_HANDLER_FREE_BTDM, WIFI_PROV_SECURITY_1, pop, service_name);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,7 @@ void sysProvEvent(arduino_event_t *sys_event)
|
||||
Serial.printf("\nConnected to Wi-Fi!\n");
|
||||
digitalWrite(gpio_led, true);
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,9 +8,15 @@ const char *service_name = "PROV_1234";
|
||||
const char *pop = "abcd1234";
|
||||
|
||||
//GPIO for push button
|
||||
static int gpio_0 = 0;
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
static int gpio_0 = 9;
|
||||
static int gpio_switch = 7;
|
||||
#else
|
||||
//GPIO for virtual device
|
||||
static int gpio_0 = 0;
|
||||
static int gpio_switch = 16;
|
||||
#endif
|
||||
|
||||
/* Variable for reading pin status*/
|
||||
bool switch_state = true;
|
||||
|
||||
@ -21,14 +27,15 @@ void sysProvEvent(arduino_event_t *sys_event)
|
||||
{
|
||||
switch (sys_event->event_id) {
|
||||
case ARDUINO_EVENT_PROV_START:
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on BLE\n", service_name, pop);
|
||||
printQR(service_name, pop, "ble");
|
||||
#else
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on SoftAP\n", service_name, pop);
|
||||
printQR(service_name, pop, "softap");
|
||||
#endif
|
||||
#else
|
||||
Serial.printf("\nProvisioning Started with name \"%s\" and PoP \"%s\" on BLE\n", service_name, pop);
|
||||
printQR(service_name, pop, "ble");
|
||||
#endif
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,10 +81,10 @@ void setup()
|
||||
RMaker.start();
|
||||
|
||||
WiFi.onEvent(sysProvEvent);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
WiFiProv.beginProvision(WIFI_PROV_SCHEME_BLE, WIFI_PROV_SCHEME_HANDLER_FREE_BTDM, WIFI_PROV_SECURITY_1, pop, service_name);
|
||||
#else
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
WiFiProv.beginProvision(WIFI_PROV_SCHEME_SOFTAP, WIFI_PROV_SCHEME_HANDLER_NONE, WIFI_PROV_SECURITY_1, pop, service_name);
|
||||
#else
|
||||
WiFiProv.beginProvision(WIFI_PROV_SCHEME_BLE, WIFI_PROV_SCHEME_HANDLER_FREE_BTDM, WIFI_PROV_SECURITY_1, pop, service_name);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
21
libraries/RainMaker/src/RMakerQR.cpp
Normal file
21
libraries/RainMaker/src/RMakerQR.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
#include "RMakerQR.h"
|
||||
#ifdef CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK
|
||||
void printQR(const char *name, const char *pop, const char *transport)
|
||||
{
|
||||
if (!name || !pop || !transport) {
|
||||
log_w("Cannot generate QR code payload. Data missing.");
|
||||
return;
|
||||
}
|
||||
char payload[150];
|
||||
snprintf(payload, sizeof(payload), "{\"ver\":\"%s\",\"name\":\"%s\"" \
|
||||
",\"pop\":\"%s\",\"transport\":\"%s\"}",
|
||||
PROV_QR_VERSION, name, pop, transport);
|
||||
if(Serial){
|
||||
Serial.printf("Scan this QR code from the ESP RainMaker phone app.\n");
|
||||
}
|
||||
qrcode_display(payload);
|
||||
if(Serial){
|
||||
Serial.printf("If QR code is not visible, copy paste the below URL in a browser.\n%s?data=%s\n", QRCODE_BASE_URL, payload);
|
||||
}
|
||||
}
|
||||
#endif
|
@ -14,24 +14,12 @@
|
||||
#pragma once
|
||||
#include "sdkconfig.h"
|
||||
#ifdef CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK
|
||||
#include "RMaker.h"
|
||||
#include "esp_system.h"
|
||||
#include <qrcode.h>
|
||||
|
||||
#define PROV_QR_VERSION "v1"
|
||||
#define QRCODE_BASE_URL "https://rainmaker.espressif.com/qrcode.html"
|
||||
|
||||
static void printQR(const char *name, const char *pop, const char *transport)
|
||||
{
|
||||
if (!name || !pop || !transport) {
|
||||
log_w("Cannot generate QR code payload. Data missing.");
|
||||
return;
|
||||
}
|
||||
char payload[150];
|
||||
snprintf(payload, sizeof(payload), "{\"ver\":\"%s\",\"name\":\"%s\"" \
|
||||
",\"pop\":\"%s\",\"transport\":\"%s\"}",
|
||||
PROV_QR_VERSION, name, pop, transport);
|
||||
Serial.printf("Scan this QR code from the ESP RainMaker phone app.\n");
|
||||
qrcode_display(payload);
|
||||
Serial.printf("If QR code is not visible, copy paste the below URL in a browser.\n%s?data=%s\n", QRCODE_BASE_URL, payload);
|
||||
}
|
||||
void printQR(const char *name, const char *pop, const char *transport);
|
||||
#endif
|
12
libraries/RainMaker/src/RMakerUtils.cpp
Normal file
12
libraries/RainMaker/src/RMakerUtils.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
#include "RMakerUtils.h"
|
||||
#ifdef CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK
|
||||
void RMakerFactoryReset(int seconds)
|
||||
{
|
||||
esp_rmaker_factory_reset(0, seconds);
|
||||
}
|
||||
|
||||
void RMakerWiFiReset(int seconds)
|
||||
{
|
||||
esp_rmaker_wifi_reset(0, seconds);
|
||||
}
|
||||
#endif
|
@ -14,16 +14,10 @@
|
||||
#pragma once
|
||||
#include "sdkconfig.h"
|
||||
#ifdef CONFIG_ESP_RMAKER_WORK_QUEUE_TASK_STACK
|
||||
#include "RMaker.h"
|
||||
#include "esp_system.h"
|
||||
#include <esp_rmaker_utils.h>
|
||||
|
||||
static void RMakerFactoryReset(int seconds)
|
||||
{
|
||||
esp_rmaker_factory_reset(0, seconds);
|
||||
}
|
||||
|
||||
static void RMakerWiFiReset(int seconds)
|
||||
{
|
||||
esp_rmaker_wifi_reset(0, seconds);
|
||||
}
|
||||
void RMakerFactoryReset(int seconds);
|
||||
void RMakerWiFiReset(int seconds);
|
||||
#endif
|
@ -801,8 +801,13 @@ bool sdcard_mount(uint8_t pdrv, const char* path, uint8_t max_files, bool format
|
||||
if (res != FR_OK) {
|
||||
log_e("f_mount failed: %s", fferr2str[res]);
|
||||
if(res == 13 && format_if_empty){
|
||||
BYTE work[FF_MAX_SS];
|
||||
BYTE* work = (BYTE*) malloc(sizeof(BYTE) * FF_MAX_SS);
|
||||
if (!work) {
|
||||
log_e("alloc for f_mkfs failed");
|
||||
return false;
|
||||
}
|
||||
res = f_mkfs(drv, FM_ANY, 0, work, sizeof(work));
|
||||
free(work);
|
||||
if (res != FR_OK) {
|
||||
log_e("f_mkfs failed: %s", fferr2str[res]);
|
||||
esp_vfs_fat_unregister_path(path);
|
||||
|
@ -20,6 +20,15 @@
|
||||
*/
|
||||
|
||||
#include "SPI.h"
|
||||
#include "esp32-hal-log.h"
|
||||
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
#define SPI_PARAM_LOCK() do {} while (xSemaphoreTake(paramLock, portMAX_DELAY) != pdPASS)
|
||||
#define SPI_PARAM_UNLOCK() xSemaphoreGive(paramLock)
|
||||
#else
|
||||
#define SPI_PARAM_LOCK()
|
||||
#define SPI_PARAM_UNLOCK()
|
||||
#endif
|
||||
|
||||
SPIClass::SPIClass(uint8_t spi_bus)
|
||||
:_spi_num(spi_bus)
|
||||
@ -32,7 +41,31 @@ SPIClass::SPIClass(uint8_t spi_bus)
|
||||
,_div(0)
|
||||
,_freq(1000000)
|
||||
,_inTransaction(false)
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
,paramLock(NULL)
|
||||
{
|
||||
if(paramLock==NULL){
|
||||
paramLock = xSemaphoreCreateMutex();
|
||||
if(paramLock==NULL){
|
||||
log_e("xSemaphoreCreateMutex failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
{}
|
||||
#endif
|
||||
|
||||
SPIClass::~SPIClass()
|
||||
{
|
||||
end();
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
if(paramLock!=NULL){
|
||||
vSemaphoreDelete(paramLock);
|
||||
paramLock = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SPIClass::begin(int8_t sck, int8_t miso, int8_t mosi, int8_t ss)
|
||||
{
|
||||
@ -106,6 +139,7 @@ void SPIClass::setHwCs(bool use)
|
||||
|
||||
void SPIClass::setFrequency(uint32_t freq)
|
||||
{
|
||||
SPI_PARAM_LOCK();
|
||||
//check if last freq changed
|
||||
uint32_t cdiv = spiGetClockDiv(_spi);
|
||||
if(_freq != freq || _div != cdiv) {
|
||||
@ -113,12 +147,15 @@ void SPIClass::setFrequency(uint32_t freq)
|
||||
_div = spiFrequencyToClockDiv(_freq);
|
||||
spiSetClockDiv(_spi, _div);
|
||||
}
|
||||
SPI_PARAM_UNLOCK();
|
||||
}
|
||||
|
||||
void SPIClass::setClockDivider(uint32_t clockDiv)
|
||||
{
|
||||
SPI_PARAM_LOCK();
|
||||
_div = clockDiv;
|
||||
spiSetClockDiv(_spi, _div);
|
||||
SPI_PARAM_UNLOCK();
|
||||
}
|
||||
|
||||
uint32_t SPIClass::getClockDivider()
|
||||
@ -138,6 +175,7 @@ void SPIClass::setBitOrder(uint8_t bitOrder)
|
||||
|
||||
void SPIClass::beginTransaction(SPISettings settings)
|
||||
{
|
||||
SPI_PARAM_LOCK();
|
||||
//check if last freq changed
|
||||
uint32_t cdiv = spiGetClockDiv(_spi);
|
||||
if(_freq != settings._clock || _div != cdiv) {
|
||||
@ -153,6 +191,7 @@ void SPIClass::endTransaction()
|
||||
if(_inTransaction){
|
||||
_inTransaction = false;
|
||||
spiEndTransaction(_spi);
|
||||
SPI_PARAM_UNLOCK(); // <-- Im not sure should it be here or right after spiTransaction()
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,9 +265,9 @@ void SPIClass::writeBytes(const uint8_t * data, uint32_t size)
|
||||
spiEndTransaction(_spi);
|
||||
}
|
||||
|
||||
void SPIClass::transfer(uint8_t * data, uint32_t size)
|
||||
void SPIClass::transfer(void * data, uint32_t size)
|
||||
{
|
||||
transferBytes(data, data, size);
|
||||
transferBytes((const uint8_t *)data, (uint8_t *)data, size);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include <stdlib.h>
|
||||
#include "pins_arduino.h"
|
||||
#include "esp32-hal-spi.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#define SPI_HAS_TRANSACTION
|
||||
|
||||
@ -50,10 +52,14 @@ private:
|
||||
uint32_t _div;
|
||||
uint32_t _freq;
|
||||
bool _inTransaction;
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
SemaphoreHandle_t paramLock=NULL;
|
||||
#endif
|
||||
void writePattern_(const uint8_t * data, uint8_t size, uint8_t repeat);
|
||||
|
||||
public:
|
||||
SPIClass(uint8_t spi_bus=HSPI);
|
||||
~SPIClass();
|
||||
void begin(int8_t sck=-1, int8_t miso=-1, int8_t mosi=-1, int8_t ss=-1);
|
||||
void end();
|
||||
|
||||
@ -67,7 +73,7 @@ public:
|
||||
|
||||
void beginTransaction(SPISettings settings);
|
||||
void endTransaction(void);
|
||||
void transfer(uint8_t * data, uint32_t size);
|
||||
void transfer(void * data, uint32_t size);
|
||||
uint8_t transfer(uint8_t data);
|
||||
uint16_t transfer16(uint16_t data);
|
||||
uint32_t transfer32(uint32_t data);
|
||||
|
@ -58,5 +58,6 @@ void Ticker::detach() {
|
||||
}
|
||||
|
||||
bool Ticker::active() {
|
||||
if (!_timer) return false;
|
||||
return esp_timer_is_active(_timer);
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ static void vendorEventCallback(void* arg, esp_event_base_t event_base, int32_t
|
||||
case ARDUINO_USB_HID_VENDOR_SET_FEATURE_EVENT:
|
||||
Serial.printf("HID VENDOR SET FEATURE: len:%u\n", data->len);
|
||||
for(uint16_t i=0; i<data->len; i++){
|
||||
Serial.printf("0x%02X ",data->buffer);
|
||||
Serial.printf("0x%02X ",*(data->buffer));
|
||||
}
|
||||
Serial.println();
|
||||
break;
|
||||
|
@ -42,7 +42,9 @@ static bool tinyusb_hid_is_initialized = false;
|
||||
static uint8_t tinyusb_loaded_hid_devices_num = 0;
|
||||
static uint16_t tinyusb_hid_device_descriptor_len = 0;
|
||||
static uint8_t * tinyusb_hid_device_descriptor = NULL;
|
||||
static const char * tinyusb_hid_device_report_types[4] = {"INVALID", "INPUT", "OUTPUT", "FEATURE"};
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
|
||||
static const char * tinyusb_hid_device_report_types[4] = {"INVALID", "INPUT", "OUTPUT", "FEATURE"};
|
||||
#endif
|
||||
|
||||
static bool tinyusb_enable_hid_device(uint16_t descriptor_len, USBHIDDevice * device){
|
||||
if(tinyusb_hid_is_initialized){
|
||||
|
@ -274,7 +274,6 @@ size_t USBHIDKeyboard::releaseRaw(uint8_t k)
|
||||
// call release(), releaseAll(), or otherwise clear the report and resend.
|
||||
size_t USBHIDKeyboard::press(uint8_t k)
|
||||
{
|
||||
uint8_t i;
|
||||
if (k >= 0x88) { // it's a non-printing key (not a modifier)
|
||||
k = k - 0x88;
|
||||
} else if (k >= 0x80) { // it's a modifier key
|
||||
@ -298,7 +297,6 @@ size_t USBHIDKeyboard::press(uint8_t k)
|
||||
// it shouldn't be repeated any more.
|
||||
size_t USBHIDKeyboard::release(uint8_t k)
|
||||
{
|
||||
uint8_t i;
|
||||
if (k >= 0x88) { // it's a non-printing key (not a modifier)
|
||||
k = k - 0x88;
|
||||
} else if (k >= 0x80) { // it's a modifier key
|
||||
|
@ -1,3 +1,5 @@
|
||||
#ifndef HTPSPOTUADATE_H
|
||||
#define HTPSPOTUADATE_H
|
||||
#include "esp_http_client.h"
|
||||
#define HttpEvent_t esp_http_client_event_t
|
||||
|
||||
@ -19,3 +21,4 @@ class HttpsOTAUpdateClass {
|
||||
};
|
||||
|
||||
extern HttpsOTAUpdateClass HttpsOTA;
|
||||
#endif
|
||||
|
@ -375,7 +375,7 @@
|
||||
|
||||
function createTreeLeaf(path, name, size){
|
||||
var leaf = document.createElement("li");
|
||||
leaf.id = (((path == "/")?"":path)+"/"+name).toLowerCase();
|
||||
leaf.id = name.toLowerCase();
|
||||
var label = document.createElement("span");
|
||||
label.textContent = name.toLowerCase();
|
||||
leaf.appendChild(label);
|
||||
@ -398,7 +398,7 @@
|
||||
var leaf = document.createElement("li");
|
||||
var check = document.createElement("input");
|
||||
check.type = "checkbox";
|
||||
check.id = (((path == "/")?"":path)+"/"+name).toLowerCase();
|
||||
check.id = name.toLowerCase();
|
||||
if(typeof disabled !== "undefined" && disabled) check.disabled = "disabled";
|
||||
leaf.appendChild(check);
|
||||
var label = document.createElement("label");
|
||||
|
@ -430,12 +430,32 @@ void WebServer::send(int code, const char* content_type, const String& content)
|
||||
// Can we asume the following?
|
||||
//if(code == 200 && content.length() == 0 && _contentLength == CONTENT_LENGTH_NOT_SET)
|
||||
// _contentLength = CONTENT_LENGTH_UNKNOWN;
|
||||
if (content.length() == 0) {
|
||||
log_w("content length is zero");
|
||||
}
|
||||
_prepareHeader(header, code, content_type, content.length());
|
||||
_currentClientWrite(header.c_str(), header.length());
|
||||
if(content.length())
|
||||
sendContent(content);
|
||||
}
|
||||
|
||||
void WebServer::send(int code, char* content_type, const String& content) {
|
||||
send(code, (const char*)content_type, content);
|
||||
}
|
||||
|
||||
void WebServer::send(int code, const String& content_type, const String& content) {
|
||||
send(code, (const char*)content_type.c_str(), content);
|
||||
}
|
||||
|
||||
void WebServer::send(int code, const char* content_type, const char* content)
|
||||
{
|
||||
const String passStr = (String)content;
|
||||
if (strlen(content) != passStr.length()) {
|
||||
log_e("String cast failed. Use send_P for long arrays");
|
||||
}
|
||||
send(code, content_type, passStr);
|
||||
}
|
||||
|
||||
void WebServer::send_P(int code, PGM_P content_type, PGM_P content) {
|
||||
size_t contentLength = 0;
|
||||
|
||||
@ -460,14 +480,6 @@ void WebServer::send_P(int code, PGM_P content_type, PGM_P content, size_t conte
|
||||
sendContent_P(content, contentLength);
|
||||
}
|
||||
|
||||
void WebServer::send(int code, char* content_type, const String& content) {
|
||||
send(code, (const char*)content_type, content);
|
||||
}
|
||||
|
||||
void WebServer::send(int code, const String& content_type, const String& content) {
|
||||
send(code, (const char*)content_type.c_str(), content);
|
||||
}
|
||||
|
||||
void WebServer::sendContent(const String& content) {
|
||||
sendContent(content.c_str(), content.length());
|
||||
}
|
||||
|
@ -120,6 +120,8 @@ public:
|
||||
void send(int code, const char* content_type = NULL, const String& content = String(""));
|
||||
void send(int code, char* content_type, const String& content);
|
||||
void send(int code, const String& content_type, const String& content);
|
||||
void send(int code, const char* content_type, const char* content);
|
||||
|
||||
void send_P(int code, PGM_P content_type, PGM_P content);
|
||||
void send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength);
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
void setup()
|
||||
{
|
||||
bool err = ESP_FAIL;
|
||||
bool err = false;
|
||||
Serial.begin(115200);
|
||||
|
||||
// Set WiFi to station mode and disconnect from an AP if it was previously connected
|
||||
@ -36,7 +36,7 @@ void setup()
|
||||
* https://docs.espressif.com/projects/arduino-esp32/en/latest/api/wifi.html
|
||||
*/
|
||||
|
||||
if(err == ESP_FAIL) {
|
||||
if(err == false) {
|
||||
Serial.println("Dual Antenna configuration failed!");
|
||||
} else {
|
||||
Serial.println("Dual Antenna configuration successfuly done!");
|
||||
|
@ -3,7 +3,7 @@ version=2.0.0
|
||||
author=Hristo Gochkov
|
||||
maintainer=Hristo Gochkov <hristo@espressif.com>
|
||||
sentence=Enables network connection (local and Internet) using the ESP32 built-in WiFi.
|
||||
paragraph=With this library you can instantiate Servers, Clients and send/receive UDP packets through WiFi. The shield can connect either to open or encrypted networks (WEP, WPA). The IP address can be assigned statically or through a DHCP. The library can also manage DNS.
|
||||
paragraph=With this library you can instantiate Servers, Clients and send/receive UDP packets through WiFi. The shield can connect either to open or encrypted networks. The IP address can be assigned statically or through a DHCP. The library can also manage DNS.
|
||||
category=Communication
|
||||
url=
|
||||
architectures=esp32
|
||||
|
@ -47,7 +47,7 @@ extern "C" {
|
||||
// -----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
esp_netif_t* get_esp_interface_netif(esp_interface_t interface);
|
||||
esp_err_t set_esp_interface_ip(esp_interface_t interface, IPAddress local_ip=IPAddress(), IPAddress gateway=IPAddress(), IPAddress subnet=IPAddress());
|
||||
esp_err_t set_esp_interface_ip(esp_interface_t interface, IPAddress local_ip=INADDR_NONE, IPAddress gateway=INADDR_NONE, IPAddress subnet=INADDR_NONE, IPAddress dhcp_lease_start=INADDR_NONE);
|
||||
static bool softap_config_equal(const wifi_config_t& lhs, const wifi_config_t& rhs);
|
||||
|
||||
static size_t _wifi_strncpy(char * dst, const char * src, size_t dst_len){
|
||||
@ -195,7 +195,7 @@ String WiFiAPClass::softAPSSID() const
|
||||
* @param gateway gateway IP
|
||||
* @param subnet subnet mask
|
||||
*/
|
||||
bool WiFiAPClass::softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet)
|
||||
bool WiFiAPClass::softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dhcp_lease_start)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
@ -204,7 +204,7 @@ bool WiFiAPClass::softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress
|
||||
return false;
|
||||
}
|
||||
|
||||
err = set_esp_interface_ip(ESP_IF_WIFI_AP, local_ip, gateway, subnet);
|
||||
err = set_esp_interface_ip(ESP_IF_WIFI_AP, local_ip, gateway, subnet, dhcp_lease_start);
|
||||
return err == ESP_OK;
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ class WiFiAPClass
|
||||
public:
|
||||
|
||||
bool softAP(const char* ssid, const char* passphrase = NULL, int channel = 1, int ssid_hidden = 0, int max_connection = 4, bool ftm_responder = false);
|
||||
bool softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet);
|
||||
bool softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dhcp_lease_start = INADDR_NONE);
|
||||
bool softAPdisconnect(bool wifioff = false);
|
||||
|
||||
uint8_t softAPgetStationNum();
|
||||
|
@ -175,11 +175,11 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
WiFiClient::WiFiClient():_connected(false),next(NULL)
|
||||
WiFiClient::WiFiClient():_connected(false),_timeout(WIFI_CLIENT_DEF_CONN_TIMEOUT_MS),next(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
WiFiClient::WiFiClient(int fd):_connected(true),next(NULL)
|
||||
WiFiClient::WiFiClient(int fd):_connected(true),_timeout(WIFI_CLIENT_DEF_CONN_TIMEOUT_MS),next(NULL)
|
||||
{
|
||||
clientSocketHandle.reset(new WiFiClientSocketHandle(fd));
|
||||
_rxBuffer.reset(new WiFiClientRxBuffer(fd));
|
||||
@ -208,10 +208,11 @@ void WiFiClient::stop()
|
||||
|
||||
int WiFiClient::connect(IPAddress ip, uint16_t port)
|
||||
{
|
||||
return connect(ip,port,WIFI_CLIENT_DEF_CONN_TIMEOUT_MS);
|
||||
}
|
||||
int WiFiClient::connect(IPAddress ip, uint16_t port, int32_t timeout )
|
||||
return connect(ip,port,_timeout);
|
||||
}
|
||||
int WiFiClient::connect(IPAddress ip, uint16_t port, int32_t timeout)
|
||||
{
|
||||
_timeout = timeout;
|
||||
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sockfd < 0) {
|
||||
log_e("socket: %d", errno);
|
||||
@ -229,8 +230,8 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
|
||||
struct timeval tv;
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(sockfd, &fdset);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = timeout * 1000;
|
||||
tv.tv_sec = _timeout / 1000;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
#ifdef ESP_IDF_VERSION_MAJOR
|
||||
int res = lwip_connect(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
|
||||
@ -243,13 +244,13 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
|
||||
return 0;
|
||||
}
|
||||
|
||||
res = select(sockfd + 1, nullptr, &fdset, nullptr, timeout<0 ? nullptr : &tv);
|
||||
res = select(sockfd + 1, nullptr, &fdset, nullptr, _timeout<0 ? nullptr : &tv);
|
||||
if (res < 0) {
|
||||
log_e("select on fd %d, errno: %d, \"%s\"", sockfd, errno, strerror(errno));
|
||||
close(sockfd);
|
||||
return 0;
|
||||
} else if (res == 0) {
|
||||
log_i("select returned due to timeout %d ms for fd %d", timeout, sockfd);
|
||||
log_i("select returned due to timeout %d ms for fd %d", _timeout, sockfd);
|
||||
close(sockfd);
|
||||
return 0;
|
||||
} else {
|
||||
@ -270,18 +271,28 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
|
||||
}
|
||||
}
|
||||
|
||||
#define ROE_WIFICLIENT(x,msg) { if (((x)<0)) { log_e("Setsockopt '" msg "'' on fd %d failed. errno: %d, \"%s\"", sockfd, errno, strerror(errno)); return 0; }}
|
||||
ROE_WIFICLIENT(setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)),"SO_SNDTIMEO");
|
||||
ROE_WIFICLIENT(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)),"SO_RCVTIMEO");
|
||||
|
||||
// These are also set in WiFiClientSecure, should be set here too?
|
||||
//ROE_WIFICLIENT(setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable)),"TCP_NODELAY");
|
||||
//ROE_WIFICLIENT (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable)),"SO_KEEPALIVE");
|
||||
|
||||
fcntl( sockfd, F_SETFL, fcntl( sockfd, F_GETFL, 0 ) & (~O_NONBLOCK) );
|
||||
clientSocketHandle.reset(new WiFiClientSocketHandle(sockfd));
|
||||
_rxBuffer.reset(new WiFiClientRxBuffer(sockfd));
|
||||
|
||||
_connected = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int WiFiClient::connect(const char *host, uint16_t port)
|
||||
{
|
||||
return connect(host,port,WIFI_CLIENT_DEF_CONN_TIMEOUT_MS);
|
||||
}
|
||||
int WiFiClient::connect(const char *host, uint16_t port, int32_t timeout )
|
||||
return connect(host,port,_timeout);
|
||||
}
|
||||
|
||||
int WiFiClient::connect(const char *host, uint16_t port, int32_t timeout)
|
||||
{
|
||||
IPAddress srv((uint32_t)0);
|
||||
if(!WiFiGenericClass::hostByName(host, srv)){
|
||||
@ -301,14 +312,20 @@ int WiFiClient::setSocketOption(int option, char* value, size_t len)
|
||||
|
||||
int WiFiClient::setTimeout(uint32_t seconds)
|
||||
{
|
||||
Client::setTimeout(seconds * 1000);
|
||||
struct timeval tv;
|
||||
tv.tv_sec = seconds;
|
||||
tv.tv_usec = 0;
|
||||
if(setSocketOption(SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)) < 0) {
|
||||
return -1;
|
||||
Client::setTimeout(seconds * 1000); // This should be here?
|
||||
_timeout = seconds * 1000;
|
||||
if(fd() >= 0) {
|
||||
struct timeval tv;
|
||||
tv.tv_sec = seconds;
|
||||
tv.tv_usec = 0;
|
||||
if(setSocketOption(SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return setSocketOption(SO_SNDTIMEO, (char *)&tv, sizeof(struct timeval));
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
return setSocketOption(SO_SNDTIMEO, (char *)&tv, sizeof(struct timeval));
|
||||
}
|
||||
|
||||
int WiFiClient::setOption(int option, int *value)
|
||||
|
@ -42,6 +42,7 @@ protected:
|
||||
std::shared_ptr<WiFiClientSocketHandle> clientSocketHandle;
|
||||
std::shared_ptr<WiFiClientRxBuffer> _rxBuffer;
|
||||
bool _connected;
|
||||
int _timeout;
|
||||
|
||||
public:
|
||||
WiFiClient *next;
|
||||
|
@ -48,6 +48,7 @@ extern "C" {
|
||||
#include <vector>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#define _byte_swap32(num) (((num>>24)&0xff) | ((num<<8)&0xff0000) | ((num>>8)&0xff00) | ((num<<24)&0xff000000))
|
||||
ESP_EVENT_DEFINE_BASE(ARDUINO_EVENTS);
|
||||
/*
|
||||
* Private (exposable) methods
|
||||
@ -82,7 +83,7 @@ esp_err_t set_esp_interface_hostname(esp_interface_t interface, const char * hos
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t set_esp_interface_ip(esp_interface_t interface, IPAddress local_ip=IPAddress(), IPAddress gateway=IPAddress(), IPAddress subnet=IPAddress()){
|
||||
esp_err_t set_esp_interface_ip(esp_interface_t interface, IPAddress local_ip=IPAddress(), IPAddress gateway=IPAddress(), IPAddress subnet=IPAddress(), IPAddress dhcp_lease_start=INADDR_NONE){
|
||||
esp_netif_t *esp_netif = esp_netifs[interface];
|
||||
esp_netif_dhcp_status_t status = ESP_NETIF_DHCP_INIT;
|
||||
esp_netif_ip_info_t info;
|
||||
@ -138,20 +139,64 @@ esp_err_t set_esp_interface_ip(esp_interface_t interface, IPAddress local_ip=IPA
|
||||
|
||||
dhcps_lease_t lease;
|
||||
lease.enable = true;
|
||||
uint32_t dhcp_ipaddr = static_cast<uint32_t>(local_ip);
|
||||
// prevents DHCP lease range to overflow subnet/24 range
|
||||
// there will be 11 addresses for DHCP to lease
|
||||
uint8_t leaseStart = (uint8_t)(~subnet[3] - 12);
|
||||
if ((local_ip[3]) < leaseStart) {
|
||||
lease.start_ip.addr = dhcp_ipaddr + (1 << 24);
|
||||
lease.end_ip.addr = dhcp_ipaddr + (11 << 24);
|
||||
} else {
|
||||
// make range stay in the begining of the netmask range
|
||||
dhcp_ipaddr = (dhcp_ipaddr & 0x00FFFFFF);
|
||||
lease.start_ip.addr = dhcp_ipaddr + (1 << 24);
|
||||
lease.end_ip.addr = dhcp_ipaddr + (11 << 24);
|
||||
uint8_t CIDR = WiFiGenericClass::calculateSubnetCIDR(subnet);
|
||||
log_v("SoftAP: %s | Gateway: %s | DHCP Start: %s | Netmask: %s", local_ip.toString().c_str(), gateway.toString().c_str(), dhcp_lease_start.toString().c_str(), subnet.toString().c_str());
|
||||
// netmask must have room for at least 12 IP addresses (AP + GW + 10 DHCP Leasing addresses)
|
||||
// netmask also must be limited to the last 8 bits of IPv4, otherwise this function won't work
|
||||
// IDF NETIF checks netmask for the 3rd byte: https://github.com/espressif/esp-idf/blob/master/components/esp_netif/lwip/esp_netif_lwip.c#L1857-L1862
|
||||
if (CIDR > 28 || CIDR < 24) {
|
||||
log_e("Bad netmask. It must be from /24 to /28 (255.255.255. 0<->240)");
|
||||
return ESP_FAIL; // ESP_FAIL if initializing failed
|
||||
}
|
||||
// The code below is ready for any netmask, not limited to 255.255.255.0
|
||||
uint32_t netmask = _byte_swap32(info.netmask.addr);
|
||||
uint32_t ap_ipaddr = _byte_swap32(info.ip.addr);
|
||||
uint32_t dhcp_ipaddr = _byte_swap32(static_cast<uint32_t>(dhcp_lease_start));
|
||||
dhcp_ipaddr = dhcp_ipaddr == 0 ? ap_ipaddr + 1 : dhcp_ipaddr;
|
||||
uint32_t leaseStartMax = ~netmask - 10;
|
||||
// there will be 10 addresses for DHCP to lease
|
||||
lease.start_ip.addr = dhcp_ipaddr;
|
||||
lease.end_ip.addr = lease.start_ip.addr + 10;
|
||||
// Check if local_ip is in the same subnet as the dhcp leasing range initial address
|
||||
if ((ap_ipaddr & netmask) != (dhcp_ipaddr & netmask)) {
|
||||
log_e("The AP IP address (%s) and the DHCP start address (%s) must be in the same subnet",
|
||||
local_ip.toString().c_str(), IPAddress(_byte_swap32(dhcp_ipaddr)).toString().c_str());
|
||||
return ESP_FAIL; // ESP_FAIL if initializing failed
|
||||
}
|
||||
// prevents DHCP lease range to overflow subnet range
|
||||
if ((dhcp_ipaddr & ~netmask) >= leaseStartMax) {
|
||||
// make first DHCP lease addr stay in the begining of the netmask range
|
||||
lease.start_ip.addr = (dhcp_ipaddr & netmask) + 1;
|
||||
lease.end_ip.addr = lease.start_ip.addr + 10;
|
||||
log_w("DHCP Lease out of range - Changing DHCP leasing start to %s", IPAddress(_byte_swap32(lease.start_ip.addr)).toString().c_str());
|
||||
}
|
||||
// Check if local_ip is within DHCP range
|
||||
if (ap_ipaddr >= lease.start_ip.addr && ap_ipaddr <= lease.end_ip.addr) {
|
||||
log_e("The AP IP address (%s) can't be within the DHCP range (%s -- %s)",
|
||||
local_ip.toString().c_str(), IPAddress(_byte_swap32(lease.start_ip.addr)).toString().c_str(), IPAddress(_byte_swap32(lease.end_ip.addr)).toString().c_str());
|
||||
return ESP_FAIL; // ESP_FAIL if initializing failed
|
||||
}
|
||||
// Check if gateway is within DHCP range
|
||||
uint32_t gw_ipaddr = _byte_swap32(info.gw.addr);
|
||||
bool gw_in_same_subnet = (gw_ipaddr & netmask) == (ap_ipaddr & netmask);
|
||||
if (gw_in_same_subnet && gw_ipaddr >= lease.start_ip.addr && gw_ipaddr <= lease.end_ip.addr) {
|
||||
log_e("The GatewayP address (%s) can't be within the DHCP range (%s -- %s)",
|
||||
gateway.toString().c_str(), IPAddress(_byte_swap32(lease.start_ip.addr)).toString().c_str(), IPAddress(_byte_swap32(lease.end_ip.addr)).toString().c_str());
|
||||
return ESP_FAIL; // ESP_FAIL if initializing failed
|
||||
}
|
||||
// all done, just revert back byte order of DHCP lease range
|
||||
lease.start_ip.addr = _byte_swap32(lease.start_ip.addr);
|
||||
lease.end_ip.addr = _byte_swap32(lease.end_ip.addr);
|
||||
log_v("DHCP Server Range: %s to %s", IPAddress(lease.start_ip.addr).toString().c_str(), IPAddress(lease.end_ip.addr).toString().c_str());
|
||||
err = tcpip_adapter_dhcps_option(
|
||||
(tcpip_adapter_dhcp_option_mode_t)TCPIP_ADAPTER_OP_SET,
|
||||
(tcpip_adapter_dhcp_option_id_t)ESP_NETIF_SUBNET_MASK,
|
||||
(void*)&info.netmask.addr, sizeof(info.netmask.addr)
|
||||
);
|
||||
if(err){
|
||||
log_e("DHCPS Set Netmask Failed! 0x%04x", err);
|
||||
return err;
|
||||
}
|
||||
log_v("DHCP Server Range: %s to %s", IPAddress(lease.start_ip.addr).toString(), IPAddress(lease.end_ip.addr).toString());
|
||||
err = tcpip_adapter_dhcps_option(
|
||||
(tcpip_adapter_dhcp_option_mode_t)TCPIP_ADAPTER_OP_SET,
|
||||
(tcpip_adapter_dhcp_option_id_t)REQUESTED_IP_ADDRESS,
|
||||
@ -161,7 +206,6 @@ esp_err_t set_esp_interface_ip(esp_interface_t interface, IPAddress local_ip=IPA
|
||||
log_e("DHCPS Set Lease Failed! 0x%04x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = esp_netif_dhcps_start(esp_netif);
|
||||
if(err){
|
||||
log_e("DHCPS Start Failed! 0x%04x", err);
|
||||
@ -195,6 +239,7 @@ esp_err_t set_esp_interface_dns(esp_interface_t interface, IPAddress main_dns=IP
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
|
||||
static const char * auth_mode_str(int authmode)
|
||||
{
|
||||
switch (authmode) {
|
||||
@ -216,11 +261,21 @@ static const char * auth_mode_str(int authmode)
|
||||
case WIFI_AUTH_WPA2_ENTERPRISE:
|
||||
return ("WPA2_ENTERPRISE");
|
||||
break;
|
||||
case WIFI_AUTH_WPA3_PSK:
|
||||
return ("WPA3_PSK");
|
||||
break;
|
||||
case WIFI_AUTH_WPA2_WPA3_PSK:
|
||||
return ("WPA2_WPA3_PSK");
|
||||
break;
|
||||
case WIFI_AUTH_WAPI_PSK:
|
||||
return ("WPAPI_PSK");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ("UNKNOWN");
|
||||
}
|
||||
#endif
|
||||
|
||||
static char default_hostname[32] = {0,};
|
||||
static const char * get_esp_netif_hostname(){
|
||||
@ -286,24 +341,32 @@ static void _arduino_event_cb(void* arg, esp_event_base_t event_base, int32_t ev
|
||||
log_v("STA Stopped");
|
||||
arduino_event.event_id = ARDUINO_EVENT_WIFI_STA_STOP;
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_AUTHMODE_CHANGE) {
|
||||
wifi_event_sta_authmode_change_t * event = (wifi_event_sta_authmode_change_t*)event_data;
|
||||
log_v("STA Auth Mode Changed: From: %s, To: %s", auth_mode_str(event->old_mode), auth_mode_str(event->new_mode));
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
|
||||
wifi_event_sta_authmode_change_t * event = (wifi_event_sta_authmode_change_t*)event_data;
|
||||
log_v("STA Auth Mode Changed: From: %s, To: %s", auth_mode_str(event->old_mode), auth_mode_str(event->new_mode));
|
||||
#endif
|
||||
arduino_event.event_id = ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE;
|
||||
memcpy(&arduino_event.event_info.wifi_sta_authmode_change, event_data, sizeof(wifi_event_sta_authmode_change_t));
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_CONNECTED) {
|
||||
wifi_event_sta_connected_t * event = (wifi_event_sta_connected_t*)event_data;
|
||||
log_v("STA Connected: SSID: %s, BSSID: " MACSTR ", Channel: %u, Auth: %s", event->ssid, MAC2STR(event->bssid), event->channel, auth_mode_str(event->authmode));
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
|
||||
wifi_event_sta_connected_t * event = (wifi_event_sta_connected_t*)event_data;
|
||||
log_v("STA Connected: SSID: %s, BSSID: " MACSTR ", Channel: %u, Auth: %s", event->ssid, MAC2STR(event->bssid), event->channel, auth_mode_str(event->authmode));
|
||||
#endif
|
||||
arduino_event.event_id = ARDUINO_EVENT_WIFI_STA_CONNECTED;
|
||||
memcpy(&arduino_event.event_info.wifi_sta_connected, event_data, sizeof(wifi_event_sta_connected_t));
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||
wifi_event_sta_disconnected_t * event = (wifi_event_sta_disconnected_t*)event_data;
|
||||
log_v("STA Disconnected: SSID: %s, BSSID: " MACSTR ", Reason: %u", event->ssid, MAC2STR(event->bssid), event->reason);
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
|
||||
wifi_event_sta_disconnected_t * event = (wifi_event_sta_disconnected_t*)event_data;
|
||||
log_v("STA Disconnected: SSID: %s, BSSID: " MACSTR ", Reason: %u", event->ssid, MAC2STR(event->bssid), event->reason);
|
||||
#endif
|
||||
arduino_event.event_id = ARDUINO_EVENT_WIFI_STA_DISCONNECTED;
|
||||
memcpy(&arduino_event.event_info.wifi_sta_disconnected, event_data, sizeof(wifi_event_sta_disconnected_t));
|
||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
|
||||
log_v("STA Got %sIP:" IPSTR, event->ip_changed?"New ":"Same ", IP2STR(&event->ip_info.ip));
|
||||
arduino_event.event_id = ARDUINO_EVENT_WIFI_STA_GOT_IP;
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
|
||||
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
|
||||
log_v("STA Got %sIP:" IPSTR, event->ip_changed?"New ":"Same ", IP2STR(&event->ip_info.ip));
|
||||
#endif
|
||||
arduino_event.event_id = ARDUINO_EVENT_WIFI_STA_GOT_IP;
|
||||
memcpy(&arduino_event.event_info.got_ip, event_data, sizeof(ip_event_got_ip_t));
|
||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_LOST_IP) {
|
||||
log_v("STA IP Lost");
|
||||
@ -313,8 +376,10 @@ static void _arduino_event_cb(void* arg, esp_event_base_t event_base, int32_t ev
|
||||
* SCAN
|
||||
* */
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_SCAN_DONE) {
|
||||
wifi_event_sta_scan_done_t * event = (wifi_event_sta_scan_done_t*)event_data;
|
||||
log_v("SCAN Done: ID: %u, Status: %u, Results: %u", event->scan_id, event->status, event->number);
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
|
||||
wifi_event_sta_scan_done_t * event = (wifi_event_sta_scan_done_t*)event_data;
|
||||
log_v("SCAN Done: ID: %u, Status: %u, Results: %u", event->scan_id, event->status, event->number);
|
||||
#endif
|
||||
arduino_event.event_id = ARDUINO_EVENT_WIFI_SCAN_DONE;
|
||||
memcpy(&arduino_event.event_info.wifi_scan_done, event_data, sizeof(wifi_event_sta_scan_done_t));
|
||||
|
||||
@ -328,24 +393,32 @@ static void _arduino_event_cb(void* arg, esp_event_base_t event_base, int32_t ev
|
||||
log_v("AP Stopped");
|
||||
arduino_event.event_id = ARDUINO_EVENT_WIFI_AP_STOP;
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_PROBEREQRECVED) {
|
||||
wifi_event_ap_probe_req_rx_t * event = (wifi_event_ap_probe_req_rx_t*)event_data;
|
||||
log_v("AP Probe Request: RSSI: %d, MAC: " MACSTR, event->rssi, MAC2STR(event->mac));
|
||||
arduino_event.event_id = ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED;
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
|
||||
wifi_event_ap_probe_req_rx_t * event = (wifi_event_ap_probe_req_rx_t*)event_data;
|
||||
log_v("AP Probe Request: RSSI: %d, MAC: " MACSTR, event->rssi, MAC2STR(event->mac));
|
||||
#endif
|
||||
arduino_event.event_id = ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED;
|
||||
memcpy(&arduino_event.event_info.wifi_ap_probereqrecved, event_data, sizeof(wifi_event_ap_probe_req_rx_t));
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_STACONNECTED) {
|
||||
wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
|
||||
log_v("AP Station Connected: MAC: " MACSTR ", AID: %d", MAC2STR(event->mac), event->aid);
|
||||
arduino_event.event_id = ARDUINO_EVENT_WIFI_AP_STACONNECTED;
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
|
||||
wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
|
||||
log_v("AP Station Connected: MAC: " MACSTR ", AID: %d", MAC2STR(event->mac), event->aid);
|
||||
#endif
|
||||
arduino_event.event_id = ARDUINO_EVENT_WIFI_AP_STACONNECTED;
|
||||
memcpy(&arduino_event.event_info.wifi_ap_staconnected, event_data, sizeof(wifi_event_ap_staconnected_t));
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_STADISCONNECTED) {
|
||||
wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
|
||||
log_v("AP Station Disconnected: MAC: " MACSTR ", AID: %d", MAC2STR(event->mac), event->aid);
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
|
||||
wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
|
||||
log_v("AP Station Disconnected: MAC: " MACSTR ", AID: %d", MAC2STR(event->mac), event->aid);
|
||||
#endif
|
||||
arduino_event.event_id = ARDUINO_EVENT_WIFI_AP_STADISCONNECTED;
|
||||
memcpy(&arduino_event.event_info.wifi_ap_stadisconnected, event_data, sizeof(wifi_event_ap_stadisconnected_t));
|
||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_AP_STAIPASSIGNED) {
|
||||
ip_event_ap_staipassigned_t * event = (ip_event_ap_staipassigned_t*)event_data;
|
||||
log_v("AP Station IP Assigned:" IPSTR, IP2STR(&event->ip));
|
||||
arduino_event.event_id = ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED;
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
|
||||
ip_event_ap_staipassigned_t * event = (ip_event_ap_staipassigned_t*)event_data;
|
||||
log_v("AP Station IP Assigned:" IPSTR, IP2STR(&event->ip));
|
||||
#endif
|
||||
arduino_event.event_id = ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED;
|
||||
memcpy(&arduino_event.event_info.wifi_ap_staipassigned, event_data, sizeof(ip_event_ap_staipassigned_t));
|
||||
|
||||
/*
|
||||
@ -353,7 +426,6 @@ static void _arduino_event_cb(void* arg, esp_event_base_t event_base, int32_t ev
|
||||
* */
|
||||
} else if (event_base == ETH_EVENT && event_id == ETHERNET_EVENT_CONNECTED) {
|
||||
log_v("Ethernet Link Up");
|
||||
esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;
|
||||
arduino_event.event_id = ARDUINO_EVENT_ETH_CONNECTED;
|
||||
memcpy(&arduino_event.event_info.eth_connected, event_data, sizeof(esp_eth_handle_t));
|
||||
} else if (event_base == ETH_EVENT && event_id == ETHERNET_EVENT_DISCONNECTED) {
|
||||
@ -366,9 +438,11 @@ static void _arduino_event_cb(void* arg, esp_event_base_t event_base, int32_t ev
|
||||
log_v("Ethernet Stopped");
|
||||
arduino_event.event_id = ARDUINO_EVENT_ETH_STOP;
|
||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_ETH_GOT_IP) {
|
||||
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
|
||||
log_v("Ethernet got %sip:" IPSTR, event->ip_changed?"new":"", IP2STR(&event->ip_info.ip));
|
||||
arduino_event.event_id = ARDUINO_EVENT_ETH_GOT_IP;
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
|
||||
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
|
||||
log_v("Ethernet got %sip:" IPSTR, event->ip_changed?"new":"", IP2STR(&event->ip_info.ip));
|
||||
#endif
|
||||
arduino_event.event_id = ARDUINO_EVENT_ETH_GOT_IP;
|
||||
memcpy(&arduino_event.event_info.got_ip, event_data, sizeof(ip_event_got_ip_t));
|
||||
|
||||
/*
|
||||
@ -393,13 +467,11 @@ static void _arduino_event_cb(void* arg, esp_event_base_t event_base, int32_t ev
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_WPS_ER_SUCCESS) {
|
||||
arduino_event.event_id = ARDUINO_EVENT_WPS_ER_SUCCESS;
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_WPS_ER_FAILED) {
|
||||
wifi_event_sta_wps_fail_reason_t * event = (wifi_event_sta_wps_fail_reason_t*)event_data;
|
||||
arduino_event.event_id = ARDUINO_EVENT_WPS_ER_FAILED;
|
||||
memcpy(&arduino_event.event_info.wps_fail_reason, event_data, sizeof(wifi_event_sta_wps_fail_reason_t));
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_WPS_ER_TIMEOUT) {
|
||||
arduino_event.event_id = ARDUINO_EVENT_WPS_ER_TIMEOUT;
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_WPS_ER_PIN) {
|
||||
wifi_event_sta_wps_er_pin_t * event = (wifi_event_sta_wps_er_pin_t*)event_data;
|
||||
arduino_event.event_id = ARDUINO_EVENT_WPS_ER_PIN;
|
||||
memcpy(&arduino_event.event_info.wps_er_pin, event_data, sizeof(wifi_event_sta_wps_er_pin_t));
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_WPS_ER_PBC_OVERLAP) {
|
||||
@ -409,7 +481,6 @@ static void _arduino_event_cb(void* arg, esp_event_base_t event_base, int32_t ev
|
||||
* FTM
|
||||
* */
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_FTM_REPORT) {
|
||||
wifi_event_ftm_report_t * event = (wifi_event_ftm_report_t*)event_data;
|
||||
arduino_event.event_id = ARDUINO_EVENT_WIFI_FTM_REPORT;
|
||||
memcpy(&arduino_event.event_info.wifi_ftm_report, event_data, sizeof(wifi_event_ftm_report_t));
|
||||
|
||||
@ -424,8 +495,10 @@ static void _arduino_event_cb(void* arg, esp_event_base_t event_base, int32_t ev
|
||||
log_v("SC Found Channel");
|
||||
arduino_event.event_id = ARDUINO_EVENT_SC_FOUND_CHANNEL;
|
||||
} else if (event_base == SC_EVENT && event_id == SC_EVENT_GOT_SSID_PSWD) {
|
||||
smartconfig_event_got_ssid_pswd_t *event = (smartconfig_event_got_ssid_pswd_t *)event_data;
|
||||
log_v("SC: SSID: %s, Password: %s", (const char *)event->ssid, (const char *)event->password);
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
|
||||
smartconfig_event_got_ssid_pswd_t *event = (smartconfig_event_got_ssid_pswd_t *)event_data;
|
||||
log_v("SC: SSID: %s, Password: %s", (const char *)event->ssid, (const char *)event->password);
|
||||
#endif
|
||||
arduino_event.event_id = ARDUINO_EVENT_SC_GOT_SSID_PSWD;
|
||||
memcpy(&arduino_event.event_info.sc_got_ssid_pswd, event_data, sizeof(smartconfig_event_got_ssid_pswd_t));
|
||||
|
||||
@ -450,13 +523,17 @@ static void _arduino_event_cb(void* arg, esp_event_base_t event_base, int32_t ev
|
||||
wifi_prov_mgr_deinit();
|
||||
arduino_event.event_id = ARDUINO_EVENT_PROV_END;
|
||||
} else if (event_base == WIFI_PROV_EVENT && event_id == WIFI_PROV_CRED_RECV) {
|
||||
wifi_sta_config_t *event = (wifi_sta_config_t *)event_data;
|
||||
log_v("Provisioned Credentials: SSID: %s, Password: %s", (const char *) event->ssid, (const char *) event->password);
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
|
||||
wifi_sta_config_t *event = (wifi_sta_config_t *)event_data;
|
||||
log_v("Provisioned Credentials: SSID: %s, Password: %s", (const char *) event->ssid, (const char *) event->password);
|
||||
#endif
|
||||
arduino_event.event_id = ARDUINO_EVENT_PROV_CRED_RECV;
|
||||
memcpy(&arduino_event.event_info.prov_cred_recv, event_data, sizeof(wifi_sta_config_t));
|
||||
} else if (event_base == WIFI_PROV_EVENT && event_id == WIFI_PROV_CRED_FAIL) {
|
||||
wifi_prov_sta_fail_reason_t *reason = (wifi_prov_sta_fail_reason_t *)event_data;
|
||||
log_e("Provisioning Failed: Reason : %s", (*reason == WIFI_PROV_STA_AUTH_ERROR)?"Authentication Failed":"AP Not Found");
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
|
||||
wifi_prov_sta_fail_reason_t *reason = (wifi_prov_sta_fail_reason_t *)event_data;
|
||||
log_e("Provisioning Failed: Reason : %s", (*reason == WIFI_PROV_STA_AUTH_ERROR)?"Authentication Failed":"AP Not Found");
|
||||
#endif
|
||||
arduino_event.event_id = ARDUINO_EVENT_PROV_CRED_FAIL;
|
||||
memcpy(&arduino_event.event_info.prov_fail_reason, event_data, sizeof(wifi_prov_sta_fail_reason_t));
|
||||
} else if (event_base == WIFI_PROV_EVENT && event_id == WIFI_PROV_CRED_SUCCESS) {
|
||||
@ -1259,6 +1336,7 @@ bool WiFiGenericClass::setDualAntennaConfig(uint8_t gpio_ant1, uint8_t gpio_ant2
|
||||
// Set antenna default configuration
|
||||
wifi_ant_config_t ant_config = {
|
||||
.rx_ant_mode = WIFI_ANT_MODE_AUTO,
|
||||
.rx_ant_default = WIFI_ANT_MAX, // Ignored in AUTO mode
|
||||
.tx_ant_mode = WIFI_ANT_MODE_AUTO,
|
||||
.enabled_ant0 = 0,
|
||||
.enabled_ant1 = 1,
|
||||
|
@ -51,7 +51,7 @@ extern "C" {
|
||||
|
||||
esp_netif_t* get_esp_interface_netif(esp_interface_t interface);
|
||||
esp_err_t set_esp_interface_dns(esp_interface_t interface, IPAddress main_dns=IPAddress(), IPAddress backup_dns=IPAddress(), IPAddress fallback_dns=IPAddress());
|
||||
esp_err_t set_esp_interface_ip(esp_interface_t interface, IPAddress local_ip=IPAddress(), IPAddress gateway=IPAddress(), IPAddress subnet=IPAddress());
|
||||
esp_err_t set_esp_interface_ip(esp_interface_t interface, IPAddress local_ip=INADDR_NONE, IPAddress gateway=INADDR_NONE, IPAddress subnet=INADDR_NONE, IPAddress dhcp_lease_start=INADDR_NONE);
|
||||
static bool sta_config_equal(const wifi_config_t& lhs, const wifi_config_t& rhs);
|
||||
|
||||
static size_t _wifi_strncpy(char * dst, const char * src, size_t dst_len){
|
||||
@ -83,7 +83,7 @@ static bool sta_config_equal(const wifi_config_t& lhs, const wifi_config_t& rhs)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void wifi_sta_config(wifi_config_t * wifi_config, const char * ssid=NULL, const char * password=NULL, const uint8_t * bssid=NULL, uint8_t channel=0, wifi_scan_method_t scan_method=WIFI_ALL_CHANNEL_SCAN, wifi_sort_method_t sort_method=WIFI_CONNECT_AP_BY_SIGNAL, uint16_t listen_interval=0, bool pmf_required=false){
|
||||
static void wifi_sta_config(wifi_config_t * wifi_config, const char * ssid=NULL, const char * password=NULL, const uint8_t * bssid=NULL, uint8_t channel=0, wifi_auth_mode_t min_security=WIFI_AUTH_WPA2_PSK, wifi_scan_method_t scan_method=WIFI_ALL_CHANNEL_SCAN, wifi_sort_method_t sort_method=WIFI_CONNECT_AP_BY_SIGNAL, uint16_t listen_interval=0, bool pmf_required=false){
|
||||
wifi_config->sta.channel = channel;
|
||||
wifi_config->sta.listen_interval = listen_interval;
|
||||
wifi_config->sta.scan_method = scan_method;//WIFI_ALL_CHANNEL_SCAN or WIFI_FAST_SCAN
|
||||
@ -99,7 +99,7 @@ static void wifi_sta_config(wifi_config_t * wifi_config, const char * ssid=NULL,
|
||||
if(ssid != NULL && ssid[0] != 0){
|
||||
_wifi_strncpy((char*)wifi_config->sta.ssid, ssid, 32);
|
||||
if(password != NULL && password[0] != 0){
|
||||
wifi_config->sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
|
||||
wifi_config->sta.threshold.authmode = min_security;
|
||||
_wifi_strncpy((char*)wifi_config->sta.password, password, 64);
|
||||
}
|
||||
if(bssid != NULL){
|
||||
@ -115,6 +115,9 @@ static void wifi_sta_config(wifi_config_t * wifi_config, const char * ssid=NULL,
|
||||
|
||||
bool WiFiSTAClass::_autoReconnect = true;
|
||||
bool WiFiSTAClass::_useStaticIp = false;
|
||||
wifi_auth_mode_t WiFiSTAClass::_minSecurity = WIFI_AUTH_WPA2_PSK;
|
||||
wifi_scan_method_t WiFiSTAClass::_scanMethod = WIFI_FAST_SCAN;
|
||||
wifi_sort_method_t WiFiSTAClass::_sortMethod = WIFI_CONNECT_AP_BY_SIGNAL;
|
||||
|
||||
static wl_status_t _sta_status = WL_NO_SHIELD;
|
||||
static EventGroupHandle_t _sta_status_group = NULL;
|
||||
@ -243,12 +246,7 @@ wl_status_t WiFiSTAClass::begin(const char* ssid, const char *passphrase, int32_
|
||||
_wifi_strncpy(reinterpret_cast<char*>(conf.sta.password), passphrase, 64);
|
||||
}
|
||||
|
||||
if(channel == 0) {
|
||||
// If no specific channel specified, then do an slower WIFI_ALL_CHANNEL_SCAN
|
||||
wifi_sta_config(&conf, ssid, passphrase, bssid, channel, WIFI_ALL_CHANNEL_SCAN);
|
||||
}
|
||||
else
|
||||
wifi_sta_config(&conf, ssid, passphrase, bssid, channel, WIFI_FAST_SCAN);
|
||||
wifi_sta_config(&conf, ssid, passphrase, bssid, channel, _minSecurity, _scanMethod, _sortMethod);
|
||||
|
||||
wifi_config_t current_conf;
|
||||
if(esp_wifi_get_config((wifi_interface_t)ESP_IF_WIFI_STA, ¤t_conf) != ESP_OK){
|
||||
@ -404,6 +402,37 @@ bool WiFiSTAClass::isConnected()
|
||||
return (status() == WL_CONNECTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum security for AP to be considered connectable
|
||||
* Must be called before WiFi.begin()
|
||||
* @param minSecurity wifi_auth_mode_t
|
||||
*/
|
||||
void WiFiSTAClass::setMinSecurity(wifi_auth_mode_t minSecurity)
|
||||
{
|
||||
_minSecurity = minSecurity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the way that AP is chosen.
|
||||
* First SSID match[WIFI_FAST_SCAN] or Sorted[WIFI_ALL_CHANNEL_SCAN] (RSSI or Security)
|
||||
* Must be called before WiFi.begin()
|
||||
* @param scanMethod wifi_scan_method_t
|
||||
*/
|
||||
void WiFiSTAClass::setScanMethod(wifi_scan_method_t scanMethod)
|
||||
{
|
||||
_scanMethod = scanMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the way that AP is sorted. (requires scanMethod WIFI_ALL_CHANNEL_SCAN)
|
||||
* By SSID[WIFI_CONNECT_AP_BY_SIGNAL] or Security[WIFI_CONNECT_AP_BY_SECURITY]
|
||||
* Must be called before WiFi.begin()
|
||||
* @param sortMethod wifi_sort_method_t
|
||||
*/
|
||||
void WiFiSTAClass::setSortMethod(wifi_sort_method_t sortMethod)
|
||||
{
|
||||
_sortMethod = sortMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setting the ESP32 station to connect to the AP (which is recorded)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user