mirror of
https://github.com/espressif/esp-protocols.git
synced 2025-07-03 21:56:40 +02:00
Compare commits
119 Commits
console_cm
...
mdns-v1.7.
Author | SHA1 | Date | |
---|---|---|---|
dea5f1c431 | |||
384d1c23ba | |||
88162d1f3a | |||
e65f22ab6c | |||
7d29b47676 | |||
f1a72ec42c | |||
ce160505dc | |||
87e96b4682 | |||
5b2077e373 | |||
b45fe143a4 | |||
ee2fbbbee7 | |||
cb061c9c38 | |||
0690eba3a8 | |||
eb4ab52487 | |||
8fcad10ccf | |||
936e43f9d8 | |||
64d818b2d3 | |||
cd07228f81 | |||
1c6580e22b | |||
87f835af0f | |||
85a8dac42d | |||
39866116f5 | |||
7740b591b6 | |||
b57979d967 | |||
42674b49f9 | |||
e069ae7762 | |||
44d476fc50 | |||
55385ec312 | |||
a3c2bbed9e | |||
84c47c37f1 | |||
e7273c46ec | |||
2e7d240abd | |||
d4a004b5b4 | |||
9046af8f8d | |||
eeeb9006eb | |||
b167aa315f | |||
72ba24470d | |||
7dc87d28b2 | |||
ac6a388cdd | |||
76aaea08d2 | |||
5db32cce30 | |||
9bdd429c7c | |||
6f7c52cc3f | |||
27435b7f34 | |||
813331f003 | |||
bd23c233a4 | |||
4eda7d472f | |||
163029c0b6 | |||
96eae25096 | |||
ebec8eff63 | |||
4451a8c5ad | |||
6d19aabb02 | |||
9162de1150 | |||
dbd164dd91 | |||
90d663ad01 | |||
a83f1b6787 | |||
84caca465d | |||
8f81478fff | |||
ae5a8ceeda | |||
774bab22ea | |||
265e38d684 | |||
93f772171c | |||
4ad88e297f | |||
196198ecc9 | |||
e838bf03f4 | |||
99b54ac384 | |||
f5be2f4115 | |||
9b74256b51 | |||
3d8835cfb9 | |||
24f55ce9b4 | |||
8f8516cc3f | |||
75a8e8640a | |||
907087c09b | |||
68a9e14898 | |||
827ea65fd5 | |||
9537721600 | |||
4394f845fc | |||
9b0ba6060f | |||
7c6a3098af | |||
f3f3e23bec | |||
9ed835ba3f | |||
f12a205657 | |||
5bd82c01a5 | |||
b4cb8f8a66 | |||
0499ed93df | |||
ade9448c01 | |||
4745fc8fe1 | |||
73e523e736 | |||
3cd0ed377b | |||
95294f5f89 | |||
5dcc33300f | |||
840a561de4 | |||
e6fb8aa078 | |||
3b2c614d86 | |||
cdeab8f517 | |||
6cce87e465 | |||
d57b8c5b29 | |||
9c11003449 | |||
85a7fc772c | |||
b090a3cb69 | |||
42cde46c97 | |||
beb6e57e5e | |||
15d3a01e11 | |||
e12ecb8e89 | |||
54271a1b96 | |||
886215032f | |||
269351f41c | |||
5e929902c7 | |||
f7c0b7564a | |||
c989c6adae | |||
18f196fa1e | |||
1db83cd1ca | |||
247f1681e8 | |||
32387f7e39 | |||
dbc3ea6809 | |||
8b6ea3311a | |||
8e55b93b59 | |||
0cb59ff80d | |||
1284f66d58 |
@ -13,7 +13,7 @@ jobs:
|
||||
name: Build
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3"]
|
||||
idf_ver: ["latest", "release-v5.0", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4"]
|
||||
idf_target: ["esp32", "esp32s2"]
|
||||
example: ["asio_chat", "async_request", "socks4", "ssl_client_server", "tcp_echo_server", "udp_echo_server"]
|
||||
runs-on: ubuntu-22.04
|
||||
@ -64,7 +64,7 @@ jobs:
|
||||
name: Target tests
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest", "release-v5.0", "release-v5.2", "release-v5.3"]
|
||||
idf_ver: ["latest", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4"]
|
||||
idf_target: ["esp32"]
|
||||
example: ["asio_chat", "tcp_echo_server", "udp_echo_server", "ssl_client_server"]
|
||||
needs: build_asio
|
||||
|
1
.github/workflows/clang-tidy.yml
vendored
1
.github/workflows/clang-tidy.yml
vendored
@ -24,6 +24,7 @@ jobs:
|
||||
chmod +x clang-tidy-sarif
|
||||
curl -sSL https://raw.githubusercontent.com/espressif/idf-extra-components/master/.github/filter_sarif.py -o filter_sarif.py
|
||||
- name: Install pyclang
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
pip install pyclang~=0.2.0
|
||||
|
24
.github/workflows/mdns__host-tests.yml
vendored
24
.github/workflows/mdns__host-tests.yml
vendored
@ -35,30 +35,36 @@ jobs:
|
||||
# Next we run the pytest (using the console app)
|
||||
pytest
|
||||
|
||||
build_afl_host_test_mdns:
|
||||
host_compat_checks:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'mdns') || github.event_name == 'push'
|
||||
name: Build AFL host test
|
||||
name: Set of compatibility checks
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32"]
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: esp-protocols
|
||||
- name: Install Necessary Libs
|
||||
run: |
|
||||
apt-get update -y
|
||||
apt-get install -y libbsd-dev
|
||||
- name: Build ${{ matrix.example }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
env:
|
||||
IDF_TARGET: ${{ matrix.idf_target }}
|
||||
- name: Test AFL compat build
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
cd $GITHUB_WORKSPACE/esp-protocols/components/mdns/tests/test_afl_fuzz_host/
|
||||
cd components/mdns/tests/test_afl_fuzz_host/
|
||||
make INSTR=off
|
||||
- name: Test no malloc functions
|
||||
shell: bash
|
||||
run: |
|
||||
cd components/mdns
|
||||
for file in $(ls *.c); do
|
||||
cp $file /tmp
|
||||
echo -n "Checking that $file does not call any std allocations directly..."
|
||||
python mem_prefix_script.py $file
|
||||
diff -q $file /tmp/$file || exit 1
|
||||
echo "OK"
|
||||
done
|
||||
|
13
.github/workflows/modem__target-test.yml
vendored
13
.github/workflows/modem__target-test.yml
vendored
@ -42,7 +42,7 @@ jobs:
|
||||
idf.py set-target ${{ matrix.idf_target }}
|
||||
idf.py build
|
||||
$GITHUB_WORKSPACE/ci/clean_build_artifacts.sh ${GITHUB_WORKSPACE}/${TEST_DIR}/build
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: modem_target_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/build
|
||||
@ -75,12 +75,17 @@ jobs:
|
||||
run: |
|
||||
sudo rm -fr $GITHUB_WORKSPACE && mkdir $GITHUB_WORKSPACE
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: modem_target_bin_${{ matrix.idf_target }}_${{ matrix.idf_ver }}_${{ matrix.test.app }}
|
||||
path: ${{ env.TEST_DIR }}/build
|
||||
- name: Run Example Test on target
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
env:
|
||||
PIP_EXTRA_INDEX_URL: "https://dl.espressif.com/pypi/"
|
||||
run: |
|
||||
python -m pip install -r $GITHUB_WORKSPACE/ci/requirements.txt
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install --prefer-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf pytest-custom_exit_code esptool
|
||||
pip install -r $GITHUB_WORKSPACE/ci/requirements.txt
|
||||
cd ${{ env.TEST_DIR }}
|
||||
python -m pytest --log-cli-level DEBUG --target=${{ matrix.idf_target }}
|
||||
|
115
.github/workflows/mosq__build.yml
vendored
115
.github/workflows/mosq__build.yml
vendored
@ -17,7 +17,8 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TEST_DIR: components/mosquitto/examples/broker
|
||||
TEST_DIR: components/mosquitto/examples
|
||||
TARGET_TEST: broker
|
||||
TARGET_TEST_DIR: build_esp32_default
|
||||
steps:
|
||||
- name: Checkout esp-protocols
|
||||
@ -29,14 +30,15 @@ jobs:
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
pip install idf-component-manager idf-build-apps --upgrade
|
||||
python ci/build_apps.py ${TEST_DIR}
|
||||
cd ${TEST_DIR}
|
||||
python ci/build_apps.py -c ${TEST_DIR} -m components/mosquitto/.build-test-rules.yml
|
||||
# upload only the target test artifacts
|
||||
cd ${TEST_DIR}/${TARGET_TEST}
|
||||
${GITHUB_WORKSPACE}/ci/clean_build_artifacts.sh `pwd`/${TARGET_TEST_DIR}
|
||||
zip -qur artifacts.zip ${TARGET_TEST_DIR}
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: mosq_target_esp32_${{ matrix.idf_ver }}
|
||||
path: ${{ env.TEST_DIR }}/artifacts.zip
|
||||
path: ${{ env.TEST_DIR }}/${{ env.TARGET_TEST }}/artifacts.zip
|
||||
if-no-files-found: error
|
||||
|
||||
test_mosq:
|
||||
@ -71,3 +73,108 @@ jobs:
|
||||
mv $dir build
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./results_esp32_${{ matrix.idf_ver }}_${dir#"ci/build_"}.xml --target=esp32
|
||||
done
|
||||
|
||||
check_consistency:
|
||||
if: contains(github.event.pull_request.labels.*.name, 'mosquitto') || github.event_name == 'push'
|
||||
name: Checks that API docs and versions are consistent
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Checks API Docs and versions
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install doxygen
|
||||
pip install esp-doxybook
|
||||
cd components/mosquitto
|
||||
cp api.md api_orig.md
|
||||
./generate_api_docs.sh
|
||||
diff -wB api.md api_orig.md
|
||||
# check version consistency
|
||||
CONFIG_VERSION=$(grep -Po '(?<=#define VERSION ")[^"]*' port/priv_include/config.h)
|
||||
CZ_VERSION=$(grep -Po '(?<=version: )[^"]*' .cz.yaml)
|
||||
COMP_VERSION=$(grep -Po '(?<=version: ")[^"]*' idf_component.yml)
|
||||
if [ "$CONFIG_VERSION" != "v$CZ_VERSION" ] || [ "$CONFIG_VERSION" != "v$COMP_VERSION" ]; then
|
||||
echo "Version mismatch detected:"
|
||||
echo "config.h: $CONFIG_VERSION"
|
||||
echo ".cz.yaml: $CZ_VERSION"
|
||||
echo "idf_component.yml: $COMP_VERSION"
|
||||
exit 1
|
||||
fi
|
||||
echo "Versions are consistent: $CONFIG_VERSION"
|
||||
|
||||
build_idf_tests_with_mosq:
|
||||
if: |
|
||||
github.repository == 'espressif/esp-protocols' &&
|
||||
( contains(github.event.pull_request.labels.*.name, 'mosquitto') || github.event_name == 'push' )
|
||||
name: Build IDF tests
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
idf_target: ["esp32"]
|
||||
test: [ { app: publish, path: "tools/test_apps/protocols/mqtt/publish_connect_test" }]
|
||||
runs-on: ubuntu-20.04
|
||||
container: espressif/idf:${{ matrix.idf_ver }}
|
||||
env:
|
||||
TARGET_TEST_DIR: build_esp32_local_broker
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }} for ${{ matrix.idf_target }}
|
||||
shell: bash
|
||||
run: |
|
||||
. ${IDF_PATH}/export.sh
|
||||
pip install idf-component-manager idf-build-apps --upgrade
|
||||
export MOSQUITTO_PATH=`pwd`/components/mosquitto
|
||||
# to use the actual version of mosquitto
|
||||
sed -i '/espressif\/mosquitto:/a \ \ \ \ override_path: "${MOSQUITTO_PATH}"' ${IDF_PATH}/${{matrix.test.path}}/main/idf_component.yml
|
||||
export PEDANTIC_FLAGS="-DIDF_CI_BUILD -Werror -Werror=deprecated-declarations -Werror=unused-variable -Werror=unused-but-set-variable -Werror=unused-function"
|
||||
export EXTRA_CFLAGS="${PEDANTIC_FLAGS} -Wstrict-prototypes"
|
||||
export EXTRA_CXXFLAGS="${PEDANTIC_FLAGS}"
|
||||
cd ${IDF_PATH}/${{matrix.test.path}}
|
||||
idf-build-apps find --config sdkconfig.ci.local_broker -vv --target ${{ matrix.idf_target }} --build-dir=${TARGET_TEST_DIR}
|
||||
idf-build-apps build --config sdkconfig.ci.local_broker -vv --target ${{ matrix.idf_target }} --build-dir=${TARGET_TEST_DIR}
|
||||
${GITHUB_WORKSPACE}/ci/clean_build_artifacts.sh `pwd`/${TARGET_TEST_DIR}
|
||||
# to replace mqtt test configs with specific mosquitto markers
|
||||
python ${MOSQUITTO_PATH}/test/replace_decorators.py pytest_mqtt_publish_app.py ${TARGET_TEST_DIR}/pytest_mosquitto.py
|
||||
zip -qur ${GITHUB_WORKSPACE}/artifacts.zip ${TARGET_TEST_DIR}
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: mosq_publish_esp32_${{ matrix.idf_ver }}
|
||||
path: artifacts.zip
|
||||
if-no-files-found: error
|
||||
|
||||
test_idf_ci_with_mosq:
|
||||
# Skip running on forks since it won't have access to secrets
|
||||
if: |
|
||||
github.repository == 'espressif/esp-protocols' &&
|
||||
( contains(github.event.pull_request.labels.*.name, 'mosquitto') || github.event_name == 'push' )
|
||||
name: Mosquitto IDF target tests
|
||||
needs: build_idf_tests_with_mosq
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["latest"]
|
||||
runs-on:
|
||||
- self-hosted
|
||||
- ESP32-ETHERNET-KIT
|
||||
env:
|
||||
TEST_DIR: examples
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: mosq_publish_esp32_${{ matrix.idf_ver }}
|
||||
path: ${{ env.TEST_DIR }}/ci/
|
||||
- name: Run Test
|
||||
working-directory: ${{ env.TEST_DIR }}
|
||||
run: |
|
||||
python -m pip install pytest-embedded-serial-esp pytest-embedded-idf pytest-rerunfailures pytest-timeout pytest-ignore-test-results "paho-mqtt<2"
|
||||
unzip ci/artifacts.zip -d ci
|
||||
for dir in `ls -d ci/build_*`; do
|
||||
rm -rf build sdkconfig.defaults
|
||||
mv $dir build
|
||||
mv build/*.py .
|
||||
# Run only "test_mosquitto" marked tests
|
||||
python -m pytest --log-cli-level DEBUG --junit-xml=./results_esp32_${{ matrix.idf_ver }}_${dir#"ci/build_"}.xml --target=esp32 -m test_mosquitto
|
||||
done
|
||||
|
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -1,6 +1,6 @@
|
||||
[submodule "components/asio/asio"]
|
||||
path = components/asio/asio
|
||||
url = https://github.com/espressif/asio
|
||||
url = https://github.com/chriskohlhoff/asio
|
||||
[submodule "components/mosquitto/mosquitto"]
|
||||
path = components/mosquitto/mosquitto
|
||||
url = https://github.com/eclipse/mosquitto
|
||||
|
@ -51,7 +51,7 @@ repos:
|
||||
rev: v1.0.5
|
||||
hooks:
|
||||
- id: astyle_py
|
||||
args: ['--style=otbs', '--attach-namespaces', '--attach-classes', '--indent=spaces=4', '--convert-tabs', '--align-pointer=name', '--align-reference=name', '--keep-one-line-statements', '--pad-header', '--pad-oper', '--exclude-list=ci/ignore_astyle.txt']
|
||||
args: ['--style=otbs', '--attach-namespaces', '--attach-classes', '--indent=spaces=4', '--convert-tabs', '--align-reference=name', '--keep-one-line-statements', '--pad-header', '--pad-oper', '--unpad-paren', '--max-continuation-indent=120', '--exclude-list=ci/ignore_astyle.txt']
|
||||
- repo: https://github.com/commitizen-tools/commitizen
|
||||
rev: v2.42.1
|
||||
hooks:
|
||||
|
@ -0,0 +1 @@
|
||||
components/mosquitto/examples/serverless_mqtt/components/libjuice/port/juice_random.c
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -64,7 +64,7 @@ static struct generic_queue_handle *create_generic_queue(queue_type_t type, uint
|
||||
return h;
|
||||
}
|
||||
|
||||
QueueHandle_t xQueueCreate(uint32_t uxQueueLength, uint32_t uxItemSize )
|
||||
QueueHandle_t xQueueCreate(uint32_t uxQueueLength, uint32_t uxItemSize)
|
||||
{
|
||||
return (QueueHandle_t)create_generic_queue(QUEUE, uxQueueLength, uxItemSize);
|
||||
}
|
||||
@ -75,7 +75,7 @@ uint32_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t
|
||||
return osal_queue_send(h->q, (uint8_t *)pvItemToQueue, h->item_size) ? pdTRUE : pdFAIL;
|
||||
}
|
||||
|
||||
uint32_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait )
|
||||
uint32_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait)
|
||||
{
|
||||
return xQueueSend(xQueue, pvItemToQueue, xTicksToWait);
|
||||
}
|
||||
@ -86,7 +86,7 @@ uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksTo
|
||||
return osal_queue_recv(h->q, (uint8_t *)pvBuffer, h->item_size, xTicksToWait) ? pdTRUE : pdFAIL;
|
||||
}
|
||||
|
||||
BaseType_t xSemaphoreGive( QueueHandle_t xQueue)
|
||||
BaseType_t xSemaphoreGive(QueueHandle_t xQueue)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX) {
|
||||
@ -96,7 +96,7 @@ BaseType_t xSemaphoreGive( QueueHandle_t xQueue)
|
||||
return xQueueSend(xQueue, &s_semaphore_data, portMAX_DELAY);
|
||||
}
|
||||
|
||||
BaseType_t xSemaphoreGiveRecursive( QueueHandle_t xQueue)
|
||||
BaseType_t xSemaphoreGiveRecursive(QueueHandle_t xQueue)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX_REC) {
|
||||
@ -106,7 +106,7 @@ BaseType_t xSemaphoreGiveRecursive( QueueHandle_t xQueue)
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
BaseType_t xSemaphoreTake( QueueHandle_t xQueue, TickType_t pvTask )
|
||||
BaseType_t xSemaphoreTake(QueueHandle_t xQueue, TickType_t pvTask)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX) {
|
||||
@ -116,7 +116,7 @@ BaseType_t xSemaphoreTake( QueueHandle_t xQueue, TickType_t pvTask )
|
||||
return xQueueReceive(xQueue, &s_semaphore_data, portMAX_DELAY);
|
||||
}
|
||||
|
||||
BaseType_t xSemaphoreTakeRecursive( QueueHandle_t xQueue, TickType_t pvTask )
|
||||
BaseType_t xSemaphoreTakeRecursive(QueueHandle_t xQueue, TickType_t pvTask)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->type == MUTEX_REC) {
|
||||
@ -126,7 +126,7 @@ BaseType_t xSemaphoreTakeRecursive( QueueHandle_t xQueue, TickType_t pvTask )
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
void vQueueDelete( QueueHandle_t xQueue )
|
||||
void vQueueDelete(QueueHandle_t xQueue)
|
||||
{
|
||||
struct generic_queue_handle *h = xQueue;
|
||||
if (h->q) {
|
||||
@ -176,14 +176,14 @@ void vTaskSuspend(void *task)
|
||||
vTaskDelete(task);
|
||||
}
|
||||
|
||||
TickType_t xTaskGetTickCount( void )
|
||||
TickType_t xTaskGetTickCount(void)
|
||||
{
|
||||
struct timespec spec;
|
||||
clock_gettime(CLOCK_REALTIME, &spec);
|
||||
return spec.tv_nsec / 1000000 + spec.tv_sec * 1000;
|
||||
}
|
||||
|
||||
void vTaskDelay( const TickType_t xTicksToDelay )
|
||||
void vTaskDelay(const TickType_t xTicksToDelay)
|
||||
{
|
||||
usleep(xTicksToDelay * 1000);
|
||||
}
|
||||
@ -212,13 +212,27 @@ void *pthread_task(void *params)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pvTaskCode,
|
||||
const char *const pcName,
|
||||
const uint32_t usStackDepth,
|
||||
void *const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t *const pvCreatedTask,
|
||||
const BaseType_t xCoreID)
|
||||
TaskHandle_t xTaskCreateStaticPinnedToCore(TaskFunction_t pxTaskCode,
|
||||
const char *const pcName,
|
||||
const uint32_t ulStackDepth,
|
||||
void *const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
StackType_t *const puxStackBuffer,
|
||||
StaticTask_t *const pxTaskBuffer,
|
||||
const BaseType_t xCoreID)
|
||||
{
|
||||
static TaskHandle_t pvCreatedTask;
|
||||
xTaskCreate(pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &pvCreatedTask);
|
||||
return pvCreatedTask;
|
||||
}
|
||||
|
||||
BaseType_t xTaskCreatePinnedToCore(TaskFunction_t pvTaskCode,
|
||||
const char *const pcName,
|
||||
const uint32_t usStackDepth,
|
||||
void *const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t *const pvCreatedTask,
|
||||
const BaseType_t xCoreID)
|
||||
{
|
||||
xTaskCreate(pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pvCreatedTask);
|
||||
return pdTRUE;
|
||||
@ -266,7 +280,7 @@ void xTaskNotifyGive(TaskHandle_t task)
|
||||
}
|
||||
}
|
||||
|
||||
BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time )
|
||||
BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -276,32 +290,32 @@ TaskHandle_t xTaskGetCurrentTaskHandle(void)
|
||||
return (TaskHandle_t)pthread_self();
|
||||
}
|
||||
|
||||
EventGroupHandle_t xEventGroupCreate( void )
|
||||
EventGroupHandle_t xEventGroupCreate(void)
|
||||
{
|
||||
return osal_signal_create();
|
||||
}
|
||||
|
||||
void vEventGroupDelete( EventGroupHandle_t xEventGroup )
|
||||
void vEventGroupDelete(EventGroupHandle_t xEventGroup)
|
||||
{
|
||||
osal_signal_delete(xEventGroup);
|
||||
}
|
||||
|
||||
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
|
||||
EventBits_t xEventGroupClearBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear)
|
||||
{
|
||||
return osal_signal_clear(xEventGroup, uxBitsToClear);
|
||||
}
|
||||
|
||||
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup)
|
||||
EventBits_t xEventGroupGetBits(EventGroupHandle_t xEventGroup)
|
||||
{
|
||||
return osal_signal_get(xEventGroup);
|
||||
}
|
||||
|
||||
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )
|
||||
EventBits_t xEventGroupSetBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet)
|
||||
{
|
||||
return osal_signal_set(xEventGroup, uxBitsToSet);
|
||||
}
|
||||
|
||||
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait )
|
||||
EventBits_t xEventGroupWaitBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait)
|
||||
{
|
||||
return osal_signal_wait(xEventGroup, uxBitsToWaitFor, xWaitForAllBits, xTicksToWait);
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -15,7 +16,10 @@ extern "C" {
|
||||
#define TaskHandle_t TaskHandle_t
|
||||
#define vSemaphoreDelete( xSemaphore ) vQueueDelete( ( QueueHandle_t ) ( xSemaphore ) )
|
||||
|
||||
void vTaskDelay( const TickType_t xTicksToDelay );
|
||||
typedef void *StackType_t;
|
||||
typedef void *StaticTask_t;
|
||||
|
||||
void vTaskDelay(const TickType_t xTicksToDelay);
|
||||
|
||||
void xTaskNotifyGive(TaskHandle_t task);
|
||||
|
||||
@ -23,39 +27,48 @@ void ulTaskNotifyTake(bool stuff, uint32_t timeout);
|
||||
|
||||
TaskHandle_t xTaskGetCurrentTaskHandle(void);
|
||||
|
||||
BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time );
|
||||
BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time);
|
||||
|
||||
BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pvTaskCode,
|
||||
const char *const pcName,
|
||||
const uint32_t usStackDepth,
|
||||
void *const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t *const pvCreatedTask,
|
||||
const BaseType_t xCoreID);
|
||||
TaskHandle_t xTaskCreateStaticPinnedToCore(TaskFunction_t pxTaskCode,
|
||||
const char *const pcName,
|
||||
const uint32_t ulStackDepth,
|
||||
void *const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
StackType_t *const puxStackBuffer,
|
||||
StaticTask_t *const pxTaskBuffer,
|
||||
const BaseType_t xCoreID);
|
||||
|
||||
BaseType_t xTaskCreatePinnedToCore(TaskFunction_t pvTaskCode,
|
||||
const char *const pcName,
|
||||
const uint32_t usStackDepth,
|
||||
void *const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t *const pvCreatedTask,
|
||||
const BaseType_t xCoreID);
|
||||
|
||||
BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, const char *const pcName, const uint32_t usStackDepth, void *const pvParameters, UBaseType_t uxPriority, TaskHandle_t *const pvCreatedTask);
|
||||
|
||||
TickType_t xTaskGetTickCount( void );
|
||||
TickType_t xTaskGetTickCount(void);
|
||||
|
||||
void vQueueDelete( QueueHandle_t xQueue );
|
||||
void vQueueDelete(QueueHandle_t xQueue);
|
||||
|
||||
QueueHandle_t xSemaphoreCreateBinary(void);
|
||||
|
||||
QueueHandle_t xSemaphoreCreateMutex(void);
|
||||
QueueHandle_t xSemaphoreCreateRecursiveMutex(void);
|
||||
|
||||
BaseType_t xSemaphoreGive( QueueHandle_t xQueue);
|
||||
BaseType_t xSemaphoreGive(QueueHandle_t xQueue);
|
||||
|
||||
BaseType_t xSemaphoreTake( QueueHandle_t xQueue, TickType_t pvTask );
|
||||
BaseType_t xSemaphoreTake(QueueHandle_t xQueue, TickType_t pvTask);
|
||||
|
||||
BaseType_t xSemaphoreGiveRecursive( QueueHandle_t xQueue);
|
||||
BaseType_t xSemaphoreGiveRecursive(QueueHandle_t xQueue);
|
||||
|
||||
BaseType_t xSemaphoreTakeRecursive( QueueHandle_t xQueue, TickType_t pvTask );
|
||||
BaseType_t xSemaphoreTakeRecursive(QueueHandle_t xQueue, TickType_t pvTask);
|
||||
|
||||
void vTaskDelete(TaskHandle_t *task);
|
||||
|
||||
QueueHandle_t xQueueCreate( uint32_t uxQueueLength,
|
||||
uint32_t uxItemSize );
|
||||
QueueHandle_t xQueueCreate(uint32_t uxQueueLength,
|
||||
uint32_t uxItemSize);
|
||||
|
||||
uint32_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait);
|
||||
|
||||
@ -63,23 +76,26 @@ uint32_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksTo
|
||||
|
||||
void vTaskSuspend(void *task);
|
||||
|
||||
EventGroupHandle_t xEventGroupCreate( void );
|
||||
void vEventGroupDelete( EventGroupHandle_t xEventGroup );
|
||||
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToClear );
|
||||
EventGroupHandle_t xEventGroupCreate(void);
|
||||
void vEventGroupDelete(EventGroupHandle_t xEventGroup);
|
||||
EventBits_t xEventGroupClearBits(EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToClear);
|
||||
|
||||
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToWaitFor,
|
||||
const BaseType_t xClearOnExit,
|
||||
const BaseType_t xWaitForAllBits,
|
||||
TickType_t xTicksToWait );
|
||||
EventBits_t xEventGroupWaitBits(EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToWaitFor,
|
||||
const BaseType_t xClearOnExit,
|
||||
const BaseType_t xWaitForAllBits,
|
||||
TickType_t xTicksToWait);
|
||||
|
||||
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup);
|
||||
EventBits_t xEventGroupGetBits(EventGroupHandle_t xEventGroup);
|
||||
|
||||
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToSet );
|
||||
EventBits_t xEventGroupSetBits(EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToSet);
|
||||
|
||||
uint32_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait );
|
||||
uint32_t xQueueSendToBack(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait);
|
||||
|
||||
void *heap_caps_malloc(size_t size, uint32_t caps);
|
||||
void heap_caps_free(void *ptr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
---
|
||||
commitizen:
|
||||
bump_message: 'bump(asio): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py asio
|
||||
tag_format: asio-v$version
|
||||
version: 1.28.0~0
|
||||
version: 1.32.0
|
||||
version_files:
|
||||
- idf_component.yml
|
||||
|
@ -1,5 +1,26 @@
|
||||
# Changelog
|
||||
|
||||
## [1.32.0](https://github.com/espressif/esp-protocols/commits/asio-v1.32.0)
|
||||
|
||||
### Features
|
||||
|
||||
- Upgrade asio to 1.32 ([9bdd429c](https://github.com/espressif/esp-protocols/commit/9bdd429c))
|
||||
- Drop esp/asio patches in favor of sock-utils ([27435b7f](https://github.com/espressif/esp-protocols/commit/27435b7f))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix chat example to print only the message body ([76aaea08](https://github.com/espressif/esp-protocols/commit/76aaea08))
|
||||
- Make asio enable if_nametoindex to fix linking ([5db32cce](https://github.com/espressif/esp-protocols/commit/5db32cce))
|
||||
- Re-applie refs to common comps idf_component.yml ([9fe44a45](https://github.com/espressif/esp-protocols/commit/9fe44a45))
|
||||
- Reference common component from IDF ([74fc228c](https://github.com/espressif/esp-protocols/commit/74fc228c))
|
||||
- Revert referencing protocol_examples_common from IDF ([f9e0281a](https://github.com/espressif/esp-protocols/commit/f9e0281a))
|
||||
- reference protocol_examples_common from IDF ([09abb18b](https://github.com/espressif/esp-protocols/commit/09abb18b))
|
||||
- specify override_path in example manifest files ([1d8923cf](https://github.com/espressif/esp-protocols/commit/1d8923cf))
|
||||
|
||||
### Updated
|
||||
|
||||
- docs(asio): Updates asio docs ([ce9337d3](https://github.com/espressif/esp-protocols/commit/ce9337d3))
|
||||
|
||||
## [1.28.2~0](https://github.com/espressif/esp-protocols/commits/asio-1.28.2_0)
|
||||
|
||||
### Bug Fixes
|
||||
|
@ -6,8 +6,8 @@ if(NOT CONFIG_LWIP_IPV6 AND NOT CMAKE_BUILD_EARLY_EXPANSION)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(asio_sources "asio/asio/src/asio.cpp")
|
||||
set(asio_requires lwip)
|
||||
set(asio_sources "asio/asio/src/asio.cpp" "port/src/asio_stub.cpp")
|
||||
set(asio_requires lwip sock_utils)
|
||||
|
||||
if(CONFIG_ASIO_SSL_SUPPORT)
|
||||
list(APPEND asio_sources
|
||||
@ -18,7 +18,7 @@ if(CONFIG_ASIO_SSL_SUPPORT)
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${asio_sources}
|
||||
INCLUDE_DIRS "asio/asio/include" "port/include"
|
||||
INCLUDE_DIRS "port/include" "asio/asio/include"
|
||||
PRIV_INCLUDE_DIRS ${asio_priv_includes}
|
||||
PRIV_REQUIRES ${asio_requires})
|
||||
|
||||
@ -30,6 +30,7 @@ target_compile_definitions(${COMPONENT_LIB} PUBLIC SA_RESTART=0x01
|
||||
ASIO_STANDALONE
|
||||
ASIO_HAS_PTHREADS
|
||||
OPENSSL_NO_ENGINE
|
||||
ASIO_DETAIL_IMPL_POSIX_EVENT_IPP # this replaces asio's posix_event constructor
|
||||
)
|
||||
|
||||
if(NOT CONFIG_COMPILER_CXX_EXCEPTIONS)
|
||||
|
@ -1,6 +1,15 @@
|
||||
menu "ESP-ASIO"
|
||||
visible if LWIP_IPV6
|
||||
|
||||
config ASIO_IS_ENABLED
|
||||
# Invisible option that is enabled if ASIO is added to the IDF components.
|
||||
# This is used to "select" LWIP_NETIF_API option
|
||||
# which enables if_indextoname() and if_nametoindex() functions
|
||||
# (these are optionally used in asio)
|
||||
bool
|
||||
default "y"
|
||||
select LWIP_NETIF_API
|
||||
|
||||
config ASIO_SSL_SUPPORT
|
||||
bool "Enable SSL/TLS support of ASIO"
|
||||
default n
|
||||
|
Submodule components/asio/asio updated: a2e0f70d61...03ae834edb
@ -120,7 +120,7 @@ private:
|
||||
asio::buffer(read_msg_.body(), read_msg_.body_length()),
|
||||
[this, self](std::error_code ec, std::size_t /*length*/) {
|
||||
if (!ec) {
|
||||
ESP_LOGD("asio-chat:", "%s", read_msg_.body());
|
||||
ESP_LOGD("asio-chat", "%.*s", read_msg_.body_length(), read_msg_.body());
|
||||
room_.deliver(read_msg_);
|
||||
do_read_header();
|
||||
} else {
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: "1.28.2~0"
|
||||
version: "1.32.0"
|
||||
description: Cross-platform C++ library for network and I/O programming
|
||||
url: https://github.com/espressif/esp-protocols/tree/master/components/asio
|
||||
issues: https://github.com/espressif/esp-protocols/issues
|
||||
@ -7,3 +7,5 @@ repository: https://github.com/espressif/esp-protocols.git
|
||||
dependencies:
|
||||
idf:
|
||||
version: ">=5.0"
|
||||
espressif/sock_utils:
|
||||
version: "^0.1"
|
||||
|
11
components/asio/port/include/asio/detail/config.hpp
Normal file
11
components/asio/port/include/asio/detail/config.hpp
Normal file
@ -0,0 +1,11 @@
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "sys/socket.h"
|
||||
#include "socketpair.h"
|
||||
|
||||
#include_next "asio/detail/config.hpp"
|
@ -1,12 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2018-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef _ESP_ASIO_CONFIG_H_
|
||||
#define _ESP_ASIO_CONFIG_H_
|
||||
|
||||
#define ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP
|
||||
#include "openssl_stub.hpp"
|
||||
|
||||
#endif // _ESP_ASIO_CONFIG_H_
|
@ -8,7 +8,7 @@
|
||||
//
|
||||
|
||||
#include "asio/detail/config.hpp"
|
||||
#include "openssl_stub.hpp"
|
||||
#include "asio/ssl/detail/openssl_types.hpp"
|
||||
#include <cstring>
|
||||
#include "asio/detail/throw_error.hpp"
|
||||
#include "asio/error.hpp"
|
||||
|
@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
#include "asio/detail/config.hpp"
|
||||
#include "openssl_stub.hpp"
|
||||
#include "asio/ssl/detail/openssl_types.hpp"
|
||||
#include "asio/detail/throw_error.hpp"
|
||||
#include "asio/error.hpp"
|
||||
#include "asio/ssl/detail/engine.hpp"
|
||||
|
36
components/asio/port/src/asio_stub.cpp
Normal file
36
components/asio/port/src/asio_stub.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
// SPDX-FileContributor: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
//
|
||||
#include "asio/detail/posix_event.hpp"
|
||||
#include "asio/detail/throw_error.hpp"
|
||||
#include "asio/error.hpp"
|
||||
#include "asio/detail/push_options.hpp"
|
||||
#include <unistd.h>
|
||||
#include <climits>
|
||||
|
||||
namespace asio::detail {
|
||||
// This replaces asio's posix_event constructor
|
||||
// since the default POSIX version uses pthread_condattr_t operations (init, setclock, destroy),
|
||||
// which are not available on all IDF versions (some are defined in compilers' headers, others in
|
||||
// pthread library, but they typically return `ENOSYS` which causes trouble in the event wrapper)
|
||||
// IMPORTANT: Check implementation of posix_event() when upgrading upstream asio in order not to
|
||||
// miss any initialization step.
|
||||
posix_event::posix_event()
|
||||
: state_(0)
|
||||
{
|
||||
int error = ::pthread_cond_init(&cond_, nullptr);
|
||||
asio::error_code ec(error, asio::error::get_system_category());
|
||||
asio::detail::throw_error(ec, "event");
|
||||
}
|
||||
} // namespace asio::detail
|
||||
|
||||
extern "C" int pause (void)
|
||||
{
|
||||
while (true) {
|
||||
::sleep(UINT_MAX);
|
||||
}
|
||||
}
|
@ -3,6 +3,6 @@ commitizen:
|
||||
bump_message: 'bump(modem): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py esp_modem
|
||||
tag_format: modem-v$version
|
||||
version: 1.2.1
|
||||
version: 1.3.0
|
||||
version_files:
|
||||
- idf_component.yml
|
||||
|
@ -1,5 +1,21 @@
|
||||
# Changelog
|
||||
|
||||
## [1.3.0](https://github.com/espressif/esp-protocols/commits/modem-v1.3.0)
|
||||
|
||||
### Features
|
||||
|
||||
- Add mode detection to the example ([18f196fa](https://github.com/espressif/esp-protocols/commit/18f196fa))
|
||||
- Support for pausing network in C-API ([1db83cd1](https://github.com/espressif/esp-protocols/commit/1db83cd1))
|
||||
- Add support for pausing netif ([247f1681](https://github.com/espressif/esp-protocols/commit/247f1681), [#699](https://github.com/espressif/esp-protocols/issues/699))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Minor cleanup of pppos example ([5e929902](https://github.com/espressif/esp-protocols/commit/5e929902))
|
||||
- Fix PPP mode detection to accept LCP/conf ([c989c6ad](https://github.com/espressif/esp-protocols/commit/c989c6ad))
|
||||
- Refine mode switch data->command ([8b6ea331](https://github.com/espressif/esp-protocols/commit/8b6ea331), [#692](https://github.com/espressif/esp-protocols/issues/692))
|
||||
- Detect serial ports properly ([0cb59ff8](https://github.com/espressif/esp-protocols/commit/0cb59ff8))
|
||||
- Fix CMUX enter to ignore URC before transition ([1284f66d](https://github.com/espressif/esp-protocols/commit/1284f66d), [#669](https://github.com/espressif/esp-protocols/issues/669))
|
||||
|
||||
## [1.2.1](https://github.com/espressif/esp-protocols/commits/modem-v1.2.1)
|
||||
|
||||
### Bug Fixes
|
||||
|
@ -76,4 +76,20 @@ menu "esp-modem"
|
||||
help
|
||||
If enabled, APIs to add URC handler are available
|
||||
|
||||
config ESP_MODEM_PPP_ESCAPE_BEFORE_EXIT
|
||||
bool "Send escape sequence when switching PPP -> CMD"
|
||||
default n
|
||||
help
|
||||
If enabled, the library sends a PPP escape ("+++" command)
|
||||
to switch to command mode. This make switching from PPP to CMD
|
||||
mode more robust for some devices (e.g. Quectel), but might cause
|
||||
trouble for other devices (e.g. SIMCOM).
|
||||
|
||||
config ESP_MODEM_ADD_DEBUG_LOGS
|
||||
bool "Add UART Tx/Rx logs"
|
||||
default n
|
||||
help
|
||||
If enabled, the library dumps all transmitted and received data.
|
||||
This option is only used for debugging.
|
||||
|
||||
endmenu
|
||||
|
@ -385,6 +385,17 @@ extern "C" void app_main(void)
|
||||
return 0;
|
||||
});
|
||||
#endif
|
||||
const ConsoleCommand PauseNetwork("pause_net", "toggle network pause", no_args, [&](ConsoleCommand * c) {
|
||||
static int cnt = 0;
|
||||
if (++cnt % 2) {
|
||||
ESP_LOGI(TAG, "Pausing netif");
|
||||
dce->pause_netif(true);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Unpausing netif");
|
||||
dce->pause_netif(false);
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
const struct SetApn {
|
||||
SetApn(): apn(STR1, nullptr, nullptr, "<apn>", "APN (Access Point Name)") {}
|
||||
|
@ -201,4 +201,23 @@ menu "Example Configuration"
|
||||
help
|
||||
MQTT data message, which we publish and expect to receive.
|
||||
|
||||
config EXAMPLE_PAUSE_NETIF_TO_CHECK_SIGNAL
|
||||
bool "Demonstrate netif pause"
|
||||
default n
|
||||
help
|
||||
Set this to true to demonstrate network pausing.
|
||||
If enabled, the example waits for an MQTT data, then temporarily
|
||||
drops network to check signal quality, resumes networking and
|
||||
publishes another MQTT message.
|
||||
Connection to the MQTT broker should be kept.
|
||||
|
||||
config EXAMPLE_DETECT_MODE_BEFORE_CONNECT
|
||||
bool "Detect mode before connect"
|
||||
default n
|
||||
help
|
||||
Set this to true to demonstrate mode auto-detection.
|
||||
If enabled, the example tries to recognize the actual mode.
|
||||
If mode is detected correctly and it is not a command mode,
|
||||
then the example switches to command mode.
|
||||
|
||||
endmenu
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@ -34,6 +34,7 @@
|
||||
static const char *TAG = "pppos_example";
|
||||
static EventGroupHandle_t event_group = NULL;
|
||||
static const int CONNECT_BIT = BIT0;
|
||||
static const int DISCONNECT_BIT = BIT1;
|
||||
static const int GOT_DATA_BIT = BIT2;
|
||||
static const int USB_DISCONNECTED_BIT = BIT3; // Used only with USB DTE but we define it unconditionally, to avoid too many #ifdefs in the code
|
||||
|
||||
@ -55,6 +56,7 @@ static void usb_terminal_error_handler(esp_modem_terminal_error_t err)
|
||||
}
|
||||
#define CHECK_USB_DISCONNECTION(event_group) \
|
||||
if ((xEventGroupGetBits(event_group) & USB_DISCONNECTED_BIT) == USB_DISCONNECTED_BIT) { \
|
||||
ESP_LOGE(TAG, "USB_DISCONNECTED_BIT destroying modem dce"); \
|
||||
esp_modem_destroy(dce); \
|
||||
continue; \
|
||||
}
|
||||
@ -140,6 +142,7 @@ static void on_ip_event(void *arg, esp_event_base_t event_base,
|
||||
ESP_LOGI(TAG, "GOT ip event!!!");
|
||||
} else if (event_id == IP_EVENT_PPP_LOST_IP) {
|
||||
ESP_LOGI(TAG, "Modem Disconnect from PPP Server");
|
||||
xEventGroupSetBits(event_group, DISCONNECT_BIT);
|
||||
} else if (event_id == IP_EVENT_GOT_IP6) {
|
||||
ESP_LOGI(TAG, "GOT IPv6 event!");
|
||||
|
||||
@ -158,6 +161,7 @@ void app_main(void)
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &on_ppp_changed, NULL));
|
||||
|
||||
/* Configure the PPP netif */
|
||||
esp_err_t err;
|
||||
esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(CONFIG_EXAMPLE_MODEM_PPP_APN);
|
||||
esp_netif_config_t netif_ppp_config = ESP_NETIF_DEFAULT_PPP();
|
||||
esp_netif_t *esp_netif = esp_netif_new(&netif_ppp_config);
|
||||
@ -205,7 +209,7 @@ void app_main(void)
|
||||
#endif
|
||||
assert(dce);
|
||||
if (dte_config.uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) {
|
||||
esp_err_t err = esp_modem_set_flow_control(dce, 2, 2); //2/2 means HW Flow Control.
|
||||
err = esp_modem_set_flow_control(dce, 2, 2); //2/2 means HW Flow Control.
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set the set_flow_control mode");
|
||||
return;
|
||||
@ -246,7 +250,27 @@ void app_main(void)
|
||||
#error Invalid serial connection to modem.
|
||||
#endif
|
||||
|
||||
xEventGroupClearBits(event_group, CONNECT_BIT | GOT_DATA_BIT | USB_DISCONNECTED_BIT);
|
||||
#if CONFIG_EXAMPLE_DETECT_MODE_BEFORE_CONNECT
|
||||
xEventGroupClearBits(event_group, CONNECT_BIT | GOT_DATA_BIT | USB_DISCONNECTED_BIT | DISCONNECT_BIT);
|
||||
|
||||
err = esp_modem_set_mode(dce, ESP_MODEM_MODE_DETECT);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_modem_set_mode(ESP_MODEM_MODE_DETECT) failed with %d", err);
|
||||
return;
|
||||
}
|
||||
esp_modem_dce_mode_t mode = esp_modem_get_mode(dce);
|
||||
ESP_LOGI(TAG, "Mode detection completed: current mode is: %d", mode);
|
||||
if (mode == ESP_MODEM_MODE_DATA) { // set back to command mode
|
||||
err = esp_modem_set_mode(dce, ESP_MODEM_MODE_COMMAND);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_modem_set_mode(ESP_MODEM_MODE_COMMAND) failed with %d", err);
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "Command mode restored");
|
||||
}
|
||||
#endif // CONFIG_EXAMPLE_DETECT_MODE_BEFORE_CONNECT
|
||||
|
||||
xEventGroupClearBits(event_group, CONNECT_BIT | GOT_DATA_BIT | USB_DISCONNECTED_BIT | DISCONNECT_BIT);
|
||||
|
||||
/* Run the modem demo app */
|
||||
#if CONFIG_EXAMPLE_NEED_SIM_PIN == 1
|
||||
@ -262,7 +286,7 @@ void app_main(void)
|
||||
#endif
|
||||
|
||||
int rssi, ber;
|
||||
esp_err_t err = esp_modem_get_signal_quality(dce, &rssi, &ber);
|
||||
err = esp_modem_get_signal_quality(dce, &rssi, &ber);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_modem_get_signal_quality failed with %d %s", err, esp_err_to_name(err));
|
||||
return;
|
||||
@ -301,22 +325,41 @@ void app_main(void)
|
||||
}
|
||||
/* Wait for IP address */
|
||||
ESP_LOGI(TAG, "Waiting for IP address");
|
||||
xEventGroupWaitBits(event_group, CONNECT_BIT | USB_DISCONNECTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
|
||||
xEventGroupWaitBits(event_group, CONNECT_BIT | USB_DISCONNECTED_BIT | DISCONNECT_BIT, pdFALSE, pdFALSE,
|
||||
pdMS_TO_TICKS(60000));
|
||||
CHECK_USB_DISCONNECTION(event_group);
|
||||
if ((xEventGroupGetBits(event_group) & CONNECT_BIT) != CONNECT_BIT) {
|
||||
ESP_LOGW(TAG, "Modem not connected, switching back to the command mode");
|
||||
err = esp_modem_set_mode(dce, ESP_MODEM_MODE_COMMAND);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_modem_set_mode(ESP_MODEM_MODE_COMMAND) failed with %d", err);
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "Command mode restored");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Config MQTT */
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
esp_mqtt_client_config_t mqtt_config = {
|
||||
.broker.address.uri = CONFIG_EXAMPLE_MQTT_BROKER_URI,
|
||||
};
|
||||
#else
|
||||
esp_mqtt_client_config_t mqtt_config = {
|
||||
.uri = CONFIG_EXAMPLE_MQTT_BROKER_URI,
|
||||
};
|
||||
#endif
|
||||
esp_mqtt_client_handle_t mqtt_client = esp_mqtt_client_init(&mqtt_config);
|
||||
esp_mqtt_client_register_event(mqtt_client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
|
||||
esp_mqtt_client_start(mqtt_client);
|
||||
|
||||
#if CONFIG_EXAMPLE_PAUSE_NETIF_TO_CHECK_SIGNAL
|
||||
xEventGroupWaitBits(event_group, GOT_DATA_BIT, pdTRUE, pdFALSE, portMAX_DELAY);
|
||||
esp_modem_pause_net(dce, true);
|
||||
err = esp_modem_get_signal_quality(dce, &rssi, &ber);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_modem_get_signal_quality failed with %d", err);
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "Signal quality: rssi=%d, ber=%d", rssi, ber);
|
||||
esp_modem_pause_net(dce, false);
|
||||
esp_mqtt_client_publish(mqtt_client, CONFIG_EXAMPLE_MQTT_TEST_TOPIC, CONFIG_EXAMPLE_MQTT_TEST_DATA, 0, 0, 0);
|
||||
#endif // CONFIG_EXAMPLE_PAUSE_NETIF_TO_CHECK_SIGNAL
|
||||
|
||||
ESP_LOGI(TAG, "Waiting for MQTT data");
|
||||
xEventGroupWaitBits(event_group, GOT_DATA_BIT | USB_DISCONNECTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
|
||||
CHECK_USB_DISCONNECTION(event_group);
|
||||
|
@ -12,7 +12,7 @@ def test_pppos_connect(dut):
|
||||
4. checks that the client cleanly disconnects
|
||||
"""
|
||||
# Check the sequence of connecting, publishing, disconnecting
|
||||
dut.expect('Modem Connect to PPP Server')
|
||||
dut.expect('Modem Connect to PPP Server', timeout=90)
|
||||
# Check for MQTT connection and the data event
|
||||
dut.expect('MQTT_EVENT_CONNECTED')
|
||||
dut.expect('MQTT_EVENT_DATA')
|
||||
|
@ -11,5 +11,7 @@ CONFIG_EXAMPLE_MODEM_DEVICE_SIM800=y
|
||||
CONFIG_EXAMPLE_MODEM_DEVICE_BG96=n
|
||||
CONFIG_EXAMPLE_MODEM_PPP_APN="lpwa.vodafone.com"
|
||||
CONFIG_EXAMPLE_MQTT_TEST_TOPIC="/ci/esp-modem/pppos-client"
|
||||
CONFIG_EXAMPLE_PAUSE_NETIF_TO_CHECK_SIGNAL=y
|
||||
CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y
|
||||
CONFIG_ESP32_PANIC_PRINT_HALT=y
|
||||
CONFIG_EXAMPLE_DETECT_MODE_BEFORE_CONNECT=y
|
||||
|
@ -16,3 +16,4 @@ CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
|
||||
CONFIG_EXAMPLE_CLOSE_CMUX_AT_END=y
|
||||
CONFIG_EXAMPLE_MQTT_TEST_TOPIC="/ci/esp-modem/pppos-client"
|
||||
CONFIG_BROKER_URI="mqtt://mqtt.eclipseprojects.io"
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: "1.2.1"
|
||||
version: "1.3.0"
|
||||
description: Library for communicating with cellular modems in command and data modes
|
||||
url: https://github.com/espressif/esp-protocols/tree/master/components/esp_modem
|
||||
issues: https://github.com/espressif/esp-protocols/issues
|
||||
|
@ -91,6 +91,11 @@ public:
|
||||
return mode.set(dte.get(), device.get(), netif, m);
|
||||
}
|
||||
|
||||
modem_mode get_mode()
|
||||
{
|
||||
return mode.get();
|
||||
}
|
||||
|
||||
bool recover()
|
||||
{
|
||||
return dte->recover();
|
||||
@ -103,6 +108,29 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Pauses/Unpauses network temporarily
|
||||
* @param do_pause true to pause, false to unpause
|
||||
* @param force true to ignore command failures and continue
|
||||
* @return command_result of the underlying commands
|
||||
*/
|
||||
command_result pause_netif(bool do_pause, bool force = false, int delay = 1000)
|
||||
{
|
||||
command_result result;
|
||||
if (do_pause) {
|
||||
netif.pause();
|
||||
Task::Delay(delay); // Mandatory 1s pause before
|
||||
dte->set_command_callbacks();
|
||||
result = device->set_command_mode();
|
||||
} else {
|
||||
result = device->resume_data_mode();
|
||||
if (result == command_result::OK || force) {
|
||||
netif.resume();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::shared_ptr<DTE> dte;
|
||||
std::shared_ptr<SpecificModule> device;
|
||||
|
@ -77,7 +77,9 @@ public:
|
||||
if (set_command_mode() == command_result::OK) {
|
||||
return true;
|
||||
}
|
||||
Task::Delay(1000); // Mandatory 1s pause after escape
|
||||
// send a newline to delimit the escape from the upcoming sync command
|
||||
uint8_t delim = '\n';
|
||||
dte->write(&delim, 1);
|
||||
if (sync() == command_result::OK) {
|
||||
return true;
|
||||
}
|
||||
|
@ -145,6 +145,12 @@ public:
|
||||
*/
|
||||
bool recover();
|
||||
|
||||
/**
|
||||
* @brief Set internal command callbacks to the underlying terminal.
|
||||
* Here we capture command replies to be processed by supplied command callbacks in struct command_cb.
|
||||
*/
|
||||
void set_command_callbacks();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Allows for locking the DTE
|
||||
@ -204,12 +210,6 @@ private:
|
||||
} inflatable;
|
||||
#endif // CONFIG_ESP_MODEM_USE_INFLATABLE_BUFFER_IF_NEEDED
|
||||
|
||||
/**
|
||||
* @brief Set internal command callbacks to the underlying terminal.
|
||||
* Here we capture command replies to be processed by supplied command callbacks in struct command_cb.
|
||||
*/
|
||||
void set_command_callbacks();
|
||||
|
||||
/**
|
||||
* @brief This abstracts command callback processing and implements its locking, signaling of completion and timeouts.
|
||||
*/
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -54,6 +54,16 @@ public:
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* @brief Pause the network interface
|
||||
*/
|
||||
void pause();
|
||||
|
||||
/**
|
||||
* @brief Resume the network interface
|
||||
*/
|
||||
void resume();
|
||||
|
||||
void receive(uint8_t *data, size_t len);
|
||||
|
||||
private:
|
||||
|
@ -45,6 +45,8 @@ typedef enum esp_modem_dce_mode {
|
||||
ESP_MODEM_MODE_CMUX_MANUAL_SWAP, /**< Swap terminals in CMUX manual mode */
|
||||
ESP_MODEM_MODE_CMUX_MANUAL_DATA, /**< Set DATA mode in CMUX manual mode */
|
||||
ESP_MODEM_MODE_CMUX_MANUAL_COMMAND, /**< Set COMMAND mode in CMUX manual mode */
|
||||
ESP_MODEM_MODE_DETECT, /**< Detect the mode and resume it (if sucessfully detected) */
|
||||
ESP_MODEM_MODE_UNDEF,
|
||||
} esp_modem_dce_mode_t;
|
||||
|
||||
/**
|
||||
@ -160,6 +162,18 @@ esp_err_t esp_modem_set_apn(esp_modem_dce_t *dce, const char *apn);
|
||||
esp_err_t esp_modem_set_urc(esp_modem_dce_t *dce, esp_err_t(*got_line_cb)(uint8_t *data, size_t len));
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief This API provides support for temporarily pausing networking in order
|
||||
* to send/receive AT commands and resume networking afterwards.
|
||||
* @note This function does not switch modes, the modem is still in data mode.
|
||||
*
|
||||
* @param dce Modem DCE handle
|
||||
* @param pause true to pause the network interface, false to resume networking
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_modem_pause_net(esp_modem_dce_t *dce, bool pause);
|
||||
|
||||
esp_modem_dce_mode_t esp_modem_get_mode(esp_modem_dce_t *dce);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
@ -95,12 +95,43 @@ extern "C" esp_err_t esp_modem_sync(esp_modem_dce_t *dce_wrap)
|
||||
return command_response_to_esp_err(dce_wrap->dce->sync());
|
||||
}
|
||||
|
||||
extern "C" esp_modem_dce_mode_t esp_modem_get_mode(esp_modem_dce_t *dce_wrap)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_MODEM_MODE_UNDEF;
|
||||
}
|
||||
auto mode = dce_wrap->dce->get_mode();
|
||||
switch (mode) {
|
||||
default:
|
||||
case modem_mode::UNDEF:
|
||||
return ESP_MODEM_MODE_UNDEF;
|
||||
case modem_mode::COMMAND_MODE:
|
||||
return ESP_MODEM_MODE_COMMAND;
|
||||
case modem_mode::DATA_MODE:
|
||||
return ESP_MODEM_MODE_DATA;
|
||||
case modem_mode::CMUX_MODE:
|
||||
return ESP_MODEM_MODE_CMUX;
|
||||
case modem_mode::CMUX_MANUAL_MODE:
|
||||
return ESP_MODEM_MODE_CMUX_MANUAL;
|
||||
case modem_mode::CMUX_MANUAL_EXIT:
|
||||
return ESP_MODEM_MODE_CMUX_MANUAL_EXIT;
|
||||
case modem_mode::CMUX_MANUAL_DATA:
|
||||
return ESP_MODEM_MODE_CMUX_MANUAL_DATA;
|
||||
case modem_mode::CMUX_MANUAL_COMMAND:
|
||||
return ESP_MODEM_MODE_CMUX_MANUAL_COMMAND;
|
||||
case modem_mode::CMUX_MANUAL_SWAP:
|
||||
return ESP_MODEM_MODE_CMUX_MANUAL_SWAP;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_set_mode(esp_modem_dce_t *dce_wrap, esp_modem_dce_mode_t mode)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
switch (mode) {
|
||||
case ESP_MODEM_MODE_UNDEF:
|
||||
return dce_wrap->dce->set_mode(modem_mode::UNDEF) ? ESP_OK : ESP_FAIL;
|
||||
case ESP_MODEM_MODE_DATA:
|
||||
return dce_wrap->dce->set_mode(modem_mode::DATA_MODE) ? ESP_OK : ESP_FAIL;
|
||||
case ESP_MODEM_MODE_COMMAND:
|
||||
@ -117,6 +148,8 @@ extern "C" esp_err_t esp_modem_set_mode(esp_modem_dce_t *dce_wrap, esp_modem_dce
|
||||
return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_DATA) ? ESP_OK : ESP_FAIL;
|
||||
case ESP_MODEM_MODE_CMUX_MANUAL_COMMAND:
|
||||
return dce_wrap->dce->set_mode(modem_mode::CMUX_MANUAL_COMMAND) ? ESP_OK : ESP_FAIL;
|
||||
case ESP_MODEM_MODE_DETECT:
|
||||
return dce_wrap->dce->set_mode(modem_mode::AUTODETECT) ? ESP_OK : ESP_FAIL;
|
||||
}
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
@ -475,3 +508,19 @@ extern "C" esp_err_t esp_modem_set_urc(esp_modem_dce_t *dce_wrap, esp_err_t(*got
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" esp_err_t esp_modem_pause_net(esp_modem_dce_t *dce_wrap, bool pause)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return command_response_to_esp_err(dce_wrap->dce->pause_netif(pause));
|
||||
}
|
||||
|
||||
extern "C" esp_err_t esp_modem_hang_up(esp_modem_dce_t *dce_wrap)
|
||||
{
|
||||
if (dce_wrap == nullptr || dce_wrap->dce == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return command_response_to_esp_err(dce_wrap->dce->hang_up());
|
||||
}
|
||||
|
@ -123,7 +123,12 @@ bool CMux::data_available(uint8_t *data, size_t len)
|
||||
{
|
||||
if (data && (type & FT_UIH) == FT_UIH && len > 0 && dlci > 0) { // valid payload on a virtual term
|
||||
int virtual_term = dlci - 1;
|
||||
if (virtual_term < MAX_TERMINALS_NUM && read_cb[virtual_term]) {
|
||||
if (virtual_term < MAX_TERMINALS_NUM) {
|
||||
if (read_cb[virtual_term] == nullptr) {
|
||||
// ignore all virtual terminal's data before we completely establish CMUX
|
||||
ESP_LOG_BUFFER_HEXDUMP("CMUX Rx before init", data, len, ESP_LOG_DEBUG);
|
||||
return true;
|
||||
}
|
||||
// Post partial data (or defragment to post on CMUX footer)
|
||||
#ifdef DEFRAGMENT_CMUX_PAYLOAD
|
||||
if (payload_start == nullptr) {
|
||||
@ -142,7 +147,11 @@ bool CMux::data_available(uint8_t *data, size_t len)
|
||||
sabm_ack = dlci;
|
||||
} else if (data == nullptr && dlci > 0) {
|
||||
int virtual_term = dlci - 1;
|
||||
if (virtual_term < MAX_TERMINALS_NUM && read_cb[virtual_term]) {
|
||||
if (virtual_term < MAX_TERMINALS_NUM) {
|
||||
if (read_cb[virtual_term] == nullptr) {
|
||||
// silently ignore this CMUX frame (not finished entering CMUX, yet)
|
||||
return true;
|
||||
}
|
||||
#ifdef DEFRAGMENT_CMUX_PAYLOAD
|
||||
read_cb[virtual_term](payload_start, total_payload_size);
|
||||
#endif
|
||||
|
@ -18,7 +18,6 @@ namespace transitions {
|
||||
|
||||
static bool exit_data(DTE &dte, ModuleIf &device, Netif &netif)
|
||||
{
|
||||
netif.stop();
|
||||
auto signal = std::make_shared<SignalGroup>();
|
||||
std::weak_ptr<SignalGroup> weak_signal = signal;
|
||||
dte.set_read_cb([&netif, weak_signal](uint8_t *data, size_t len) -> bool {
|
||||
@ -32,7 +31,7 @@ static bool exit_data(DTE &dte, ModuleIf &device, Netif &netif)
|
||||
if (memchr(data, '\n', len))
|
||||
{
|
||||
ESP_LOG_BUFFER_HEXDUMP("esp-modem: debug_data (CMD)", data, len, ESP_LOG_DEBUG);
|
||||
const auto pass = std::list<std::string_view>({"NO CARRIER", "DISCONNECTED"});
|
||||
const auto pass = std::list<std::string_view>({"NO CARRIER", "DISCONNECTED", "OK"});
|
||||
std::string_view response((char *) data, len);
|
||||
for (auto &it : pass)
|
||||
if (response.find(it) != std::string::npos) {
|
||||
@ -44,8 +43,14 @@ static bool exit_data(DTE &dte, ModuleIf &device, Netif &netif)
|
||||
}
|
||||
return false;
|
||||
});
|
||||
netif.stop();
|
||||
netif.wait_until_ppp_exits();
|
||||
if (!signal->wait(1, 2000)) {
|
||||
#ifdef ESP_MODEM_PPP_ESCAPE_BEFORE_EXIT
|
||||
std::array<uint8_t, 3> ppp_escape = {'+', '+', '+'};
|
||||
dte.write(ppp_escape.data(), ppp_escape.size());
|
||||
#endif
|
||||
if (!signal->wait(1, 2000)) { // wait for any of the disconnection messages
|
||||
// if no reply -> set device to command mode
|
||||
dte.set_read_cb(nullptr);
|
||||
if (!device.set_mode(modem_mode::COMMAND_MODE)) {
|
||||
return false;
|
||||
@ -323,12 +328,19 @@ modem_mode DCE_Mode::guess_unsafe(DTE *dte, bool with_cmux)
|
||||
if (reply_pos >= sizeof(probe::ppp::lcp_echo_reply_head)) {
|
||||
// check for initial 2 bytes
|
||||
auto *ptr = static_cast<uint8_t *>(memmem(reply, reply_pos, probe::ppp::lcp_echo_reply_head.data(), 2));
|
||||
// and check the other two bytes for protocol ID: LCP
|
||||
// and check the other two bytes for protocol ID:
|
||||
// * either LCP reply
|
||||
if (ptr && ptr[3] == probe::ppp::lcp_echo_reply_head[3] && ptr[4] == probe::ppp::lcp_echo_reply_head[4]) {
|
||||
if (auto signal = weak_signal.lock()) {
|
||||
signal->set(probe::ppp::mode);
|
||||
}
|
||||
}
|
||||
// * or LCP conf request
|
||||
if (ptr && ptr[3] == probe::ppp::lcp_echo_request[3] && ptr[4] == probe::ppp::lcp_echo_request[4]) {
|
||||
if (auto signal = weak_signal.lock()) {
|
||||
signal->set(probe::ppp::mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (reply_pos >= 4 && memmem(reply, reply_pos, probe::cmd::reply, sizeof(probe::cmd::reply))) {
|
||||
if (reply[0] != 0xf9) { // double check that the reply is not wrapped in CMUX headers
|
||||
|
@ -99,6 +99,20 @@ void Netif::stop()
|
||||
signal.clear(PPP_STARTED);
|
||||
}
|
||||
|
||||
void Netif::resume()
|
||||
{
|
||||
ppp_dte->set_read_cb([this](uint8_t *data, size_t len) -> bool {
|
||||
receive(data, len);
|
||||
return true;
|
||||
});
|
||||
signal.set(PPP_STARTED);
|
||||
}
|
||||
|
||||
void Netif::pause()
|
||||
{
|
||||
signal.clear(PPP_STARTED);
|
||||
}
|
||||
|
||||
Netif::~Netif()
|
||||
{
|
||||
if (signal.is_any(PPP_STARTED)) {
|
||||
|
@ -52,7 +52,6 @@ void Netif::start()
|
||||
|
||||
void Netif::stop()
|
||||
{
|
||||
ppp_dte->set_read_cb(nullptr);
|
||||
signal.clear(PPP_STARTED);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -176,13 +176,20 @@ int UartTerminal::read(uint8_t *data, size_t len)
|
||||
uart_get_buffered_data_len(uart.port, &length);
|
||||
length = std::min(len, length);
|
||||
if (length > 0) {
|
||||
return uart_read_bytes(uart.port, data, length, portMAX_DELAY);
|
||||
int read_len = uart_read_bytes(uart.port, data, length, portMAX_DELAY);
|
||||
#if CONFIG_ESP_MODEM_ADD_DEBUG_LOGS
|
||||
ESP_LOG_BUFFER_HEXDUMP("uart-rx", data, read_len, ESP_LOG_DEBUG);
|
||||
#endif
|
||||
return read_len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UartTerminal::write(uint8_t *data, size_t len)
|
||||
{
|
||||
#if CONFIG_ESP_MODEM_ADD_DEBUG_LOGS
|
||||
ESP_LOG_BUFFER_HEXDUMP("uart-tx", data, len, ESP_LOG_DEBUG);
|
||||
#endif
|
||||
return uart_write_bytes_compat(uart.port, data, len);
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,20 @@ from threading import Event, Thread
|
||||
import netifaces
|
||||
|
||||
|
||||
def is_esp32(port):
|
||||
"""
|
||||
Check if the given port is connected to an ESP32 using esptool.
|
||||
"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['esptool.py', '--port', port, 'chip_id'],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True, text=True
|
||||
)
|
||||
return 'ESP32' in result.stdout
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
|
||||
|
||||
def run_server(server_stop, port, server_ip, client_ip, auth, auth_user, auth_password):
|
||||
print('Starting PPP server on port: {}'.format(port))
|
||||
try:
|
||||
@ -66,13 +80,27 @@ def test_examples_protocol_pppos_connect(dut):
|
||||
)
|
||||
raise
|
||||
|
||||
# the PPP test env uses two ttyUSB's: one for ESP32 board, another one for ppp server
|
||||
# use the other port for PPP server than the DUT/ESP
|
||||
port = '/dev/ttyUSB0' if dut.serial.port == '/dev/ttyUSB1' else '/dev/ttyUSB1'
|
||||
# the PPP test env uses three ttyUSB's: two for ESP32 board and another one for the ppp server
|
||||
# we need to detect the server_port (for PPPD)
|
||||
server_port = None
|
||||
for i in ['/dev/ttyUSB0', '/dev/ttyUSB1', '/dev/ttyUSB2']:
|
||||
if i == dut.serial.port:
|
||||
print(f'DUT port: {i}')
|
||||
elif is_esp32(i):
|
||||
print(f'Some other ESP32: {i}')
|
||||
else:
|
||||
print(f'Port for PPPD: {i}')
|
||||
server_port = i
|
||||
if server_port is None:
|
||||
print(
|
||||
'ENV_TEST_FAILURE: Cannot locate PPPD port'
|
||||
)
|
||||
raise
|
||||
|
||||
# Start the PPP server
|
||||
server_stop = Event()
|
||||
t = Thread(target=run_server,
|
||||
args=(server_stop, port, server_ip, client_ip, auth, auth_user, auth_password))
|
||||
args=(server_stop, server_port, server_ip, client_ip, auth, auth_user, auth_password))
|
||||
t.start()
|
||||
try:
|
||||
ppp_server_timeout = time.time() + 30
|
||||
|
@ -3,6 +3,6 @@ commitizen:
|
||||
bump_message: 'bump(websocket): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py esp_websocket_client
|
||||
tag_format: websocket-v$version
|
||||
version: 1.3.0
|
||||
version: 1.4.0
|
||||
version_files:
|
||||
- idf_component.yml
|
||||
|
@ -1,5 +1,23 @@
|
||||
# Changelog
|
||||
|
||||
## [1.4.0](https://github.com/espressif/esp-protocols/commits/websocket-v1.4.0)
|
||||
|
||||
### Features
|
||||
|
||||
- Support DS peripheral for mutual TLS ([55385ec3](https://github.com/espressif/esp-protocols/commit/55385ec3))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- wait for task on destroy ([42674b49](https://github.com/espressif/esp-protocols/commit/42674b49))
|
||||
- Fix pytest to verify client correctly ([9046af8f](https://github.com/espressif/esp-protocols/commit/9046af8f))
|
||||
- propagate error type ([eeeb9006](https://github.com/espressif/esp-protocols/commit/eeeb9006))
|
||||
- fix example buffer leak ([5219c39d](https://github.com/espressif/esp-protocols/commit/5219c39d))
|
||||
|
||||
### Updated
|
||||
|
||||
- chore(websocket): align structure members ([beb6e57e](https://github.com/espressif/esp-protocols/commit/beb6e57e))
|
||||
- chore(websocket): remove unused client variable ([15d3a01e](https://github.com/espressif/esp-protocols/commit/15d3a01e))
|
||||
|
||||
## [1.3.0](https://github.com/espressif/esp-protocols/commits/websocket-v1.3.0)
|
||||
|
||||
### Features
|
||||
|
@ -93,10 +93,13 @@ typedef struct {
|
||||
size_t client_cert_len;
|
||||
const char *client_key;
|
||||
size_t client_key_len;
|
||||
#if CONFIG_ESP_TLS_USE_DS_PERIPHERAL
|
||||
void *client_ds_data;
|
||||
#endif
|
||||
bool use_global_ca_store;
|
||||
bool skip_cert_common_name_check;
|
||||
const char *cert_common_name;
|
||||
esp_err_t (*crt_bundle_attach)(void *conf);
|
||||
esp_err_t (*crt_bundle_attach)(void *conf);
|
||||
esp_transport_handle_t ext_transport;
|
||||
} websocket_config_storage_t;
|
||||
|
||||
@ -122,12 +125,11 @@ struct esp_websocket_client {
|
||||
uint64_t ping_tick_ms;
|
||||
uint64_t pingpong_tick_ms;
|
||||
int wait_timeout_ms;
|
||||
int auto_reconnect;
|
||||
bool run;
|
||||
bool wait_for_pong_resp;
|
||||
bool selected_for_destroying;
|
||||
EventGroupHandle_t status_bits;
|
||||
SemaphoreHandle_t lock;
|
||||
SemaphoreHandle_t lock;
|
||||
size_t errormsg_size;
|
||||
char *errormsg_buffer;
|
||||
char *rx_buffer;
|
||||
@ -186,9 +188,9 @@ static void esp_websocket_free_buf(esp_websocket_client_handle_t client, bool is
|
||||
}
|
||||
|
||||
static esp_err_t esp_websocket_client_dispatch_event(esp_websocket_client_handle_t client,
|
||||
esp_websocket_event_id_t event,
|
||||
const char *data,
|
||||
int data_len)
|
||||
esp_websocket_event_id_t event,
|
||||
const char *data,
|
||||
int data_len)
|
||||
{
|
||||
esp_err_t err;
|
||||
esp_websocket_event_data_t event_data;
|
||||
@ -204,8 +206,8 @@ static esp_err_t esp_websocket_client_dispatch_event(esp_websocket_client_handle
|
||||
|
||||
if (client->error_handle.error_type == WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT) {
|
||||
event_data.error_handle.esp_tls_last_esp_err = esp_tls_get_and_clear_last_error(esp_transport_get_error_handle(client->transport),
|
||||
&client->error_handle.esp_tls_stack_err,
|
||||
&client->error_handle.esp_tls_cert_verify_flags);
|
||||
&client->error_handle.esp_tls_stack_err,
|
||||
&client->error_handle.esp_tls_cert_verify_flags);
|
||||
event_data.error_handle.esp_tls_stack_err = client->error_handle.esp_tls_stack_err;
|
||||
event_data.error_handle.esp_tls_cert_verify_flags = client->error_handle.esp_tls_cert_verify_flags;
|
||||
event_data.error_handle.esp_transport_sock_errno = esp_transport_get_errno(client->transport);
|
||||
@ -235,14 +237,14 @@ static esp_err_t esp_websocket_client_abort_connection(esp_websocket_client_hand
|
||||
} else {
|
||||
client->reconnect_tick_ms = _tick_get_ms();
|
||||
ESP_LOGI(TAG, "Reconnect after %d ms", client->wait_timeout_ms);
|
||||
client->error_handle.error_type = error_type;
|
||||
client->state = WEBSOCKET_STATE_WAIT_TIMEOUT;
|
||||
}
|
||||
client->error_handle.error_type = error_type;
|
||||
esp_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_DISCONNECTED, NULL, 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t esp_websocket_client_error(esp_websocket_client_handle_t client, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
static esp_err_t esp_websocket_client_error(esp_websocket_client_handle_t client, const char *format, ...) __attribute__((format(printf, 2, 3)));
|
||||
static esp_err_t esp_websocket_client_error(esp_websocket_client_handle_t client, const char *format, ...)
|
||||
{
|
||||
va_list myargs;
|
||||
@ -447,6 +449,21 @@ static void destroy_and_free_resources(esp_websocket_client_handle_t client)
|
||||
client = NULL;
|
||||
}
|
||||
|
||||
static esp_err_t stop_wait_task(esp_websocket_client_handle_t client)
|
||||
{
|
||||
/* A running client cannot be stopped from the websocket task/event handler */
|
||||
TaskHandle_t running_task = xTaskGetCurrentTaskHandle();
|
||||
if (running_task == client->task_handle) {
|
||||
ESP_LOGE(TAG, "Client cannot be stopped from websocket task");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
client->run = false;
|
||||
xEventGroupWaitBits(client->status_bits, STOPPED_BIT, false, true, portMAX_DELAY);
|
||||
client->state = WEBSOCKET_STATE_UNKNOW;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t set_websocket_transport_optional_settings(esp_websocket_client_handle_t client, const char *scheme)
|
||||
{
|
||||
esp_transport_handle_t trans = esp_transport_list_get_transport(client->transport_list, scheme);
|
||||
@ -532,6 +549,10 @@ static esp_err_t esp_websocket_client_create_transport(esp_websocket_client_hand
|
||||
} else {
|
||||
esp_transport_ssl_set_client_key_data_der(ssl, client->config->client_key, client->config->client_key_len);
|
||||
}
|
||||
#if CONFIG_ESP_TLS_USE_DS_PERIPHERAL
|
||||
} else if (client->config->client_ds_data) {
|
||||
esp_transport_ssl_set_ds_data(ssl, client->config->client_ds_data);
|
||||
#endif
|
||||
}
|
||||
if (client->config->crt_bundle_attach) {
|
||||
#ifdef CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
|
||||
@ -654,7 +675,7 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
|
||||
client->keep_alive_cfg.keep_alive_enable = true;
|
||||
client->keep_alive_cfg.keep_alive_idle = (config->keep_alive_idle == 0) ? WEBSOCKET_KEEP_ALIVE_IDLE : config->keep_alive_idle;
|
||||
client->keep_alive_cfg.keep_alive_interval = (config->keep_alive_interval == 0) ? WEBSOCKET_KEEP_ALIVE_INTERVAL : config->keep_alive_interval;
|
||||
client->keep_alive_cfg.keep_alive_count = (config->keep_alive_count == 0) ? WEBSOCKET_KEEP_ALIVE_COUNT : config->keep_alive_count;
|
||||
client->keep_alive_cfg.keep_alive_count = (config->keep_alive_count == 0) ? WEBSOCKET_KEEP_ALIVE_COUNT : config->keep_alive_count;
|
||||
}
|
||||
|
||||
if (config->if_name) {
|
||||
@ -697,6 +718,9 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
|
||||
client->config->client_cert_len = config->client_cert_len;
|
||||
client->config->client_key = config->client_key;
|
||||
client->config->client_key_len = config->client_key_len;
|
||||
#if CONFIG_ESP_TLS_USE_DS_PERIPHERAL
|
||||
client->config->client_ds_data = config->client_ds_data;
|
||||
#endif
|
||||
client->config->skip_cert_common_name_check = config->skip_cert_common_name_check;
|
||||
client->config->cert_common_name = config->cert_common_name;
|
||||
client->config->crt_bundle_attach = config->crt_bundle_attach;
|
||||
@ -745,6 +769,7 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
|
||||
ESP_WS_CLIENT_MEM_CHECK(TAG, client->status_bits, {
|
||||
goto _websocket_init_fail;
|
||||
});
|
||||
xEventGroupSetBits(client->status_bits, STOPPED_BIT);
|
||||
|
||||
client->buffer_size = buffer_size;
|
||||
return client;
|
||||
@ -759,9 +784,11 @@ esp_err_t esp_websocket_client_destroy(esp_websocket_client_handle_t client)
|
||||
if (client == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (client->run) {
|
||||
esp_websocket_client_stop(client);
|
||||
|
||||
if (client->status_bits && (STOPPED_BIT & xEventGroupGetBits(client->status_bits)) == 0) {
|
||||
stop_wait_task(client);
|
||||
}
|
||||
|
||||
destroy_and_free_resources(client);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -923,7 +950,7 @@ static esp_err_t esp_websocket_client_recv(esp_websocket_client_handle_t client)
|
||||
client->last_fin = esp_transport_ws_get_fin_flag(client->transport);
|
||||
client->last_opcode = esp_transport_ws_get_read_opcode(client->transport);
|
||||
|
||||
if (rlen == 0 && client->last_opcode == WS_TRANSPORT_OPCODES_NONE ) {
|
||||
if (rlen == 0 && client->last_opcode == WS_TRANSPORT_OPCODES_NONE) {
|
||||
ESP_LOGV(TAG, "esp_transport_read timeouts");
|
||||
esp_websocket_free_buf(client, false);
|
||||
return ESP_OK;
|
||||
@ -1029,7 +1056,7 @@ static void esp_websocket_client_task(void *pv)
|
||||
}
|
||||
}
|
||||
|
||||
if ( _tick_get_ms() - client->pingpong_tick_ms > client->config->pingpong_timeout_sec * 1000 ) {
|
||||
if (_tick_get_ms() - client->pingpong_tick_ms > client->config->pingpong_timeout_sec * 1000) {
|
||||
if (client->wait_for_pong_resp) {
|
||||
esp_websocket_client_error(client, "Error, no PONG received for more than %d seconds after PING", client->config->pingpong_timeout_sec);
|
||||
esp_websocket_client_abort_connection(client, WEBSOCKET_ERROR_TYPE_PONG_TIMEOUT);
|
||||
@ -1150,23 +1177,13 @@ esp_err_t esp_websocket_client_stop(esp_websocket_client_handle_t client)
|
||||
if (client == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (!client->run) {
|
||||
|
||||
if (xEventGroupGetBits(client->status_bits) & STOPPED_BIT) {
|
||||
ESP_LOGW(TAG, "Client was not started");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* A running client cannot be stopped from the websocket task/event handler */
|
||||
TaskHandle_t running_task = xTaskGetCurrentTaskHandle();
|
||||
if (running_task == client->task_handle) {
|
||||
ESP_LOGE(TAG, "Client cannot be stopped from websocket task");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
|
||||
client->run = false;
|
||||
xEventGroupWaitBits(client->status_bits, STOPPED_BIT, false, true, portMAX_DELAY);
|
||||
client->state = WEBSOCKET_STATE_UNKNOW;
|
||||
return ESP_OK;
|
||||
return stop_wait_task(client);
|
||||
}
|
||||
|
||||
static int esp_websocket_client_send_close(esp_websocket_client_handle_t client, int code, const char *additional_data, int total_len, TickType_t timeout)
|
||||
@ -1356,3 +1373,13 @@ esp_err_t esp_websocket_register_events(esp_websocket_client_handle_t client,
|
||||
}
|
||||
return esp_event_handler_register_with(client->event_handle, WEBSOCKET_EVENTS, event, event_handler, event_handler_arg);
|
||||
}
|
||||
|
||||
esp_err_t esp_websocket_unregister_events(esp_websocket_client_handle_t client,
|
||||
esp_websocket_event_id_t event,
|
||||
esp_event_handler_t event_handler)
|
||||
{
|
||||
if (client == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return esp_event_handler_unregister_with(client->event_handle, WEBSOCKET_EVENTS, event, event_handler);
|
||||
}
|
||||
|
@ -227,6 +227,7 @@ static void websocket_app_start(void)
|
||||
xSemaphoreTake(shutdown_sema, portMAX_DELAY);
|
||||
esp_websocket_client_close(client, portMAX_DELAY);
|
||||
ESP_LOGI(TAG, "Websocket Stopped");
|
||||
esp_websocket_unregister_events(client, WEBSOCKET_EVENT_ANY, websocket_event_handler);
|
||||
esp_websocket_client_destroy(client);
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ class Websocket(object):
|
||||
ssl_context.load_cert_chain(certfile='main/certs/server/server_cert.pem', keyfile='main/certs/server/server_key.pem')
|
||||
if self.client_verify is True:
|
||||
ssl_context.load_verify_locations(cafile='main/certs/ca_cert.pem')
|
||||
ssl_context.verify = ssl.CERT_REQUIRED
|
||||
ssl_context.verify_mode = ssl.CERT_REQUIRED
|
||||
ssl_context.check_hostname = False
|
||||
self.server = SimpleSSLWebSocketServer('', self.port, WebsocketTestEcho, ssl_context=ssl_context)
|
||||
else:
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: "1.3.0"
|
||||
version: "1.4.0"
|
||||
description: WebSocket protocol client for ESP-IDF
|
||||
url: https://github.com/espressif/esp-protocols/tree/master/components/esp_websocket_client
|
||||
dependencies:
|
||||
|
@ -108,10 +108,13 @@ typedef struct {
|
||||
int buffer_size; /*!< Websocket buffer size */
|
||||
const char *cert_pem; /*!< Pointer to certificate data in PEM or DER format for server verify (with SSL), default is NULL, not required to verify the server. PEM-format must have a terminating NULL-character. DER-format requires the length to be passed in cert_len. */
|
||||
size_t cert_len; /*!< Length of the buffer pointed to by cert_pem. May be 0 for null-terminated pem */
|
||||
const char *client_cert; /*!< Pointer to certificate data in PEM or DER format for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_key` has to be provided. PEM-format must have a terminating NULL-character. DER-format requires the length to be passed in client_cert_len. */
|
||||
const char *client_cert; /*!< Pointer to certificate data in PEM or DER format for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_key` or `client_ds_data` (if supported) has to be provided. PEM-format must have a terminating NULL-character. DER-format requires the length to be passed in client_cert_len. */
|
||||
size_t client_cert_len; /*!< Length of the buffer pointed to by client_cert. May be 0 for null-terminated pem */
|
||||
const char *client_key; /*!< Pointer to private key data in PEM or DER format for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_cert` has to be provided. PEM-format must have a terminating NULL-character. DER-format requires the length to be passed in client_key_len */
|
||||
const char *client_key; /*!< Pointer to private key data in PEM or DER format for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_cert` has to be provided and `client_ds_data` (if supported) gets ignored. PEM-format must have a terminating NULL-character. DER-format requires the length to be passed in client_key_len */
|
||||
size_t client_key_len; /*!< Length of the buffer pointed to by client_key_pem. May be 0 for null-terminated pem */
|
||||
#if CONFIG_ESP_TLS_USE_DS_PERIPHERAL
|
||||
void *client_ds_data; /*!< Pointer to the encrypted private key data for SSL mutual authentication using the DS peripheral, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_cert` has to be provided. It is ignored if `client_key` is provided */
|
||||
#endif
|
||||
esp_websocket_transport_t transport; /*!< Websocket transport type, see `esp_websocket_transport_t */
|
||||
const char *subprotocol; /*!< Websocket subprotocol */
|
||||
const char *user_agent; /*!< Websocket user-agent */
|
||||
@ -457,6 +460,18 @@ esp_err_t esp_websocket_register_events(esp_websocket_client_handle_t client,
|
||||
esp_event_handler_t event_handler,
|
||||
void *event_handler_arg);
|
||||
|
||||
/**
|
||||
* @brief Unegister the Websocket Events
|
||||
*
|
||||
* @param client The client handle
|
||||
* @param event The event id
|
||||
* @param event_handler The callback function
|
||||
* @return esp_err_t
|
||||
*/
|
||||
esp_err_t esp_websocket_unregister_events(esp_websocket_client_handle_t client,
|
||||
esp_websocket_event_id_t event,
|
||||
esp_event_handler_t event_handler);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -3,6 +3,6 @@ commitizen:
|
||||
bump_message: 'bump(mdns): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py mdns
|
||||
tag_format: mdns-v$version
|
||||
version: 1.4.2
|
||||
version: 1.7.0
|
||||
version_files:
|
||||
- idf_component.yml
|
||||
|
@ -1,5 +1,76 @@
|
||||
# Changelog
|
||||
|
||||
## [1.7.0](https://github.com/espressif/esp-protocols/commits/mdns-v1.7.0)
|
||||
|
||||
### Features
|
||||
|
||||
- Support user defined allocators ([88162d1f](https://github.com/espressif/esp-protocols/commit/88162d1f))
|
||||
- Allow allocate memory with configured caps ([7d29b476](https://github.com/espressif/esp-protocols/commit/7d29b476))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Adjust some formatting per indent-cont=120 ([5b2077e3](https://github.com/espressif/esp-protocols/commit/5b2077e3))
|
||||
|
||||
## [1.6.0](https://github.com/espressif/esp-protocols/commits/mdns-v1.6.0)
|
||||
|
||||
### Features
|
||||
|
||||
- support allocating mDNS task from SPIRAM ([8fcad10c](https://github.com/espressif/esp-protocols/commit/8fcad10c))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Use correct task delete function ([eb4ab524](https://github.com/espressif/esp-protocols/commit/eb4ab524))
|
||||
|
||||
### Updated
|
||||
|
||||
- ci(mdns): Fix mdns host test layers with static task creation ([0690eba3](https://github.com/espressif/esp-protocols/commit/0690eba3))
|
||||
|
||||
## [1.5.3](https://github.com/espressif/esp-protocols/commits/mdns-v1.5.3)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix responder to ignore only invalid queries ([cd07228f](https://github.com/espressif/esp-protocols/commit/cd07228f), [#754](https://github.com/espressif/esp-protocols/issues/754))
|
||||
|
||||
## [1.5.2](https://github.com/espressif/esp-protocols/commits/mdns-v1.5.2)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix potential NULL deref when sending sub-buy ([e7273c46](https://github.com/espressif/esp-protocols/commit/e7273c46))
|
||||
- Fix _mdns_append_fqdn excessive stack usage ([bd23c233](https://github.com/espressif/esp-protocols/commit/bd23c233))
|
||||
|
||||
## [1.5.1](https://github.com/espressif/esp-protocols/commits/mdns-v1.5.1)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix incorrect memory free for mdns browse ([4451a8c5](https://github.com/espressif/esp-protocols/commit/4451a8c5))
|
||||
|
||||
## [1.5.0](https://github.com/espressif/esp-protocols/commits/mdns-v1.5.0)
|
||||
|
||||
### Features
|
||||
|
||||
- supported removal of subtype when updating service ([4ad88e29](https://github.com/espressif/esp-protocols/commit/4ad88e29))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix zero-sized VLA clang-tidy warnings ([196198ec](https://github.com/espressif/esp-protocols/commit/196198ec))
|
||||
- Remove dead store to arg variable shared ([e838bf03](https://github.com/espressif/esp-protocols/commit/e838bf03))
|
||||
- Fix name mangling not to use strcpy() ([99b54ac3](https://github.com/espressif/esp-protocols/commit/99b54ac3))
|
||||
- Fix potential null derefernce in _mdns_execute_action() ([f5be2f41](https://github.com/espressif/esp-protocols/commit/f5be2f41))
|
||||
- Fix AFL test mock per espressif/esp-idf@a5bc08fb55c ([3d8835cf](https://github.com/espressif/esp-protocols/commit/3d8835cf))
|
||||
- Fixed potential out-of-bound interface error ([24f55ce9](https://github.com/espressif/esp-protocols/commit/24f55ce9))
|
||||
- Fixed incorrect error conversion ([8f8516cc](https://github.com/espressif/esp-protocols/commit/8f8516cc))
|
||||
- Fixed potential overflow when allocating txt data ([75a8e864](https://github.com/espressif/esp-protocols/commit/75a8e864))
|
||||
- Move MDNS_NAME_BUF_LEN to public headers ([907087c0](https://github.com/espressif/esp-protocols/commit/907087c0), [#724](https://github.com/espressif/esp-protocols/issues/724))
|
||||
- Cleanup includes in mdns.c ([68a9e148](https://github.com/espressif/esp-protocols/commit/68a9e148), [#725](https://github.com/espressif/esp-protocols/issues/725))
|
||||
- Allow advertizing service with port==0 ([827ea65f](https://github.com/espressif/esp-protocols/commit/827ea65f))
|
||||
- Fixed complier warning if MDNS_MAX_SERVICES==0 ([95377216](https://github.com/espressif/esp-protocols/commit/95377216), [#611](https://github.com/espressif/esp-protocols/issues/611))
|
||||
|
||||
## [1.4.3](https://github.com/espressif/esp-protocols/commits/mdns-v1.4.3)
|
||||
|
||||
### Features
|
||||
|
||||
- support zero item when update subtype ([5bd82c01](https://github.com/espressif/esp-protocols/commit/5bd82c01))
|
||||
|
||||
## [1.4.2](https://github.com/espressif/esp-protocols/commits/mdns-v1.4.2)
|
||||
|
||||
### Features
|
||||
|
@ -10,15 +10,17 @@ else()
|
||||
set(MDNS_CONSOLE "")
|
||||
endif()
|
||||
|
||||
set(MDNS_MEMORY "mdns_mem_caps.c")
|
||||
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
if(${target} STREQUAL "linux")
|
||||
set(dependencies esp_netif_linux esp_event)
|
||||
set(private_dependencies esp_timer console esp_system)
|
||||
set(srcs "mdns.c" ${MDNS_NETWORKING} ${MDNS_CONSOLE})
|
||||
set(srcs "mdns.c" ${MDNS_MEMORY} ${MDNS_NETWORKING} ${MDNS_CONSOLE})
|
||||
else()
|
||||
set(dependencies lwip console esp_netif)
|
||||
set(private_dependencies esp_timer esp_wifi)
|
||||
set(srcs "mdns.c" ${MDNS_NETWORKING} ${MDNS_CONSOLE})
|
||||
set(srcs "mdns.c" ${MDNS_MEMORY} ${MDNS_NETWORKING} ${MDNS_CONSOLE})
|
||||
endif()
|
||||
|
||||
idf_component_register(
|
||||
|
@ -61,6 +61,48 @@ menu "mDNS"
|
||||
default 0x0 if MDNS_TASK_AFFINITY_CPU0
|
||||
default 0x1 if MDNS_TASK_AFFINITY_CPU1
|
||||
|
||||
menu "MDNS Memory Configuration"
|
||||
|
||||
choice MDNS_TASK_MEMORY_ALLOC_FROM
|
||||
prompt "Select mDNS task create on which type of memory"
|
||||
default MDNS_TASK_CREATE_FROM_INTERNAL
|
||||
config MDNS_TASK_CREATE_FROM_SPIRAM
|
||||
bool "mDNS task creates on the SPIRAM (READ HELP)"
|
||||
depends on (SPIRAM_USE_CAPS_ALLOC || SPIRAM_USE_MALLOC)
|
||||
help
|
||||
mDNS task creates on the SPIRAM.
|
||||
This option requires FreeRTOS component to allow creating
|
||||
tasks on the external memory.
|
||||
Please read the documentation about FREERTOS_TASK_CREATE_ALLOW_EXT_MEM
|
||||
|
||||
config MDNS_TASK_CREATE_FROM_INTERNAL
|
||||
bool "mDNS task creates on the internal RAM"
|
||||
|
||||
endchoice
|
||||
|
||||
choice MDNS_MEMORY_ALLOC_FROM
|
||||
prompt "Select mDNS memory allocation type"
|
||||
default MDNS_MEMORY_ALLOC_INTERNAL
|
||||
|
||||
config MDNS_MEMORY_ALLOC_SPIRAM
|
||||
bool "Allocate mDNS memory from SPIRAM"
|
||||
depends on (SPIRAM_USE_CAPS_ALLOC || SPIRAM_USE_MALLOC)
|
||||
|
||||
config MDNS_MEMORY_ALLOC_INTERNAL
|
||||
bool "Allocate mDNS memory from internal RAM"
|
||||
|
||||
endchoice
|
||||
|
||||
config MDNS_MEMORY_CUSTOM_IMPL
|
||||
bool "Implement custom memory functions"
|
||||
default n
|
||||
help
|
||||
Enable to implement custom memory functions for mDNS library.
|
||||
This option is useful when the application wants to use custom
|
||||
memory allocation functions for mDNS library.
|
||||
|
||||
endmenu # MDNS Memory Configuration
|
||||
|
||||
config MDNS_SERVICE_ADD_TIMEOUT_MS
|
||||
int "mDNS adding service timeout (ms)"
|
||||
range 10 30000
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: "1.4.2"
|
||||
version: "1.7.0"
|
||||
description: "Multicast UDP service used to provide local network service and host discovery."
|
||||
url: "https://github.com/espressif/esp-protocols/tree/master/components/mdns"
|
||||
issues: "https://github.com/espressif/esp-protocols/issues"
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -10,6 +10,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include <esp_netif.h>
|
||||
|
||||
#define MDNS_TYPE_A 0x0001
|
||||
@ -21,6 +22,13 @@ extern "C" {
|
||||
#define MDNS_TYPE_NSEC 0x002F
|
||||
#define MDNS_TYPE_ANY 0x00FF
|
||||
|
||||
#if defined(CONFIG_LWIP_IPV6) && defined(CONFIG_MDNS_RESPOND_REVERSE_QUERIES)
|
||||
#define MDNS_NAME_MAX_LEN (64+4) // Need to account for IPv6 reverse queries (64 char address + ".ip6" )
|
||||
#else
|
||||
#define MDNS_NAME_MAX_LEN 64 // Maximum string length of hostname, instance, service and proto
|
||||
#endif
|
||||
#define MDNS_NAME_BUF_LEN (MDNS_NAME_MAX_LEN+1) // Maximum char buffer size to hold hostname, instance, service or proto
|
||||
|
||||
/**
|
||||
* @brief Asynchronous query handle
|
||||
*/
|
||||
@ -615,6 +623,8 @@ esp_err_t mdns_service_subtype_add_multiple_items_for_host(const char *instance_
|
||||
* @param subtype the pointer of subtype array to add.
|
||||
* @param num_items number of items in subtype array
|
||||
*
|
||||
* @note If `num_items` is 0, then remove all subtypes.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -10,6 +10,7 @@
|
||||
#include "mdns.h"
|
||||
#include "mdns_private.h"
|
||||
#include "inttypes.h"
|
||||
#include "mdns_mem_caps.h"
|
||||
|
||||
static const char *ip_protocol_str[] = {"V4", "V6", "MAX"};
|
||||
|
||||
@ -110,7 +111,7 @@ static void register_mdns_query_a(void)
|
||||
.argtable = &mdns_query_a_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_init));
|
||||
}
|
||||
#endif /* CONFIG_LWIP_IPV4 */
|
||||
|
||||
@ -169,7 +170,7 @@ static void register_mdns_query_aaaa(void)
|
||||
.argtable = &mdns_query_a_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_init));
|
||||
}
|
||||
#endif /* CONFIG_LWIP_IPV6 */
|
||||
|
||||
@ -231,7 +232,7 @@ static void register_mdns_query_srv(void)
|
||||
.argtable = &mdns_query_srv_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_init));
|
||||
}
|
||||
|
||||
static struct {
|
||||
@ -293,7 +294,7 @@ static void register_mdns_query_txt(void)
|
||||
.argtable = &mdns_query_txt_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_init));
|
||||
}
|
||||
|
||||
static struct {
|
||||
@ -359,7 +360,7 @@ static void register_mdns_query_ptr(void)
|
||||
.argtable = &mdns_query_ptr_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_init));
|
||||
}
|
||||
|
||||
static struct {
|
||||
@ -427,7 +428,7 @@ static void register_mdns_query_ip(void)
|
||||
.argtable = &mdns_query_ip_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_init));
|
||||
}
|
||||
|
||||
static struct {
|
||||
@ -496,7 +497,7 @@ static void register_mdns_query_svc(void)
|
||||
.argtable = &mdns_query_svc_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_init));
|
||||
}
|
||||
|
||||
static struct {
|
||||
@ -513,15 +514,15 @@ static int cmd_mdns_init(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK( mdns_init() );
|
||||
ESP_ERROR_CHECK(mdns_init());
|
||||
|
||||
if (mdns_init_args.hostname->sval[0]) {
|
||||
ESP_ERROR_CHECK( mdns_hostname_set(mdns_init_args.hostname->sval[0]) );
|
||||
ESP_ERROR_CHECK(mdns_hostname_set(mdns_init_args.hostname->sval[0]));
|
||||
printf("MDNS: Hostname: %s\n", mdns_init_args.hostname->sval[0]);
|
||||
}
|
||||
|
||||
if (mdns_init_args.instance->count) {
|
||||
ESP_ERROR_CHECK( mdns_instance_name_set(mdns_init_args.instance->sval[0]) );
|
||||
ESP_ERROR_CHECK(mdns_instance_name_set(mdns_init_args.instance->sval[0]));
|
||||
printf("MDNS: Instance: %s\n", mdns_init_args.instance->sval[0]);
|
||||
}
|
||||
|
||||
@ -542,7 +543,7 @@ static void register_mdns_init(void)
|
||||
.argtable = &mdns_init_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_init) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_init));
|
||||
}
|
||||
|
||||
static int cmd_mdns_free(int argc, char **argv)
|
||||
@ -561,7 +562,7 @@ static void register_mdns_free(void)
|
||||
.argtable = NULL
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_free) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_free));
|
||||
}
|
||||
|
||||
static struct {
|
||||
@ -582,7 +583,7 @@ static int cmd_mdns_set_hostname(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK( mdns_hostname_set(mdns_set_hostname_args.hostname->sval[0]) );
|
||||
ESP_ERROR_CHECK(mdns_hostname_set(mdns_set_hostname_args.hostname->sval[0]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -599,7 +600,7 @@ static void register_mdns_set_hostname(void)
|
||||
.argtable = &mdns_set_hostname_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_set_hostname) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_set_hostname));
|
||||
}
|
||||
|
||||
static struct {
|
||||
@ -620,7 +621,7 @@ static int cmd_mdns_set_instance(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK( mdns_instance_name_set(mdns_set_instance_args.instance->sval[0]) );
|
||||
ESP_ERROR_CHECK(mdns_instance_name_set(mdns_set_instance_args.instance->sval[0]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -637,14 +638,14 @@ static void register_mdns_set_instance(void)
|
||||
.argtable = &mdns_set_instance_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_set_instance) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_set_instance));
|
||||
}
|
||||
|
||||
static mdns_txt_item_t *_convert_items(const char **values, int count)
|
||||
{
|
||||
int i = 0, e;
|
||||
const char *value = NULL;
|
||||
mdns_txt_item_t *items = (mdns_txt_item_t *) malloc(sizeof(mdns_txt_item_t) * count);
|
||||
mdns_txt_item_t *items = (mdns_txt_item_t *) mdns_mem_malloc(sizeof(mdns_txt_item_t) * count);
|
||||
if (!items) {
|
||||
printf("ERROR: No Memory!\n");
|
||||
goto fail;
|
||||
@ -661,15 +662,15 @@ static mdns_txt_item_t *_convert_items(const char **values, int count)
|
||||
}
|
||||
int var_len = esign - value;
|
||||
int val_len = strlen(value) - var_len - 1;
|
||||
char *var = (char *)malloc(var_len + 1);
|
||||
char *var = (char *)mdns_mem_malloc(var_len + 1);
|
||||
if (var == NULL) {
|
||||
printf("ERROR: No Memory!\n");
|
||||
goto fail;
|
||||
}
|
||||
char *val = (char *)malloc(val_len + 1);
|
||||
char *val = (char *)mdns_mem_malloc(val_len + 1);
|
||||
if (val == NULL) {
|
||||
printf("ERROR: No Memory!\n");
|
||||
free(var);
|
||||
mdns_mem_free(var);
|
||||
goto fail;
|
||||
}
|
||||
memcpy(var, value, var_len);
|
||||
@ -685,10 +686,10 @@ static mdns_txt_item_t *_convert_items(const char **values, int count)
|
||||
|
||||
fail:
|
||||
for (e = 0; e < i; e++) {
|
||||
free((char *)items[e].key);
|
||||
free((char *)items[e].value);
|
||||
mdns_mem_free((char *)items[e].key);
|
||||
mdns_mem_free((char *)items[e].value);
|
||||
}
|
||||
free(items);
|
||||
mdns_mem_free(items);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -734,9 +735,9 @@ static int cmd_mdns_service_add(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK( mdns_service_add_for_host(instance, mdns_add_args.service->sval[0], mdns_add_args.proto->sval[0],
|
||||
host, mdns_add_args.port->ival[0], items, mdns_add_args.txt->count) );
|
||||
free(items);
|
||||
ESP_ERROR_CHECK(mdns_service_add_for_host(instance, mdns_add_args.service->sval[0], mdns_add_args.proto->sval[0],
|
||||
host, mdns_add_args.port->ival[0], items, mdns_add_args.txt->count));
|
||||
mdns_mem_free(items);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -758,7 +759,7 @@ static void register_mdns_service_add(void)
|
||||
.argtable = &mdns_add_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_add) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_add));
|
||||
}
|
||||
|
||||
static struct {
|
||||
@ -791,7 +792,7 @@ static int cmd_mdns_service_remove(int argc, char **argv)
|
||||
host = mdns_remove_args.host->sval[0];
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK( mdns_service_remove_for_host(instance, mdns_remove_args.service->sval[0], mdns_remove_args.proto->sval[0], host) );
|
||||
ESP_ERROR_CHECK(mdns_service_remove_for_host(instance, mdns_remove_args.service->sval[0], mdns_remove_args.proto->sval[0], host));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -811,7 +812,7 @@ static void register_mdns_service_remove(void)
|
||||
.argtable = &mdns_remove_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_remove) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_remove));
|
||||
}
|
||||
|
||||
static struct {
|
||||
@ -869,7 +870,7 @@ static void register_mdns_service_instance_set(void)
|
||||
.argtable = &mdns_service_instance_set_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_add) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_add));
|
||||
}
|
||||
|
||||
static struct {
|
||||
@ -927,7 +928,7 @@ static void register_mdns_service_port_set(void)
|
||||
.argtable = &mdns_service_port_set_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_add) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_add));
|
||||
}
|
||||
|
||||
static struct {
|
||||
@ -970,8 +971,8 @@ static int cmd_mdns_service_txt_replace(int argc, char **argv)
|
||||
|
||||
}
|
||||
}
|
||||
ESP_ERROR_CHECK( mdns_service_txt_set_for_host(instance, mdns_txt_replace_args.service->sval[0], mdns_txt_replace_args.proto->sval[0], host, items, mdns_txt_replace_args.txt->count) );
|
||||
free(items);
|
||||
ESP_ERROR_CHECK(mdns_service_txt_set_for_host(instance, mdns_txt_replace_args.service->sval[0], mdns_txt_replace_args.proto->sval[0], host, items, mdns_txt_replace_args.txt->count));
|
||||
mdns_mem_free(items);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -992,7 +993,7 @@ static void register_mdns_service_txt_replace(void)
|
||||
.argtable = &mdns_txt_replace_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_txt_set) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_txt_set));
|
||||
}
|
||||
|
||||
static struct {
|
||||
@ -1028,7 +1029,7 @@ static int cmd_mdns_service_txt_set(int argc, char **argv)
|
||||
printf("MDNS: Service for delegated host: %s\n", host);
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK( mdns_service_txt_item_set_for_host(instance, mdns_txt_set_args.service->sval[0], mdns_txt_set_args.proto->sval[0], host, mdns_txt_set_args.var->sval[0], mdns_txt_set_args.value->sval[0]) );
|
||||
ESP_ERROR_CHECK(mdns_service_txt_item_set_for_host(instance, mdns_txt_set_args.service->sval[0], mdns_txt_set_args.proto->sval[0], host, mdns_txt_set_args.var->sval[0], mdns_txt_set_args.value->sval[0]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1050,7 +1051,7 @@ static void register_mdns_service_txt_set(void)
|
||||
.argtable = &mdns_txt_set_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_txt_set) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_txt_set));
|
||||
}
|
||||
|
||||
static struct {
|
||||
@ -1082,7 +1083,7 @@ static int cmd_mdns_service_txt_remove(int argc, char **argv)
|
||||
if (mdns_txt_remove_args.host->count && mdns_txt_remove_args.host->sval[0]) {
|
||||
host = mdns_txt_remove_args.host->sval[0];
|
||||
}
|
||||
ESP_ERROR_CHECK( mdns_service_txt_item_remove_for_host(instance, mdns_txt_remove_args.service->sval[0], mdns_txt_remove_args.proto->sval[0], host, mdns_txt_remove_args.var->sval[0]) );
|
||||
ESP_ERROR_CHECK(mdns_service_txt_item_remove_for_host(instance, mdns_txt_remove_args.service->sval[0], mdns_txt_remove_args.proto->sval[0], host, mdns_txt_remove_args.var->sval[0]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1103,7 +1104,7 @@ static void register_mdns_service_txt_remove(void)
|
||||
.argtable = &mdns_txt_remove_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_txt_remove) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_txt_remove));
|
||||
}
|
||||
|
||||
static int cmd_mdns_service_remove_all(int argc, char **argv)
|
||||
@ -1122,7 +1123,7 @@ static void register_mdns_service_remove_all(void)
|
||||
.argtable = NULL
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_free) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_free));
|
||||
}
|
||||
|
||||
#define MDNS_MAX_LOOKUP_RESULTS CONFIG_MDNS_MAX_SERVICES
|
||||
@ -1189,7 +1190,7 @@ static void register_mdns_lookup_service(void)
|
||||
.argtable = &mdns_lookup_service_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_lookup_service) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_lookup_service));
|
||||
}
|
||||
|
||||
static struct {
|
||||
@ -1237,7 +1238,7 @@ static void register_mdns_delegate_host(void)
|
||||
.argtable = &mdns_delegate_host_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_delegate_host) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_delegate_host));
|
||||
}
|
||||
|
||||
static struct {
|
||||
@ -1278,7 +1279,7 @@ static void register_mdns_undelegate_host(void)
|
||||
.argtable = &mdns_undelegate_host_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_undelegate_host) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_undelegate_host));
|
||||
}
|
||||
|
||||
static struct {
|
||||
@ -1310,7 +1311,7 @@ static int cmd_mdns_service_subtype(int argc, char **argv)
|
||||
if (mdns_service_subtype_args.host->count && mdns_service_subtype_args.host->sval[0]) {
|
||||
host = mdns_service_subtype_args.host->sval[0];
|
||||
}
|
||||
ESP_ERROR_CHECK( mdns_service_subtype_add_for_host(instance, mdns_service_subtype_args.service->sval[0], mdns_service_subtype_args.proto->sval[0], host, mdns_service_subtype_args.sub->sval[0]) );
|
||||
ESP_ERROR_CHECK(mdns_service_subtype_add_for_host(instance, mdns_service_subtype_args.service->sval[0], mdns_service_subtype_args.proto->sval[0], host, mdns_service_subtype_args.sub->sval[0]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1331,7 +1332,7 @@ static void register_mdns_service_subtype_set(void)
|
||||
.argtable = &mdns_service_subtype_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_service_sub) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_service_sub));
|
||||
}
|
||||
|
||||
static struct {
|
||||
@ -1377,7 +1378,7 @@ static void register_mdns_browse(void)
|
||||
.argtable = &mdns_browse_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_browse) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_browse));
|
||||
}
|
||||
|
||||
static int cmd_mdns_browse_del(int argc, char **argv)
|
||||
@ -1410,7 +1411,7 @@ static void register_mdns_browse_del(void)
|
||||
.argtable = &mdns_browse_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd_browse_del) );
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd_browse_del));
|
||||
}
|
||||
|
||||
void mdns_console_register(void)
|
||||
|
96
components/mdns/mdns_mem_caps.c
Normal file
96
components/mdns/mdns_mem_caps.c
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "mdns_private.h"
|
||||
#include "mdns_mem_caps.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#if CONFIG_MDNS_MEMORY_CUSTOM_IMPL
|
||||
#define ALLOW_WEAK __attribute__((weak))
|
||||
#else
|
||||
#define ALLOW_WEAK
|
||||
#endif
|
||||
|
||||
#if CONFIG_MDNS_TASK_CREATE_FROM_SPIRAM
|
||||
#define MDNS_TASK_MEMORY_CAPS (MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT)
|
||||
#define MDNS_TASK_MEMORY_LOG "SPIRAM"
|
||||
#endif
|
||||
#if CONFIG_MDNS_TASK_CREATE_FROM_INTERNAL
|
||||
#define MDNS_TASK_MEMORY_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||
#define MDNS_TASK_MEMORY_LOG "internal RAM"
|
||||
#endif
|
||||
|
||||
#if CONFIG_MDNS_MEMORY_ALLOC_SPIRAM
|
||||
#define MDNS_MEMORY_CAPS (MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT)
|
||||
#endif
|
||||
#if CONFIG_MDNS_MEMORY_ALLOC_INTERNAL
|
||||
#define MDNS_MEMORY_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||
#endif
|
||||
|
||||
// Allocate memory from internal heap as default.
|
||||
#ifndef MDNS_MEMORY_CAPS
|
||||
#warning "No memory allocation method defined, using internal memory"
|
||||
#define MDNS_MEMORY_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||
#endif
|
||||
#ifndef MDNS_TASK_MEMORY_CAPS
|
||||
#define MDNS_TASK_MEMORY_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||
#define MDNS_TASK_MEMORY_LOG "internal RAM"
|
||||
#endif
|
||||
|
||||
void ALLOW_WEAK *mdns_mem_malloc(size_t size)
|
||||
{
|
||||
return heap_caps_malloc(size, MDNS_MEMORY_CAPS);
|
||||
}
|
||||
|
||||
void ALLOW_WEAK *mdns_mem_calloc(size_t num, size_t size)
|
||||
{
|
||||
return heap_caps_calloc(num, size, MDNS_MEMORY_CAPS);
|
||||
}
|
||||
|
||||
void ALLOW_WEAK mdns_mem_free(void *ptr)
|
||||
{
|
||||
heap_caps_free(ptr);
|
||||
}
|
||||
|
||||
char ALLOW_WEAK *mdns_mem_strdup(const char *s)
|
||||
{
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
size_t len = strlen(s) + 1;
|
||||
char *copy = (char *)heap_caps_malloc(len, MDNS_MEMORY_CAPS);
|
||||
if (copy) {
|
||||
memcpy(copy, s, len);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
char ALLOW_WEAK *mdns_mem_strndup(const char *s, size_t n)
|
||||
{
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
size_t len = strnlen(s, n);
|
||||
char *copy = (char *)heap_caps_malloc(len + 1, MDNS_MEMORY_CAPS);
|
||||
if (copy) {
|
||||
memcpy(copy, s, len);
|
||||
copy[len] = '\0';
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
void ALLOW_WEAK *mdns_mem_task_malloc(size_t size)
|
||||
{
|
||||
ESP_LOGI("mdns_mem", "mDNS task will be created from %s", MDNS_TASK_MEMORY_LOG);
|
||||
return heap_caps_malloc(size, MDNS_TASK_MEMORY_CAPS);
|
||||
}
|
||||
|
||||
void ALLOW_WEAK mdns_mem_task_free(void *ptr)
|
||||
{
|
||||
heap_caps_free(ptr);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -20,6 +20,7 @@
|
||||
#include "esp_event.h"
|
||||
#include "mdns_networking.h"
|
||||
#include "esp_netif_net_stack.h"
|
||||
#include "mdns_mem_caps.h"
|
||||
|
||||
/*
|
||||
* MDNS Server Networking
|
||||
@ -143,7 +144,7 @@ static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip
|
||||
pb = pb->next;
|
||||
this_pb->next = NULL;
|
||||
|
||||
mdns_rx_packet_t *packet = (mdns_rx_packet_t *)malloc(sizeof(mdns_rx_packet_t));
|
||||
mdns_rx_packet_t *packet = (mdns_rx_packet_t *)mdns_mem_malloc(sizeof(mdns_rx_packet_t));
|
||||
if (!packet) {
|
||||
HOOK_MALLOC_FAILED;
|
||||
//missed packet - no memory
|
||||
@ -188,7 +189,7 @@ static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip
|
||||
bool found = false;
|
||||
for (i = 0; i < MDNS_MAX_INTERFACES; i++) {
|
||||
netif = esp_netif_get_netif_impl(_mdns_get_esp_netif(i));
|
||||
if (s_interfaces[i].proto && netif && netif == ip_current_input_netif ()) {
|
||||
if (s_interfaces[i].proto && netif && netif == ip_current_input_netif()) {
|
||||
#if LWIP_IPV4
|
||||
if (packet->src.type == IPADDR_TYPE_V4) {
|
||||
if ((packet->src.u_addr.ip4.addr & ip_2_ip4(&netif->netmask)->addr) != (ip_2_ip4(&netif->ip_addr)->addr & ip_2_ip4(&netif->netmask)->addr)) {
|
||||
@ -205,7 +206,7 @@ static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip
|
||||
|
||||
if (!found || _mdns_send_rx_action(packet) != ESP_OK) {
|
||||
pbuf_free(this_pb);
|
||||
free(packet);
|
||||
mdns_mem_free(packet);
|
||||
}
|
||||
}
|
||||
|
||||
@ -288,7 +289,7 @@ typedef struct {
|
||||
static err_t _mdns_pcb_init_api(struct tcpip_api_call_data *api_call_msg)
|
||||
{
|
||||
mdns_api_call_t *msg = (mdns_api_call_t *)api_call_msg;
|
||||
msg->err = _udp_pcb_init(msg->tcpip_if, msg->ip_protocol);
|
||||
msg->err = _udp_pcb_init(msg->tcpip_if, msg->ip_protocol) == ESP_OK ? ERR_OK : ERR_IF;
|
||||
return msg->err;
|
||||
}
|
||||
|
||||
@ -338,7 +339,7 @@ static err_t _mdns_udp_pcb_write_api(struct tcpip_api_call_data *api_call_msg)
|
||||
msg->err = ERR_IF;
|
||||
return ERR_IF;
|
||||
}
|
||||
esp_err_t err = udp_sendto_if (_pcb_main, msg->pbt, msg->ip, msg->port, (struct netif *)nif);
|
||||
esp_err_t err = udp_sendto_if(_pcb_main, msg->pbt, msg->ip, msg->port, (struct netif *)nif);
|
||||
pbuf_free(msg->pbt);
|
||||
msg->err = err;
|
||||
return err;
|
||||
@ -393,5 +394,5 @@ size_t _mdns_get_packet_len(mdns_rx_packet_t *packet)
|
||||
void _mdns_packet_free(mdns_rx_packet_t *packet)
|
||||
{
|
||||
pbuf_free(packet->pb);
|
||||
free(packet);
|
||||
mdns_mem_free(packet);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -21,6 +21,7 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#include "esp_log.h"
|
||||
#include "mdns_mem_caps.h"
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_LINUX)
|
||||
#include <sys/ioctl.h>
|
||||
@ -87,9 +88,9 @@ size_t _mdns_get_packet_len(mdns_rx_packet_t *packet)
|
||||
|
||||
void _mdns_packet_free(mdns_rx_packet_t *packet)
|
||||
{
|
||||
free(packet->pb->payload);
|
||||
free(packet->pb);
|
||||
free(packet);
|
||||
mdns_mem_free(packet->pb->payload);
|
||||
mdns_mem_free(packet->pb);
|
||||
mdns_mem_free(packet);
|
||||
}
|
||||
|
||||
esp_err_t _mdns_pcb_deinit(mdns_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
|
||||
@ -297,13 +298,13 @@ void sock_recv_task(void *arg)
|
||||
inet_to_espaddr(&raddr, &addr, &port);
|
||||
|
||||
// Allocate the packet structure and pass it to the mdns main engine
|
||||
mdns_rx_packet_t *packet = (mdns_rx_packet_t *) calloc(1, sizeof(mdns_rx_packet_t));
|
||||
struct pbuf *packet_pbuf = calloc(1, sizeof(struct pbuf));
|
||||
uint8_t *buf = malloc(len);
|
||||
if (packet == NULL || packet_pbuf == NULL || buf == NULL ) {
|
||||
free(buf);
|
||||
free(packet_pbuf);
|
||||
free(packet);
|
||||
mdns_rx_packet_t *packet = (mdns_rx_packet_t *) mdns_mem_calloc(1, sizeof(mdns_rx_packet_t));
|
||||
struct pbuf *packet_pbuf = mdns_mem_calloc(1, sizeof(struct pbuf));
|
||||
uint8_t *buf = mdns_mem_malloc(len);
|
||||
if (packet == NULL || packet_pbuf == NULL || buf == NULL) {
|
||||
mdns_mem_free(buf);
|
||||
mdns_mem_free(packet_pbuf);
|
||||
mdns_mem_free(packet);
|
||||
HOOK_MALLOC_FAILED;
|
||||
ESP_LOGE(TAG, "Failed to allocate the mdns packet");
|
||||
continue;
|
||||
@ -326,9 +327,9 @@ void sock_recv_task(void *arg)
|
||||
packet->src.type == ESP_IPADDR_TYPE_V4 ? MDNS_IP_PROTOCOL_V4 : MDNS_IP_PROTOCOL_V6;
|
||||
if (_mdns_send_rx_action(packet) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "_mdns_send_rx_action failed!");
|
||||
free(packet->pb->payload);
|
||||
free(packet->pb);
|
||||
free(packet);
|
||||
mdns_mem_free(packet->pb->payload);
|
||||
mdns_mem_free(packet->pb);
|
||||
mdns_mem_free(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -341,7 +342,7 @@ static void mdns_networking_init(void)
|
||||
{
|
||||
if (s_run_sock_recv_task == false) {
|
||||
s_run_sock_recv_task = true;
|
||||
xTaskCreate( sock_recv_task, "mdns recv task", 3 * 1024, NULL, 5, NULL );
|
||||
xTaskCreate(sock_recv_task, "mdns recv task", 3 * 1024, NULL, 5, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -392,7 +393,7 @@ static int create_socket(esp_netif_t *netif)
|
||||
}
|
||||
|
||||
int on = 1;
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0) {
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
|
||||
ESP_LOGE(TAG, "Failed setsockopt() to set SO_REUSEADDR. errno=%d: %s\n", errno, strerror(errno));
|
||||
}
|
||||
// Bind the socket to any address
|
||||
@ -419,7 +420,7 @@ static int create_socket(esp_netif_t *netif)
|
||||
#endif // CONFIG_LWIP_IPV6
|
||||
struct ifreq ifr;
|
||||
esp_netif_get_netif_impl_name(netif, ifr.ifr_name);
|
||||
int ret = setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(struct ifreq));
|
||||
int ret = setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(struct ifreq));
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "\"%s\" Unable to bind socket to specified interface. errno=%d: %s", esp_netif_get_desc(netif), errno, strerror(errno));
|
||||
goto err;
|
||||
|
54
components/mdns/mem_prefix_script.py
Normal file
54
components/mdns/mem_prefix_script.py
Normal file
@ -0,0 +1,54 @@
|
||||
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
import re
|
||||
import sys
|
||||
|
||||
# Configurable prefix for memory functions
|
||||
MDNS_MEM_PREFIX = 'mdns_mem_' # Change this to modify the prefix
|
||||
|
||||
|
||||
def add_prefix_to_mem_funcs(content):
|
||||
# List of memory functions to prefix
|
||||
mem_funcs = [
|
||||
'malloc',
|
||||
'calloc',
|
||||
'free',
|
||||
'strdup',
|
||||
'strndup'
|
||||
]
|
||||
|
||||
# Create regex pattern matching the memory functions but not already prefixed ones
|
||||
pattern = fr'(?<!{MDNS_MEM_PREFIX})(?<![\w])(' + '|'.join(mem_funcs) + r')(?=\s*\()'
|
||||
|
||||
# Replace all occurrences with configured prefix
|
||||
modified = re.sub(pattern, fr'{MDNS_MEM_PREFIX}\1', content)
|
||||
|
||||
return modified
|
||||
|
||||
|
||||
def process_file(filename):
|
||||
try:
|
||||
# Read the file
|
||||
with open(filename, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
# Add prefixes
|
||||
modified = add_prefix_to_mem_funcs(content)
|
||||
|
||||
# Write back to file
|
||||
with open(filename, 'w') as f:
|
||||
f.write(modified)
|
||||
|
||||
print(f'Successfully processed {filename}')
|
||||
|
||||
except Exception as e:
|
||||
print(f'Error processing {filename}: {str(e)}')
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) != 2:
|
||||
print('Usage: python script.py <filename>')
|
||||
sys.exit(1)
|
||||
|
||||
process_file(sys.argv[1])
|
65
components/mdns/private_include/mdns_mem_caps.h
Normal file
65
components/mdns/private_include/mdns_mem_caps.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Allocate memory.
|
||||
* @param size Number of bytes to allocate.
|
||||
* @return Pointer to allocated memory, or NULL on failure.
|
||||
*/
|
||||
void *mdns_mem_malloc(size_t size);
|
||||
|
||||
/**
|
||||
* @brief Allocate and zero memory.
|
||||
* @param num Number of elements.
|
||||
* @param size Size of each element.
|
||||
* @return Pointer to allocated memory, or NULL on failure.
|
||||
*/
|
||||
void *mdns_mem_calloc(size_t num, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Free allocated memory.
|
||||
* @param ptr Pointer to memory to free.
|
||||
*/
|
||||
void mdns_mem_free(void *ptr);
|
||||
|
||||
/**
|
||||
* @brief Duplicate a string.
|
||||
* @param s String to duplicate.
|
||||
* @return Pointer to duplicated string, or NULL on failure.
|
||||
*/
|
||||
char *mdns_mem_strdup(const char *s);
|
||||
|
||||
/**
|
||||
* @brief Duplicate a string with length limit.
|
||||
* @param s String to duplicate.
|
||||
* @param n Maximum number of characters to copy.
|
||||
* @return Pointer to duplicated string, or NULL on failure.
|
||||
*/
|
||||
char *mdns_mem_strndup(const char *s, size_t n);
|
||||
|
||||
/**
|
||||
* @brief Allocate memory for mDNS task.
|
||||
* @param size Number of bytes to allocate.
|
||||
* @return Pointer to allocated memory, or NULL on failure.
|
||||
*/
|
||||
void *mdns_mem_task_malloc(size_t size);
|
||||
|
||||
/**
|
||||
* @brief Free allocated memory for mDNS task.
|
||||
* @param ptr Pointer to memory to free.
|
||||
*/
|
||||
void mdns_mem_task_free(void *ptr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -103,12 +103,6 @@
|
||||
#define MDNS_PACKET_QUEUE_LEN 16 // Maximum packets that can be queued for parsing
|
||||
#define MDNS_ACTION_QUEUE_LEN CONFIG_MDNS_ACTION_QUEUE_LEN // Maximum actions pending to the server
|
||||
#define MDNS_TXT_MAX_LEN 1024 // Maximum string length of text data in TXT record
|
||||
#if defined(CONFIG_LWIP_IPV6) && defined(CONFIG_MDNS_RESPOND_REVERSE_QUERIES)
|
||||
#define MDNS_NAME_MAX_LEN (64+4) // Need to account for IPv6 reverse queries (64 char address + ".ip6" )
|
||||
#else
|
||||
#define MDNS_NAME_MAX_LEN 64 // Maximum string length of hostname, instance, service and proto
|
||||
#endif
|
||||
#define MDNS_NAME_BUF_LEN (MDNS_NAME_MAX_LEN+1) // Maximum char buffer size to hold hostname, instance, service or proto
|
||||
#define MDNS_MAX_PACKET_SIZE 1460 // Maximum size of mDNS outgoing packet
|
||||
|
||||
#define MDNS_HEAD_LEN 12
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
@ -59,7 +59,7 @@ uint32_t xTaskGetTickCount(void)
|
||||
}
|
||||
|
||||
/// Queue mock
|
||||
QueueHandle_t xQueueCreate( uint32_t uxQueueLength, uint32_t uxItemSize )
|
||||
QueueHandle_t xQueueCreate(uint32_t uxQueueLength, uint32_t uxItemSize)
|
||||
{
|
||||
g_size = uxItemSize;
|
||||
g_queue = malloc((uxQueueLength) * (uxItemSize));
|
||||
@ -67,7 +67,7 @@ QueueHandle_t xQueueCreate( uint32_t uxQueueLength, uint32_t uxItemSize )
|
||||
}
|
||||
|
||||
|
||||
void vQueueDelete( QueueHandle_t xQueue )
|
||||
void vQueueDelete(QueueHandle_t xQueue)
|
||||
{
|
||||
free(xQueue);
|
||||
}
|
||||
@ -117,7 +117,46 @@ void esp_log_write(esp_log_level_t level, const char *tag, const char *format, .
|
||||
{
|
||||
}
|
||||
|
||||
void esp_log(esp_log_config_t config, const char *tag, const char *format, ...)
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t esp_log_timestamp(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *mdns_mem_malloc(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void *mdns_mem_calloc(size_t num, size_t size)
|
||||
{
|
||||
return calloc(num, size);
|
||||
}
|
||||
|
||||
void mdns_mem_free(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
char *mdns_mem_strdup(const char *s)
|
||||
{
|
||||
return strdup(s);
|
||||
}
|
||||
|
||||
char *mdns_mem_strndup(const char *s, size_t n)
|
||||
{
|
||||
return strndup(s, n);
|
||||
}
|
||||
|
||||
void *mdns_mem_task_malloc(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void mdns_mem_task_free(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -38,6 +38,10 @@
|
||||
#define ESP_ERR_INVALID_RESPONSE 0x108
|
||||
#define ESP_ERR_INVALID_CRC 0x109
|
||||
|
||||
#define MDNS_TASK_MEMORY_LOG "internal RAM"
|
||||
#define MALLOC_CAP_8BIT (1<<2)
|
||||
#define MALLOC_CAP_INTERNAL (1<<11)
|
||||
|
||||
#define pdTRUE true
|
||||
#define pdFALSE false
|
||||
#define pdPASS ( pdTRUE )
|
||||
@ -62,6 +66,7 @@
|
||||
#define vSemaphoreDelete(s) free(s)
|
||||
#define queueQUEUE_TYPE_MUTEX ( ( uint8_t ) 1U
|
||||
#define xTaskCreatePinnedToCore(a,b,c,d,e,f,g) *(f) = malloc(1)
|
||||
#define xTaskCreateStaticPinnedToCore(a,b,c,d,e,f,g,h) true
|
||||
#define vTaskDelay(m) usleep((m)*0)
|
||||
#define esp_random() (rand()%UINT32_MAX)
|
||||
|
||||
@ -79,7 +84,8 @@ typedef void *QueueHandle_t;
|
||||
typedef void *TaskHandle_t;
|
||||
typedef int BaseType_t;
|
||||
typedef uint32_t TickType_t;
|
||||
|
||||
typedef void *StackType_t;
|
||||
typedef void *StaticTask_t;
|
||||
|
||||
struct udp_pcb {
|
||||
uint8_t dummy;
|
||||
@ -111,10 +117,10 @@ uint32_t xTaskGetTickCount(void);
|
||||
typedef void (*esp_timer_cb_t)(void *arg);
|
||||
|
||||
// Queue mock
|
||||
QueueHandle_t xQueueCreate( uint32_t uxQueueLength,
|
||||
uint32_t uxItemSize );
|
||||
QueueHandle_t xQueueCreate(uint32_t uxQueueLength,
|
||||
uint32_t uxItemSize);
|
||||
|
||||
void vQueueDelete( QueueHandle_t xQueue );
|
||||
void vQueueDelete(QueueHandle_t xQueue);
|
||||
|
||||
uint32_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait);
|
||||
|
||||
@ -131,6 +137,6 @@ esp_err_t esp_event_handler_unregister(const char *event_base, int32_t event_id,
|
||||
|
||||
TaskHandle_t xTaskGetCurrentTaskHandle(void);
|
||||
void xTaskNotifyGive(TaskHandle_t task);
|
||||
BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time );
|
||||
BaseType_t xTaskNotifyWait(uint32_t bits_entry_clear, uint32_t bits_exit_clear, uint32_t *value, TickType_t wait_time);
|
||||
|
||||
#endif //_ESP32_COMPAT_H_
|
||||
|
3
components/mosquitto/.build-test-rules.yml
Normal file
3
components/mosquitto/.build-test-rules.yml
Normal file
@ -0,0 +1,3 @@
|
||||
components/mosquitto/examples/serverless_mqtt:
|
||||
disable:
|
||||
- if: IDF_TARGET not in ["esp32", "esp32s3", "esp32c3"]
|
@ -3,6 +3,6 @@ commitizen:
|
||||
bump_message: 'bump(mosq): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py mosquitto
|
||||
tag_format: mosq-v$version
|
||||
version: 2.0.28~0
|
||||
version: 2.0.20~1
|
||||
version_files:
|
||||
- idf_component.yml
|
||||
|
@ -1,5 +1,30 @@
|
||||
# Changelog
|
||||
|
||||
## [2.0.20~1](https://github.com/espressif/esp-protocols/commits/mosq-v2.0.20_1)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Use sock_utils instead of func stubs ([3cd0ed37](https://github.com/espressif/esp-protocols/commit/3cd0ed37))
|
||||
- Update API docs adding on-message callback ([5dcc3330](https://github.com/espressif/esp-protocols/commit/5dcc3330))
|
||||
|
||||
## [2.0.20](https://github.com/espressif/esp-protocols/commits/mosq-v2.0.20)
|
||||
|
||||
### Features
|
||||
|
||||
- Upgrade to mosquitto v2.0.20 ([3b2c614d](https://github.com/espressif/esp-protocols/commit/3b2c614d))
|
||||
- Add support for on-message callback ([cdeab8f5](https://github.com/espressif/esp-protocols/commit/cdeab8f5))
|
||||
- Add example with two brokers synced on P2P ([d57b8c5b](https://github.com/espressif/esp-protocols/commit/d57b8c5b))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix dependency issues moving esp-tls to public deps ([6cce87e4](https://github.com/espressif/esp-protocols/commit/6cce87e4))
|
||||
|
||||
## [2.0.28~0](https://github.com/espressif/esp-protocols/commits/mosq-v2.0.28_0)
|
||||
|
||||
### Warning
|
||||
|
||||
Incorrect version number! This version published under `2.0.28~0` is based on upstream v2.0.18
|
||||
|
||||
### Features
|
||||
|
||||
- Added support for TLS transport using ESP-TLS ([1af4bbe1](https://github.com/espressif/esp-protocols/commit/1af4bbe1))
|
||||
|
@ -74,15 +74,15 @@ idf_component_register(SRCS ${m_srcs}
|
||||
port/callbacks.c
|
||||
port/config.c
|
||||
port/signals.c
|
||||
port/ifaddrs.c
|
||||
port/broker.c
|
||||
port/files.c
|
||||
port/net__esp_tls.c
|
||||
port/sysconf.c
|
||||
PRIV_INCLUDE_DIRS port/priv_include port/priv_include/sys ${m_dir} ${m_src_dir}
|
||||
${m_incl_dir} ${m_lib_dir} ${m_deps_dir}
|
||||
INCLUDE_DIRS ${m_incl_dir} port/include
|
||||
PRIV_REQUIRES newlib esp-tls
|
||||
)
|
||||
REQUIRES esp-tls
|
||||
PRIV_REQUIRES newlib sock_utils)
|
||||
|
||||
target_compile_definitions(${COMPONENT_LIB} PRIVATE "WITH_BROKER")
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
||||
|
@ -20,7 +20,7 @@ mosq_broker_run(&config);
|
||||
|
||||
## Memory Footprint Considerations
|
||||
|
||||
The broker primarily uses the heap for internal data, with minimal use of static/BSS memory. It consumes approximately 60 kB of program memory.
|
||||
The broker primarily uses the heap for internal data, with minimal use of static/BSS memory. It consumes approximately 60 kB of program memory and minimum 5kB of stack size.
|
||||
|
||||
- **Initial Memory Usage**: ~2 kB of heap on startup
|
||||
- **Per Client Memory Usage**: ~4 kB of heap for each connected client
|
||||
|
@ -15,6 +15,7 @@
|
||||
| Type | Name |
|
||||
| ---: | :--- |
|
||||
| struct | [**mosq\_broker\_config**](#struct-mosq_broker_config) <br>_Mosquitto configuration structure._ |
|
||||
| typedef void(\* | [**mosq\_message\_cb\_t**](#typedef-mosq_message_cb_t) <br> |
|
||||
|
||||
## Functions
|
||||
|
||||
@ -34,12 +35,20 @@ ESP port of mosquittto supports only the options in this configuration structure
|
||||
|
||||
Variables:
|
||||
|
||||
- void(\* handle_message_cb <br>On message callback. If configured, user function is called whenever mosquitto processes a message.
|
||||
|
||||
- char \* host <br>Address on which the broker is listening for connections
|
||||
|
||||
- int port <br>Port number of the broker to listen to
|
||||
|
||||
- esp\_tls\_cfg\_server\_t \* tls_cfg <br>ESP-TLS configuration (if TLS transport used) Please refer to the ESP-TLS official documentation for more details on configuring the TLS options. You can open the respective docs with this idf.py command: `idf.py docs -sp api-reference/protocols/esp_tls.html`
|
||||
|
||||
### typedef `mosq_message_cb_t`
|
||||
|
||||
```c
|
||||
typedef void(* mosq_message_cb_t) (char *client, char *topic, char *data, int len, int qos, int retain);
|
||||
```
|
||||
|
||||
|
||||
## Functions Documentation
|
||||
|
||||
|
@ -0,0 +1,6 @@
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(serverless_mqtt)
|
53
components/mosquitto/examples/serverless_mqtt/README.md
Normal file
53
components/mosquitto/examples/serverless_mqtt/README.md
Normal file
@ -0,0 +1,53 @@
|
||||
# Brokerless MQTT Example
|
||||
|
||||
MQTT served by (two) mosquitto's running on two ESP chips.
|
||||
|
||||
* Leverages MQTT connectivity between two private networks without cloud premisses.
|
||||
* Creates two local MQTT servers (on ESP32x's) which are being synchronized over peer to peer connection (established via ICE protocol, by [libjuice](https://github.com/paullouisageneau/libjuice)).
|
||||
|
||||
## How it works
|
||||
|
||||
This example needs two ESP32 chipsets, that will create two separate Wi-Fi networks (IoT networks) used for IoT devices.
|
||||
Each IoT network is served by an MQTT server (using mosquitto component).
|
||||
This example will also synchronize these two MQTT brokers, as if there was only one IoT network with one broker.
|
||||
This example creates a peer to peer connection between two chipsets to keep them synchronize. This connection utilizes libjuice (which implements a simplified ICE-UDP) to traverse NATs, which enabling direct connection between two private networks behind NATs.
|
||||
|
||||
* Diagram
|
||||
|
||||

|
||||
|
||||
Here's a step-by-step procedure of establishing this remote connection:
|
||||
1) Initialize and start Wi-Fi AP (for IoT networks) and Wi-Fi station (for internet connection)
|
||||
2) Start mosquitto broker on IoT network
|
||||
3) Start libjuice to gather connection candidates
|
||||
4) Synchronize using a public MQTT broker and exchange ICE descriptors
|
||||
5) Establish ICE UDP connection between the two ESP32 chipsets
|
||||
6) Start forwarding mqtt messages
|
||||
- Each remote datagram (received from ICE-UDP channel) is re-published to the local MQTT server
|
||||
- Each local MQTT message (received from mosquitto on_message callback) is sent in ICE-UDP datagram
|
||||
|
||||
## How to use this example
|
||||
|
||||
You need two ESP32 devices that support Wi-Fi station and Wi-Fi software access point.
|
||||
|
||||
* Configure Wi-Fi credentials for both devices on both interfaces
|
||||
* These devices would be deployed in distinct Wi-Fi environments, so the Wi-Fi station credentials would likely be different.
|
||||
* They also create their own IoT network (on the soft-AP interface) Wi-Fi, so the AP credentials would likely be the same, suggesting the IoT networks will be keep synchronized (even though these are two distict Wi-Fi networks).
|
||||
* Choose `CONFIG_EXAMPLE_SERVERLESS_ROLE_PEER1` for one device and `CONFIG_EXAMPLE_SERVERLESS_ROLE_PEER2` for another. It's not important which device is PEER1, since the code is symmetric, but these two devices need to have different role.
|
||||
* Optionally: You can use `idf.py` `-D` and `-B` flag to keep separate build directories and sdkconfigs for these two roles
|
||||
```
|
||||
idf.py -B build1 -DSDKCONFIG=build1/sdkconfig menuconfig build flash monitor
|
||||
```
|
||||
* Flash and run the two devices and wait for them to connect and synchronize.
|
||||
* Now you can test MQTT connectivity, for example:
|
||||
* Join PEER1 device's AP and connect to the MQTT broker with one or more clients, subscribing to one or more topics.
|
||||
* Join PEER2 device's AP and connect to the MQTT broker with one or more clients, subscribing to one or more topics.
|
||||
* Whenever you publish to a topic, all subscribed clients should receive the message, no matter which Wi-Fi network they're connected to.
|
||||
|
||||
## Warning
|
||||
|
||||
This example uses libjuice as a dependency:
|
||||
|
||||
* libjuice (UDP Interactive Connectivity Establishment): https://github.com/paullouisageneau/libjuice
|
||||
|
||||
which is distributed under Mozilla Public License v2.0.
|
@ -0,0 +1,44 @@
|
||||
set(LIBJUICE_VERSION "73785387eafe15c02b6a210edb10f722474e8e14")
|
||||
set(LIBJUICE_URL "https://github.com/paullouisageneau/libjuice/archive/${LIBJUICE_VERSION}.zip")
|
||||
|
||||
set(libjuice_dir ${CMAKE_BINARY_DIR}/libjuice/libjuice-${LIBJUICE_VERSION})
|
||||
|
||||
# Fetch the library
|
||||
if(NOT EXISTS ${libjuice_dir})
|
||||
message(STATUS "Downloading libjuice ${LIBJUICE_VERSION}...")
|
||||
file(DOWNLOAD ${LIBJUICE_URL} ${CMAKE_BINARY_DIR}/libjuice.zip SHOW_PROGRESS)
|
||||
execute_process(COMMAND unzip -o ${CMAKE_BINARY_DIR}/libjuice.zip -d ${CMAKE_BINARY_DIR}/libjuice
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
endif()
|
||||
|
||||
set(JUICE_SOURCES ${libjuice_dir}/src/addr.c
|
||||
${libjuice_dir}/src/agent.c
|
||||
${libjuice_dir}/src/base64.c
|
||||
${libjuice_dir}/src/conn.c
|
||||
${libjuice_dir}/src/conn_mux.c
|
||||
${libjuice_dir}/src/conn_poll.c
|
||||
${libjuice_dir}/src/conn_thread.c
|
||||
${libjuice_dir}/src/const_time.c
|
||||
${libjuice_dir}/src/crc32.c
|
||||
${libjuice_dir}/src/hash.c
|
||||
${libjuice_dir}/src/ice.c
|
||||
${libjuice_dir}/src/juice.c
|
||||
${libjuice_dir}/src/log.c
|
||||
${libjuice_dir}/src/server.c
|
||||
${libjuice_dir}/src/stun.c
|
||||
${libjuice_dir}/src/timestamp.c
|
||||
${libjuice_dir}/src/turn.c
|
||||
${libjuice_dir}/src/udp.c
|
||||
# Use hmac from mbedtls and random numbers from esp_random:
|
||||
# ${libjuice_dir}/src/hmac.c
|
||||
# ${libjuice_dir}/src/random.c
|
||||
)
|
||||
|
||||
idf_component_register(SRCS port/juice_random.c
|
||||
${JUICE_SOURCES}
|
||||
INCLUDE_DIRS "include" "${libjuice_dir}/include" "${libjuice_dir}/include/juice"
|
||||
REQUIRES esp_netif
|
||||
PRIV_REQUIRES sock_utils)
|
||||
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
||||
set_source_files_properties(${libjuice_dir}/src/udp.c PROPERTIES COMPILE_FLAGS -Wno-unused-variable)
|
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// Purpose of this header is to replace udp_sendto() to avoid name conflict with lwip
|
||||
// added here since ifaddrs.h is included from juice_udp sources
|
||||
#define udp_sendto juice_udp_sendto
|
||||
|
||||
// other than that, let's just include the ifaddrs (from sock_utils)
|
||||
#include_next "ifaddrs.h"
|
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Paul-Louis Ageneau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
#include "esp_random.h"
|
||||
|
||||
void juice_random(void *buf, size_t size)
|
||||
{
|
||||
esp_fill_random(buf, size);
|
||||
}
|
||||
|
||||
void juice_random_str64(char *buf, size_t size)
|
||||
{
|
||||
static const char chars64[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
size_t i = 0;
|
||||
for (i = 0; i + 1 < size; ++i) {
|
||||
uint8_t byte = 0;
|
||||
juice_random(&byte, 1);
|
||||
buf[i] = chars64[byte & 0x3F];
|
||||
}
|
||||
buf[i] = '\0';
|
||||
}
|
||||
|
||||
uint32_t juice_rand32(void)
|
||||
{
|
||||
uint32_t r = 0;
|
||||
juice_random(&r, sizeof(r));
|
||||
return r;
|
||||
}
|
||||
|
||||
uint64_t juice_rand64(void)
|
||||
{
|
||||
uint64_t r = 0;
|
||||
juice_random(&r, sizeof(r));
|
||||
return r;
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
idf_component_register(SRCS "serverless_mqtt.c"
|
||||
"wifi_connect.c"
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES libjuice nvs_flash mqtt json esp_wifi)
|
@ -0,0 +1,85 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
menu "AP Configuration"
|
||||
comment "AP Configuration"
|
||||
|
||||
config EXAMPLE_AP_SSID
|
||||
string "Wi-Fi SSID"
|
||||
default "myssid"
|
||||
help
|
||||
Set the SSID of Wi-Fi ap interface.
|
||||
|
||||
config EXAMPLE_AP_PASSWORD
|
||||
string "Wi-Fi Password"
|
||||
default "12345678"
|
||||
help
|
||||
Set the password of Wi-Fi ap interface.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "STA Configuration"
|
||||
comment "STA Configuration"
|
||||
|
||||
config EXAMPLE_STA_SSID
|
||||
string "WiFi Station SSID"
|
||||
default "mystationssid"
|
||||
help
|
||||
SSID for the example's sta to connect to.
|
||||
|
||||
config EXAMPLE_STA_PASSWORD
|
||||
string "WiFi Station Password"
|
||||
default "mystationpassword"
|
||||
help
|
||||
WiFi station password for the example to use.
|
||||
endmenu
|
||||
|
||||
config EXAMPLE_MQTT_BROKER_URI
|
||||
string "MQTT Broker URL"
|
||||
default "mqtt://mqtt.eclipseprojects.io"
|
||||
help
|
||||
URL of the mqtt broker use for synchronisation and exchanging
|
||||
ICE connect info (description and candidates).
|
||||
|
||||
config EXAMPLE_MQTT_SYNC_TOPIC
|
||||
string "MQTT topic for synchronisation"
|
||||
default "/topic/serverless_mqtt"
|
||||
help
|
||||
MQTT topic used fo synchronisation.
|
||||
|
||||
config EXAMPLE_STUN_SERVER
|
||||
string "Hostname of STUN server"
|
||||
default "stun.l.google.com"
|
||||
help
|
||||
STUN server hostname.
|
||||
|
||||
config EXAMPLE_MQTT_CLIENT_STACK_SIZE
|
||||
int "Stack size for mqtt client"
|
||||
default 16384
|
||||
help
|
||||
Set stack size for the mqtt client.
|
||||
Need more stack, since calling juice API from the handler.
|
||||
|
||||
config EXAMPLE_MQTT_BROKER_PORT
|
||||
int "port for the mosquitto to listen to"
|
||||
default 1883
|
||||
help
|
||||
This is a port which the local mosquitto uses.
|
||||
|
||||
choice EXAMPLE_SERVERLESS_ROLE
|
||||
prompt "Choose your role"
|
||||
default EXAMPLE_SERVERLESS_ROLE_PEER1
|
||||
help
|
||||
Choose either peer1 or peer2.
|
||||
It's not very important which device is peer1
|
||||
(peer-1 sends sync messages, peer2 listens for them)
|
||||
It is important that we have two peers,
|
||||
one with peer1 config, another one with peer2 config
|
||||
|
||||
config EXAMPLE_SERVERLESS_ROLE_PEER1
|
||||
bool "peer1"
|
||||
|
||||
config EXAMPLE_SERVERLESS_ROLE_PEER2
|
||||
bool "peer2"
|
||||
endchoice
|
||||
|
||||
endmenu
|
@ -0,0 +1,5 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/mosquitto:
|
||||
override_path: ../../..
|
||||
espressif/sock_utils: "*"
|
@ -0,0 +1,374 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "mqtt_client.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_random.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "mosq_broker.h"
|
||||
#include "juice/juice.h"
|
||||
#include "cJSON.h"
|
||||
|
||||
#if defined(CONFIG_EXAMPLE_SERVERLESS_ROLE_PEER1)
|
||||
#define OUR_PEER "1"
|
||||
#define THEIR_PEER "2"
|
||||
#elif defined(CONFIG_EXAMPLE_SERVERLESS_ROLE_PEER2)
|
||||
#define OUR_PEER "2"
|
||||
#define THEIR_PEER "1"
|
||||
#endif
|
||||
|
||||
#define PEER_SYNC0 BIT(0)
|
||||
#define PEER_SYNC1 BIT(1)
|
||||
#define PEER_SYNC2 BIT(2)
|
||||
#define PEER_FAIL BIT(3)
|
||||
#define PEER_GATHER_DONE BIT(4)
|
||||
#define PEER_DESC_PUBLISHED BIT(5)
|
||||
#define PEER_CONNECTED BIT(6)
|
||||
|
||||
#define SYNC_BITS (PEER_SYNC1 | PEER_SYNC2 | PEER_FAIL)
|
||||
|
||||
#define PUBLISH_SYNC_TOPIC CONFIG_EXAMPLE_MQTT_SYNC_TOPIC OUR_PEER
|
||||
#define SUBSCRIBE_SYNC_TOPIC CONFIG_EXAMPLE_MQTT_SYNC_TOPIC THEIR_PEER
|
||||
#define MAX_BUFFER_SIZE JUICE_MAX_SDP_STRING_LEN
|
||||
|
||||
typedef struct message_wrap {
|
||||
uint16_t topic_len;
|
||||
uint16_t data_len;
|
||||
char data[];
|
||||
} __attribute__((packed)) message_wrap_t;
|
||||
|
||||
static const char *TAG = "serverless_mqtt" OUR_PEER;
|
||||
static char s_buffer[MAX_BUFFER_SIZE];
|
||||
static EventGroupHandle_t s_state = NULL;
|
||||
static juice_agent_t *s_agent = NULL;
|
||||
static cJSON *s_peer_desc_json = NULL;
|
||||
static char *s_peer_desc = NULL;
|
||||
static esp_mqtt_client_handle_t s_local_mqtt = NULL;
|
||||
|
||||
char *wifi_get_ipv4(wifi_interface_t interface);
|
||||
esp_err_t wifi_connect(void);
|
||||
static esp_err_t sync_peers(void);
|
||||
static esp_err_t create_candidates(void);
|
||||
static esp_err_t create_local_client(void);
|
||||
static esp_err_t create_local_broker(void);
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
__attribute__((__unused__)) esp_err_t ret;
|
||||
ESP_GOTO_ON_ERROR(wifi_connect(), err, TAG, "Failed to initialize WiFi");
|
||||
ESP_GOTO_ON_ERROR(create_local_broker(), err, TAG, "Failed to create local broker");
|
||||
ESP_GOTO_ON_ERROR(create_candidates(), err, TAG, "Failed to create juice candidates");
|
||||
ESP_GOTO_ON_ERROR(sync_peers(), err, TAG, "Failed to sync with the other peer");
|
||||
EventBits_t bits = xEventGroupWaitBits(s_state, PEER_FAIL | PEER_CONNECTED, pdFALSE, pdFALSE, pdMS_TO_TICKS(90000));
|
||||
if (bits & PEER_CONNECTED) {
|
||||
ESP_LOGI(TAG, "Peer is connected!");
|
||||
ESP_GOTO_ON_ERROR(create_local_client(), err, TAG, "Failed to create forwarding mqtt client");
|
||||
ESP_LOGI(TAG, "Everything is ready, exiting main task");
|
||||
return;
|
||||
}
|
||||
err:
|
||||
ESP_LOGE(TAG, "Non recoverable error, going to sleep for some time (random, max 20s)");
|
||||
esp_deep_sleep(1000000LL * (esp_random() % 20));
|
||||
}
|
||||
|
||||
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
esp_mqtt_event_handle_t event = event_data;
|
||||
esp_mqtt_client_handle_t client = event->client;
|
||||
switch ((esp_mqtt_event_id_t)event_id) {
|
||||
case MQTT_EVENT_CONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
|
||||
if (esp_mqtt_client_subscribe(client, SUBSCRIBE_SYNC_TOPIC, 1) < 0) {
|
||||
ESP_LOGE(TAG, "Failed to subscribe to the sync topic");
|
||||
}
|
||||
xEventGroupSetBits(s_state, PEER_SYNC0);
|
||||
break;
|
||||
case MQTT_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
|
||||
xEventGroupSetBits(s_state, PEER_FAIL);
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_DATA:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
|
||||
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
|
||||
printf("DATA=%.*s\r\n", event->data_len, event->data);
|
||||
if (s_state == NULL || memcmp(event->topic, SUBSCRIBE_SYNC_TOPIC, event->topic_len) != 0) {
|
||||
break;
|
||||
}
|
||||
EventBits_t bits = xEventGroupGetBits(s_state);
|
||||
if (event->data_len > 1 && s_agent) {
|
||||
cJSON *root = cJSON_Parse(event->data);
|
||||
if (root == NULL) {
|
||||
break;
|
||||
}
|
||||
cJSON *desc = cJSON_GetObjectItem(root, "desc");
|
||||
if (desc == NULL) {
|
||||
cJSON_Delete(root);
|
||||
break;
|
||||
}
|
||||
printf("desc->valuestring:%s\n", desc->valuestring);
|
||||
juice_set_remote_description(s_agent, desc->valuestring);
|
||||
char cand_name[] = "cand0";
|
||||
while (true) {
|
||||
cJSON *cand = cJSON_GetObjectItem(root, cand_name);
|
||||
if (cand == NULL) {
|
||||
break;
|
||||
}
|
||||
printf("%s: cand->valuestring:%s\n", cand_name, cand->valuestring);
|
||||
juice_add_remote_candidate(s_agent, cand->valuestring);
|
||||
cand_name[4]++;
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
xEventGroupSetBits(s_state, PEER_DESC_PUBLISHED); // this will complete the sync process
|
||||
// and destroy the mqtt client
|
||||
}
|
||||
#ifdef CONFIG_EXAMPLE_SERVERLESS_ROLE_PEER1
|
||||
if (event->data_len == 1 && event->data[0] == '1' && (bits & PEER_SYNC2) == 0) {
|
||||
if (esp_mqtt_client_publish(client, PUBLISH_SYNC_TOPIC, "2", 1, 1, 0) >= 0) {
|
||||
xEventGroupSetBits(s_state, PEER_SYNC2);
|
||||
} else {
|
||||
xEventGroupSetBits(s_state, PEER_FAIL);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (event->data_len == 1 && event->data[0] == '0' && (bits & PEER_SYNC1) == 0) {
|
||||
if (esp_mqtt_client_publish(client, PUBLISH_SYNC_TOPIC, "1", 1, 1, 0) >= 0) {
|
||||
xEventGroupSetBits(s_state, PEER_SYNC1);
|
||||
} else {
|
||||
xEventGroupSetBits(s_state, PEER_FAIL);
|
||||
}
|
||||
} else if (event->data_len == 1 && event->data[0] == '2' && (bits & PEER_SYNC2) == 0) {
|
||||
xEventGroupSetBits(s_state, PEER_SYNC2);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case MQTT_EVENT_ERROR:
|
||||
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
|
||||
xEventGroupSetBits(s_state, PEER_FAIL);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t sync_peers(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
esp_mqtt_client_config_t mqtt_cfg = {
|
||||
.broker.address.uri = CONFIG_EXAMPLE_MQTT_BROKER_URI,
|
||||
.task.stack_size = CONFIG_EXAMPLE_MQTT_CLIENT_STACK_SIZE,
|
||||
};
|
||||
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
|
||||
ESP_GOTO_ON_FALSE(client, ESP_ERR_NO_MEM, err, TAG, "Failed to create mqtt client");
|
||||
ESP_GOTO_ON_ERROR(esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL),
|
||||
err, TAG, "Failed to register mqtt event handler");
|
||||
ESP_GOTO_ON_ERROR(esp_mqtt_client_start(client), err, TAG, "Failed to start mqtt client");
|
||||
ESP_GOTO_ON_FALSE(xEventGroupWaitBits(s_state, PEER_SYNC0, pdTRUE, pdTRUE, pdMS_TO_TICKS(10000)),
|
||||
ESP_FAIL, err, TAG, "Failed to connect to the sync broker");
|
||||
ESP_LOGI(TAG, "Waiting for the other peer...");
|
||||
const int max_sync_retry = 60;
|
||||
int retry = 0;
|
||||
while (true) {
|
||||
EventBits_t bits = xEventGroupWaitBits(s_state, SYNC_BITS, pdTRUE, pdFALSE, pdMS_TO_TICKS(1000));
|
||||
if (bits & PEER_SYNC2) {
|
||||
break;
|
||||
}
|
||||
if (bits & PEER_SYNC1) {
|
||||
continue;
|
||||
}
|
||||
ESP_GOTO_ON_FALSE((bits & PEER_FAIL) == 0, ESP_FAIL, err, TAG, "Failed to sync with the other peer");
|
||||
ESP_GOTO_ON_FALSE(retry++ < max_sync_retry, ESP_FAIL, err, TAG, "Failed to sync after %d seconds", retry);
|
||||
#ifdef CONFIG_EXAMPLE_SERVERLESS_ROLE_PEER1
|
||||
ESP_RETURN_ON_FALSE(esp_mqtt_client_publish(client, PUBLISH_SYNC_TOPIC, "0", 1, 1, 0) >= 0,
|
||||
ESP_FAIL, TAG, "Failed to publish mqtt message");
|
||||
#endif
|
||||
}
|
||||
ESP_LOGI(TAG, "Sync done");
|
||||
ESP_RETURN_ON_FALSE(esp_mqtt_client_publish(client, PUBLISH_SYNC_TOPIC, s_peer_desc, 0, 1, 0) >= 0,
|
||||
ESP_FAIL, TAG, "Failed to publish peer's description");
|
||||
ESP_LOGI(TAG, "Waiting for the other peer description and candidates...");
|
||||
ESP_GOTO_ON_FALSE(xEventGroupWaitBits(s_state, PEER_DESC_PUBLISHED, pdTRUE, pdTRUE, pdMS_TO_TICKS(10000)),
|
||||
ESP_FAIL, err, TAG, "Timeout in waiting for the other peer candidates");
|
||||
err:
|
||||
free(s_peer_desc);
|
||||
esp_mqtt_client_destroy(client);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void juice_state(juice_agent_t *agent, juice_state_t state, void *user_ptr)
|
||||
{
|
||||
ESP_LOGI(TAG, "JUICE state change: %s", juice_state_to_string(state));
|
||||
if (state == JUICE_STATE_CONNECTED) {
|
||||
xEventGroupSetBits(s_state, PEER_CONNECTED);
|
||||
} else if (state == JUICE_STATE_FAILED || state == JUICE_STATE_DISCONNECTED) {
|
||||
esp_restart();
|
||||
}
|
||||
}
|
||||
|
||||
static void juice_candidate(juice_agent_t *agent, const char *sdp, void *user_ptr)
|
||||
{
|
||||
static uint8_t cand_nr = 0;
|
||||
if (s_peer_desc_json && cand_nr < 10) { // supporting only 10 candidates
|
||||
char cand_name[] = "cand0";
|
||||
cand_name[4] += cand_nr++;
|
||||
cJSON_AddStringToObject(s_peer_desc_json, cand_name, sdp);
|
||||
}
|
||||
}
|
||||
|
||||
static void juice_gathering_done(juice_agent_t *agent, void *user_ptr)
|
||||
{
|
||||
ESP_LOGI(TAG, "Gathering done");
|
||||
if (s_state) {
|
||||
xEventGroupSetBits(s_state, PEER_GATHER_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
#define ALIGN(size) (((size) + 3U) & ~(3U))
|
||||
|
||||
static void juice_recv(juice_agent_t *agent, const char *data, size_t size, void *user_ptr)
|
||||
{
|
||||
if (s_local_mqtt) {
|
||||
message_wrap_t *message = (message_wrap_t *)data;
|
||||
int topic_len = message->topic_len;
|
||||
int payload_len = message->data_len;
|
||||
int topic_len_aligned = ALIGN(topic_len);
|
||||
char *topic = message->data;
|
||||
char *payload = message->data + topic_len_aligned;
|
||||
if (topic_len + topic_len_aligned + 4 > size) {
|
||||
ESP_LOGE(TAG, "Received invalid message");
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "forwarding remote message: topic:%s", topic);
|
||||
ESP_LOGI(TAG, "forwarding remote message: payload:%.*s", payload_len, payload);
|
||||
esp_mqtt_client_publish(s_local_mqtt, topic, payload, payload_len, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t create_candidates(void)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(s_state = xEventGroupCreate(), ESP_ERR_NO_MEM, TAG, "Failed to create state event group");
|
||||
s_peer_desc_json = cJSON_CreateObject();
|
||||
esp_err_t ret = ESP_OK;
|
||||
juice_set_log_level(JUICE_LOG_LEVEL_INFO);
|
||||
juice_config_t config = { .stun_server_host = CONFIG_EXAMPLE_STUN_SERVER,
|
||||
.bind_address = wifi_get_ipv4(WIFI_IF_STA),
|
||||
.stun_server_port = 19302,
|
||||
.cb_state_changed = juice_state,
|
||||
.cb_candidate = juice_candidate,
|
||||
.cb_gathering_done = juice_gathering_done,
|
||||
.cb_recv = juice_recv,
|
||||
};
|
||||
|
||||
s_agent = juice_create(&config);
|
||||
ESP_RETURN_ON_FALSE(s_agent, ESP_FAIL, TAG, "Failed to create juice agent");
|
||||
ESP_GOTO_ON_FALSE(juice_get_local_description(s_agent, s_buffer, MAX_BUFFER_SIZE) == JUICE_ERR_SUCCESS,
|
||||
ESP_FAIL, err, TAG, "Failed to get local description");
|
||||
ESP_LOGI(TAG, "desc: %s", s_buffer);
|
||||
cJSON_AddStringToObject(s_peer_desc_json, "desc", s_buffer);
|
||||
|
||||
ESP_GOTO_ON_FALSE(juice_gather_candidates(s_agent) == JUICE_ERR_SUCCESS,
|
||||
ESP_FAIL, err, TAG, "Failed to start gathering candidates");
|
||||
ESP_GOTO_ON_FALSE(xEventGroupWaitBits(s_state, PEER_GATHER_DONE, pdTRUE, pdTRUE, pdMS_TO_TICKS(30000)),
|
||||
ESP_FAIL, err, TAG, "Failed to connect to the sync broker");
|
||||
s_peer_desc = cJSON_Print(s_peer_desc_json);
|
||||
ESP_LOGI(TAG, "desc: %s", s_peer_desc);
|
||||
cJSON_Delete(s_peer_desc_json);
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
juice_destroy(s_agent);
|
||||
s_agent = NULL;
|
||||
cJSON_Delete(s_peer_desc_json);
|
||||
s_peer_desc_json = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void local_handler(void *args, esp_event_base_t base, int32_t id, void *data)
|
||||
{
|
||||
switch (id) {
|
||||
case MQTT_EVENT_CONNECTED:
|
||||
ESP_LOGI(TAG, "local client connected");
|
||||
break;
|
||||
case MQTT_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "local client disconnected");
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_ERROR:
|
||||
ESP_LOGI(TAG, "local client error");
|
||||
break;
|
||||
default:
|
||||
ESP_LOGI(TAG, "local client event id:%d", (int)id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t create_local_client(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
esp_mqtt_client_config_t mqtt_cfg = {
|
||||
.broker.address.transport = MQTT_TRANSPORT_OVER_TCP,
|
||||
.broker.address.hostname = wifi_get_ipv4(WIFI_IF_AP),
|
||||
.broker.address.port = CONFIG_EXAMPLE_MQTT_BROKER_PORT,
|
||||
.task.stack_size = CONFIG_EXAMPLE_MQTT_CLIENT_STACK_SIZE,
|
||||
.credentials.client_id = "local_mqtt"
|
||||
};
|
||||
s_local_mqtt = esp_mqtt_client_init(&mqtt_cfg);
|
||||
ESP_GOTO_ON_FALSE(s_local_mqtt, ESP_ERR_NO_MEM, err, TAG, "Failed to create mqtt client");
|
||||
ESP_GOTO_ON_ERROR(esp_mqtt_client_register_event(s_local_mqtt, ESP_EVENT_ANY_ID, local_handler, NULL),
|
||||
err, TAG, "Failed to register mqtt event handler");
|
||||
ESP_GOTO_ON_ERROR(esp_mqtt_client_start(s_local_mqtt), err, TAG, "Failed to start mqtt client");
|
||||
|
||||
return ESP_OK;
|
||||
err:
|
||||
esp_mqtt_client_destroy(s_local_mqtt);
|
||||
s_local_mqtt = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void handle_message(char *client, char *topic, char *payload, int len, int qos, int retain)
|
||||
{
|
||||
if (client && strcmp(client, "local_mqtt") == 0 ) {
|
||||
// This is our little local client -- do not forward
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "handle_message topic:%s", topic);
|
||||
ESP_LOGI(TAG, "handle_message data:%.*s", len, payload);
|
||||
ESP_LOGI(TAG, "handle_message qos=%d, retain=%d", qos, retain);
|
||||
if (s_local_mqtt && s_agent) {
|
||||
int topic_len = strlen(topic) + 1; // null term
|
||||
int topic_len_aligned = ALIGN(topic_len);
|
||||
int total_msg_len = 2 + 2 /* msg_wrap header */ + topic_len_aligned + len;
|
||||
if (total_msg_len > MAX_BUFFER_SIZE) {
|
||||
ESP_LOGE(TAG, "Fail to forward, message too long");
|
||||
return;
|
||||
}
|
||||
message_wrap_t *message = (message_wrap_t *)s_buffer;
|
||||
message->topic_len = topic_len;
|
||||
message->data_len = len;
|
||||
|
||||
memcpy(s_buffer + 4, topic, topic_len);
|
||||
memcpy(s_buffer + 4 + topic_len_aligned, payload, len);
|
||||
juice_send(s_agent, s_buffer, total_msg_len);
|
||||
}
|
||||
}
|
||||
|
||||
static void broker_task(void *ctx)
|
||||
{
|
||||
struct mosq_broker_config config = { .host = wifi_get_ipv4(WIFI_IF_AP), .port = CONFIG_EXAMPLE_MQTT_BROKER_PORT, .handle_message_cb = handle_message };
|
||||
mosq_broker_run(&config);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static esp_err_t create_local_broker(void)
|
||||
{
|
||||
return xTaskCreate(broker_task, "mqtt_broker_task", 1024 * 32, NULL, 5, NULL) == pdTRUE ?
|
||||
ESP_OK : ESP_FAIL;
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_mac.h"
|
||||
|
||||
#define WIFI_CONNECTED_BIT BIT0
|
||||
#define WIFI_FAIL_BIT BIT1
|
||||
|
||||
static const char *TAG = "serverless_wifi";
|
||||
static EventGroupHandle_t s_wifi_events;
|
||||
static int s_retry_num = 0;
|
||||
static const int s_max_retry = 30;
|
||||
|
||||
static void wifi_event_handler(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
if (event_id == WIFI_EVENT_AP_STACONNECTED) {
|
||||
wifi_event_ap_staconnected_t *event = (wifi_event_ap_staconnected_t *) event_data;
|
||||
ESP_LOGI(TAG, "station "MACSTR" join, AID=%d",
|
||||
MAC2STR(event->mac), event->aid);
|
||||
} else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {
|
||||
wifi_event_ap_stadisconnected_t *event = (wifi_event_ap_stadisconnected_t *) event_data;
|
||||
ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d",
|
||||
MAC2STR(event->mac), event->aid);
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
||||
esp_wifi_connect();
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||
if (s_retry_num < s_max_retry) {
|
||||
esp_wifi_connect();
|
||||
s_retry_num++;
|
||||
ESP_LOGI(TAG, "retry to connect to the AP");
|
||||
} else {
|
||||
xEventGroupSetBits(s_wifi_events, WIFI_FAIL_BIT);
|
||||
}
|
||||
ESP_LOGI(TAG, "Connect to the AP fail");
|
||||
} 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;
|
||||
ESP_LOGI(TAG, "Got ip:" IPSTR, IP2STR(&event->ip_info.ip));
|
||||
s_retry_num = 0;
|
||||
xEventGroupSetBits(s_wifi_events, WIFI_CONNECTED_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t wifi_connect(void)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_GOTO_ON_FALSE(s_wifi_events = xEventGroupCreate(), ESP_ERR_NO_MEM, err, TAG, "Failed to create wifi_events");
|
||||
ESP_GOTO_ON_ERROR(nvs_flash_init(), err, TAG, "Failed to init nvs flash");
|
||||
ESP_GOTO_ON_ERROR(esp_netif_init(), err, TAG, "Failed to init esp_netif");
|
||||
ESP_GOTO_ON_ERROR(esp_event_loop_create_default(), err, TAG, "Failed to create default event loop");
|
||||
ESP_GOTO_ON_ERROR(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handler, NULL),
|
||||
err, TAG, "Failed to register WiFi event handler");
|
||||
ESP_GOTO_ON_ERROR(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, wifi_event_handler, NULL),
|
||||
err, TAG, "Failed to register IP event handler");
|
||||
|
||||
// Initialize WiFi
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_GOTO_ON_ERROR(esp_wifi_init(&cfg), err, TAG, "Failed to initialize WiFi");
|
||||
ESP_GOTO_ON_ERROR(esp_wifi_set_mode(WIFI_MODE_APSTA), err, TAG, "Failed to set STA+AP mode");
|
||||
|
||||
// Initialize AP
|
||||
esp_netif_t *ap = esp_netif_create_default_wifi_ap();
|
||||
ESP_GOTO_ON_FALSE(ap, ESP_FAIL, err, TAG, "Failed to create AP network interface");
|
||||
wifi_config_t wifi_ap_config = {
|
||||
.ap = {
|
||||
.ssid = CONFIG_EXAMPLE_AP_SSID,
|
||||
.password = CONFIG_EXAMPLE_AP_PASSWORD,
|
||||
.authmode = WIFI_AUTH_WPA2_PSK,
|
||||
.max_connection = 4,
|
||||
},
|
||||
};
|
||||
ESP_GOTO_ON_ERROR(esp_wifi_set_config(WIFI_IF_AP, &wifi_ap_config), err, TAG, "Failed to set AP config");
|
||||
|
||||
|
||||
// Initialize STA
|
||||
esp_netif_t *sta = esp_netif_create_default_wifi_sta();
|
||||
ESP_GOTO_ON_FALSE(sta, ESP_FAIL, err, TAG, "Failed to create WiFi station network interface");
|
||||
wifi_config_t wifi_sta_config = {
|
||||
.sta = {
|
||||
.ssid = CONFIG_EXAMPLE_STA_SSID,
|
||||
.password = CONFIG_EXAMPLE_STA_PASSWORD,
|
||||
},
|
||||
};
|
||||
ESP_GOTO_ON_ERROR(esp_wifi_set_config(WIFI_IF_STA, &wifi_sta_config), err, TAG, "Failed to set STA config");
|
||||
|
||||
// Start WiFi
|
||||
ESP_GOTO_ON_ERROR(esp_wifi_start(), err, TAG, "Failed to start WiFi");
|
||||
|
||||
// Wait for connection
|
||||
EventBits_t bits = xEventGroupWaitBits(s_wifi_events, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
|
||||
pdFALSE, pdFALSE, pdMS_TO_TICKS(30000));
|
||||
ESP_GOTO_ON_FALSE((bits & WIFI_CONNECTED_BIT) == WIFI_CONNECTED_BIT, ESP_FAIL, err,
|
||||
TAG, "Failed to obtain IP address from WiFi station");
|
||||
return ESP_OK;
|
||||
err:
|
||||
esp_wifi_stop();
|
||||
esp_wifi_deinit();
|
||||
nvs_flash_deinit();
|
||||
esp_netif_deinit();
|
||||
esp_event_loop_delete_default();
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
_Thread_local char s_ipv4_addr[4 * 4]; // 4 octets + '.'/term
|
||||
|
||||
char *wifi_get_ipv4(wifi_interface_t interface)
|
||||
{
|
||||
esp_netif_t *netif = esp_netif_get_handle_from_ifkey(interface == WIFI_IF_AP ? "WIFI_AP_DEF" : "WIFI_STA_DEF");
|
||||
ESP_RETURN_ON_FALSE(netif, NULL, TAG, "Failed to find default Wi-Fi netif");
|
||||
esp_netif_ip_info_t ip_info;
|
||||
ESP_RETURN_ON_FALSE(esp_netif_get_ip_info(netif, &ip_info) == ESP_OK, NULL, TAG, "Failed to get IP from netif");
|
||||
ESP_RETURN_ON_FALSE(esp_ip4addr_ntoa(&ip_info.ip, s_ipv4_addr, sizeof(s_ipv4_addr)) != NULL, NULL, TAG, "Failed to convert IP");
|
||||
return s_ipv4_addr;
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=16384
|
||||
CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=32768
|
BIN
components/mosquitto/examples/serverless_mqtt/serverless.png
Normal file
BIN
components/mosquitto/examples/serverless_mqtt/serverless.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 84 KiB |
@ -1,5 +1,7 @@
|
||||
version: "2.0.28~0"
|
||||
version: "2.0.20~1"
|
||||
url: https://github.com/espressif/esp-protocols/tree/master/components/mosquitto
|
||||
description: The component provides a simple ESP32 port of mosquitto broker
|
||||
dependencies:
|
||||
idf: '>=5.1'
|
||||
espressif/sock_utils:
|
||||
version: '^0.2'
|
||||
|
Submodule components/mosquitto/mosquitto updated: 3923526c6b...a196c2b244
@ -101,6 +101,8 @@ void mosq_broker_stop(void)
|
||||
run = 0;
|
||||
}
|
||||
|
||||
extern mosq_message_cb_t g_mosq_message_callback;
|
||||
|
||||
int mosq_broker_run(struct mosq_broker_config *broker_config)
|
||||
{
|
||||
|
||||
@ -125,6 +127,9 @@ int mosq_broker_run(struct mosq_broker_config *broker_config)
|
||||
if (broker_config->tls_cfg) {
|
||||
net__set_tls_config(broker_config->tls_cfg);
|
||||
}
|
||||
if (broker_config->handle_message_cb) {
|
||||
g_mosq_message_callback = broker_config->handle_message_cb;
|
||||
}
|
||||
|
||||
db.config = &config;
|
||||
|
||||
|
@ -13,7 +13,9 @@
|
||||
#include "util_mosq.h"
|
||||
#include "utlist.h"
|
||||
#include "lib_load.h"
|
||||
#include "mosq_broker.h"
|
||||
|
||||
mosq_message_cb_t g_mosq_message_callback = NULL;
|
||||
|
||||
int mosquitto_callback_register(
|
||||
mosquitto_plugin_id_t *identifier,
|
||||
@ -44,5 +46,8 @@ void plugin__handle_disconnect(struct mosquitto *context, int reason)
|
||||
|
||||
int plugin__handle_message(struct mosquitto *context, struct mosquitto_msg_store *stored)
|
||||
{
|
||||
if (g_mosq_message_callback) {
|
||||
g_mosq_message_callback(context->id, stored->topic, stored->payload, stored->payloadlen, stored->qos, stored->retain);
|
||||
}
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
}
|
||||
|
@ -1,20 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Roger Light <roger@atchoo.org>
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*
|
||||
* SPDX-FileContributor: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*/
|
||||
#include "ifaddrs.h"
|
||||
|
||||
// Dummy implementation of getifaddrs()
|
||||
// TODO: Implement this if we need to use bind_interface option of listener's config
|
||||
int getifaddrs(struct ifaddrs **ifap)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void freeifaddrs(struct ifaddrs *ifa)
|
||||
{
|
||||
|
||||
}
|
@ -9,6 +9,7 @@
|
||||
|
||||
struct mosquitto__config;
|
||||
|
||||
typedef void (*mosq_message_cb_t)(char *client, char *topic, char *data, int len, int qos, int retain);
|
||||
/**
|
||||
* @brief Mosquitto configuration structure
|
||||
*
|
||||
@ -24,6 +25,10 @@ struct mosq_broker_config {
|
||||
* You can open the respective docs with this idf.py command:
|
||||
* `idf.py docs -sp api-reference/protocols/esp_tls.html`
|
||||
*/
|
||||
void (*handle_message_cb)(char *client, char *topic, char *data, int len, int qos, int retain); /*!<
|
||||
* On message callback. If configured, user function is called
|
||||
* whenever mosquitto processes a message.
|
||||
*/
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -5,20 +5,11 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include <ctype.h>
|
||||
#include "net/if.h"
|
||||
|
||||
#undef isspace
|
||||
#define isspace(__c) (__ctype_lookup((int)__c)&_S)
|
||||
|
||||
#include_next "config.h"
|
||||
#define VERSION "v2.0.18~0"
|
||||
|
||||
#define _SC_OPEN_MAX_OVERRIDE 4
|
||||
|
||||
// used to override syscall for obtaining max open fds
|
||||
static inline long sysconf(int arg)
|
||||
{
|
||||
if (arg == _SC_OPEN_MAX_OVERRIDE) {
|
||||
return 64;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#define VERSION "v2.0.20~1"
|
||||
|
@ -1,17 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#define gai_strerror(x) "gai_strerror() not supported"
|
||||
|
||||
struct ifaddrs {
|
||||
struct ifaddrs *ifa_next; /* Next item in list */
|
||||
char *ifa_name; /* Name of interface */
|
||||
struct sockaddr *ifa_addr; /* Address of interface */
|
||||
};
|
||||
|
||||
int getifaddrs(struct ifaddrs **ifap);
|
||||
void freeifaddrs(struct ifaddrs *ifa);
|
@ -1,8 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include_next "sys/poll.h"
|
18
components/mosquitto/port/sysconf.c
Normal file
18
components/mosquitto/port/sysconf.c
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define _SC_OPEN_MAX_OVERRIDE 4
|
||||
|
||||
// used to override syscall for obtaining max open fds
|
||||
long sysconf(int arg)
|
||||
{
|
||||
if (arg == _SC_OPEN_MAX_OVERRIDE) {
|
||||
return 64;
|
||||
}
|
||||
return -1;
|
||||
}
|
5
components/mosquitto/test/README.md
Normal file
5
components/mosquitto/test/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# ESP32 mosquitto tests
|
||||
|
||||
Mosquitto component doesn't have any tests yet, but we upcycle IDF mqtt tests and run them with the current version of mosquitto.
|
||||
For that we need to update the IDF test project's `idf_component.yml` file to reference this actual version of mosquitto.
|
||||
We also need to update some pytest decorators to run only relevant test cases. See the [replacement](./replace_decorators.py) script.
|
42
components/mosquitto/test/replace_decorators.py
Normal file
42
components/mosquitto/test/replace_decorators.py
Normal file
@ -0,0 +1,42 @@
|
||||
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
|
||||
# This script replaces the `@pytest` decorators in the test files
|
||||
# based on the value of the `config` parameter in the `@pytest` decorator.
|
||||
# to reuse mqtt test cases for mosquitto broker.
|
||||
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
def replace_decorators(in_file: str, out_file: str) -> None:
|
||||
with open(in_file, 'r') as file:
|
||||
content = file.read()
|
||||
|
||||
# we replace config decorators to differentiate between local mosquitto based tests
|
||||
pattern = r"@pytest\.mark\.parametrize\(\s*'config'\s*,\s*\[\s*'(.*?)'\s*\]\s*,.*\)"
|
||||
|
||||
def replacement(match):
|
||||
config_value = match.group(1)
|
||||
if config_value == 'local_broker':
|
||||
return '@pytest.mark.test_mosquitto'
|
||||
else:
|
||||
return '@pytest.mark.test_mqtt'
|
||||
|
||||
# Replace occurrences
|
||||
updated_content = re.sub(pattern, replacement, content)
|
||||
|
||||
with open(out_file, 'w') as file:
|
||||
file.write(updated_content)
|
||||
|
||||
|
||||
# Main function to handle arguments
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) != 3:
|
||||
print('Usage: python replace_decorators.py <in_file> <out_file>')
|
||||
sys.exit(1)
|
||||
|
||||
in_file = sys.argv[1]
|
||||
out_file = sys.argv[2]
|
||||
replace_decorators(in_file, out_file)
|
||||
print(f'Replacements completed')
|
@ -3,6 +3,6 @@ commitizen:
|
||||
bump_message: 'bump(sockutls): $current_version -> $new_version'
|
||||
pre_bump_hooks: python ../../ci/changelog.py sock_utils
|
||||
tag_format: sock_utils-v$version
|
||||
version: 0.1.0
|
||||
version: 0.2.2
|
||||
version_files:
|
||||
- idf_component.yml
|
||||
|
@ -1,5 +1,24 @@
|
||||
# Changelog
|
||||
|
||||
## [0.2.2](https://github.com/espressif/esp-protocols/commits/sock_utils-v0.2.2)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix gai_strerror() impl to return const string ([f12a2056](https://github.com/espressif/esp-protocols/commit/f12a2056))
|
||||
|
||||
## [0.2.1](https://github.com/espressif/esp-protocols/commits/sock_utils-v0.2.1)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix potential macro colission including standard headers ([ade9448c](https://github.com/espressif/esp-protocols/commit/ade9448c))
|
||||
|
||||
## [0.2.0](https://github.com/espressif/esp-protocols/commits/sock_utils-v0.2.0)
|
||||
|
||||
### Features
|
||||
|
||||
- Declare socketpair and gai_strerror via standard headers ([b090a3cb](https://github.com/espressif/esp-protocols/commit/b090a3cb))
|
||||
- Add support for gethostname() ([f7c0b756](https://github.com/espressif/esp-protocols/commit/f7c0b756))
|
||||
|
||||
## [0.1.0](https://github.com/espressif/esp-protocols/commits/sock_utils-v0.1.0)
|
||||
|
||||
### Features
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user