mirror of
https://github.com/espressif/esp-protocols.git
synced 2025-07-03 13:46:33 +02:00
Compare commits
22 Commits
console_cm
...
sock_utils
Author | SHA1 | Date | |
---|---|---|---|
9c11003449 | |||
85a7fc772c | |||
b090a3cb69 | |||
42cde46c97 | |||
beb6e57e5e | |||
15d3a01e11 | |||
e12ecb8e89 | |||
54271a1b96 | |||
886215032f | |||
269351f41c | |||
5e929902c7 | |||
f7c0b7564a | |||
c989c6adae | |||
18f196fa1e | |||
1db83cd1ca | |||
247f1681e8 | |||
32387f7e39 | |||
dbc3ea6809 | |||
8b6ea3311a | |||
8e55b93b59 | |||
0cb59ff80d | |||
1284f66d58 |
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
|
||||
|
9
.github/workflows/modem__target-test.yml
vendored
9
.github/workflows/modem__target-test.yml
vendored
@ -80,7 +80,12 @@ jobs:
|
||||
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 }}
|
||||
|
@ -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
|
||||
|
@ -122,12 +122,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;
|
||||
|
@ -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.0
|
||||
version_files:
|
||||
- idf_component.yml
|
||||
|
@ -1,5 +1,12 @@
|
||||
# Changelog
|
||||
|
||||
## [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
|
||||
|
@ -2,5 +2,15 @@ idf_component_register(SRCS "src/getnameinfo.c"
|
||||
"src/ifaddrs.c"
|
||||
"src/gai_strerror.c"
|
||||
"src/socketpair.c"
|
||||
"src/gethostname.c"
|
||||
INCLUDE_DIRS "include"
|
||||
PRIV_REQUIRES lwip esp_netif)
|
||||
|
||||
# To support declarations from standard headers in lwip component
|
||||
# - socket pair from lwip/sockets.h
|
||||
# - gai_strerror from lwip/netdb.h
|
||||
# also need to make lwip depend on the sock_utils lib
|
||||
idf_component_get_property(lwip lwip COMPONENT_LIB)
|
||||
target_compile_definitions(${lwip} PUBLIC LWIP_SOCKET_HAS_SOCKETPAIR=1)
|
||||
target_compile_definitions(${lwip} PUBLIC LWIP_NETDB_HAS_GAI_STRERROR=1)
|
||||
target_link_libraries(${lwip} PUBLIC ${COMPONENT_LIB})
|
||||
|
@ -6,12 +6,17 @@ This component provides simplified implementations of common socket-related util
|
||||
## Supported Functions
|
||||
|
||||
|
||||
| API | Description | Limitations |
|
||||
|------------------|-------------------------------------------------------------|-------------------------------------------------------------------|
|
||||
| `ifaddrs()` | Retrieves interface addresses using `esp_netif` | IPv4 addresses only |
|
||||
| `socketpair()` | Creates a pair of connected sockets using `lwIP` loopback stream sockets | IPv4 sockets only |
|
||||
| `pipe()` | Wraps `socketpair()` to provide unidirectional pipe-like functionality | Uses bidirectional sockets in place of true pipes |
|
||||
| `getnameinfo()` | Converts IP addresses to human-readable form using `lwIP`'s `inet_ntop()` | IPv4 only; supports `NI_NUMERICHOST` and `NI_NUMERICSERV` flags only |
|
||||
| `gai_strerror()` | Returns error code as a string | Simple numeric string representation only |
|
||||
| API | Description | Limitations | Declared in |
|
||||
|--------------------|-------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------|
|
||||
| `ifaddrs()` | Retrieves interface addresses using `esp_netif` | IPv4 addresses only | `ifaddrs.h` |
|
||||
| `socketpair()` *) | Creates a pair of connected sockets using `lwIP` loopback stream sockets | IPv4 sockets only | `socketpair.h`, `sys/socket.h` **) |
|
||||
| `pipe()` *) | Wraps `socketpair()` to provide unidirectional pipe-like functionality | Uses bidirectional sockets in place of true pipes | `socketpair.h`, `unistd.h` ***) |
|
||||
| `getnameinfo()` | Converts IP addresses to human-readable form using `lwIP`'s `inet_ntop()` | IPv4 only; supports `NI_NUMERICHOST` and `NI_NUMERICSERV` flags only | `getnameinfo.h`, `netdb.h` in ESP-IDF |
|
||||
| `gai_strerror()` | Returns error code as a string | Simple numeric string representation only | `gai_strerror.h`, `netdb.h` **) |
|
||||
| `gethostname()` | Returns lwip netif hostname | Not a system-wide hostname, but interface specific hostname | `gethostname.h`, `unistd.h` in ESP-IDF |
|
||||
|
||||
**Note**: `socketpair()` and `pipe()` are built on top of `lwIP` TCP sockets, inheriting the same characteristics. For instance, the maximum transmit buffer size is based on the `TCP_SND_BUF` setting.
|
||||
**Notes**:
|
||||
|
||||
- **`*)`** `socketpair()` and `pipe()` are built on top of `lwIP` TCP sockets, inheriting the same characteristics. For instance, the maximum transmit buffer size is based on the `TCP_SND_BUF` setting.
|
||||
- **`**)`** `socketpair()` and `gai_strerror()` are declared in sock_utils header files, the declaration is propagated to ESP-IDF from v5.5 to the official header files. If you're using older IDF version, you need to manually pre-include related header files from the sock_utils public include directory.
|
||||
- **`***)`** `pipe()` is declared in compiler's `sys/unistd.h`.
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: 0.1.0
|
||||
version: 0.2.0
|
||||
description: The component provides helper implementation of common system/socket utilities
|
||||
url: https://github.com/espressif/esp-protocols/tree/master/components/sock_utils
|
||||
dependencies:
|
||||
|
51
components/sock_utils/include/gethostname.h
Normal file
51
components/sock_utils/include/gethostname.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <unistd.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_LINUX
|
||||
// namespace with esp_ on linux to avoid conflict of symbols
|
||||
#define gethostname esp_gethostname
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Retrieves the hostname of the device.
|
||||
*
|
||||
* This function provides the hostname associated with the network interface.
|
||||
* Unlike the standard behavior where the hostname represents a system-wide name,
|
||||
* this implementation returns lwip netif hostname (used as a hostname in DHCP packets)
|
||||
*
|
||||
* @param[out] name A pointer to a buffer where the hostname will be stored.
|
||||
* The buffer must be allocated by the caller.
|
||||
* @param[in] len The size of the buffer pointed to by @p name. The hostname,
|
||||
* including the null-terminator, must fit within this size.
|
||||
*
|
||||
* @return
|
||||
* - 0 on success
|
||||
* - -1 on error, with `errno` set to indicate the error:
|
||||
* - `EINVAL`: Invalid argument, name is NULL, or hostname is too long
|
||||
*
|
||||
* @note This implementation retrieves the hostname associated with the network
|
||||
* interface using the `esp_netif_get_hostname()` function, which in turn
|
||||
* returns lwip netif hostname used in DHCP packets if LWIP_NETIF_HOSTNAME=1 (hardcoded)
|
||||
* in ESP-IDF lwip port.
|
||||
* As there could be multiple network interfaces in the system, the logic tries
|
||||
* to find the default (active) netif first, then it looks for any (inactive) netif
|
||||
* with highest route priority. If none of the above found or esp_netif_get_hostname() fails
|
||||
* for the selected interface, this API returns the default value of `CONFIG_LWIP_LOCAL_HOSTNAME`,
|
||||
* the local hostname from lwip component configuration menu.
|
||||
*/
|
||||
int gethostname(char *name, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -32,3 +32,10 @@
|
||||
#ifndef AF_UNIX
|
||||
#define AF_UNIX 1
|
||||
#endif
|
||||
|
||||
#ifndef PF_LOCAL
|
||||
/*
|
||||
* In POSIX, AF_UNIX and PF_LOCAL are essentially synonymous.
|
||||
*/
|
||||
#define PF_LOCAL AF_UNIX
|
||||
#endif
|
||||
|
46
components/sock_utils/src/gethostname.c
Normal file
46
components/sock_utils/src/gethostname.c
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <string.h>
|
||||
#include "gethostname.h"
|
||||
#include "esp_netif.h"
|
||||
#include "errno.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
|
||||
static bool highest_prio_netif(esp_netif_t *netif, void *ctx)
|
||||
{
|
||||
esp_netif_t **highest_so_far = ctx;
|
||||
if (esp_netif_get_route_prio(netif) > esp_netif_get_route_prio(*highest_so_far)) {
|
||||
*highest_so_far = netif;
|
||||
}
|
||||
return false; // go over the entire list to find the netif with the highest route-prio
|
||||
}
|
||||
|
||||
int gethostname(char *name, size_t len)
|
||||
{
|
||||
if (name == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
const char *netif_hostname = CONFIG_LWIP_LOCAL_HOSTNAME; // default value from Kconfig
|
||||
|
||||
// Find the default netif
|
||||
esp_netif_t *default_netif = esp_netif_get_default_netif();
|
||||
if (default_netif == NULL) { // if no netif is active/up -> find the highest prio netif
|
||||
esp_netif_find_if(highest_prio_netif, &default_netif);
|
||||
}
|
||||
// now the `default_netif` could be NULL and/or the esp_netif_get_hostname() could fail
|
||||
// but we ignore the return code, as if it fails, the `netif_hostname` still holds the default value
|
||||
esp_netif_get_hostname(default_netif, &netif_hostname);
|
||||
|
||||
size_t hostname_len;
|
||||
if (netif_hostname == NULL || len < (hostname_len = strlen(netif_hostname) + 1)) { // including the NULL terminator
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
memcpy(name, netif_hostname, hostname_len);
|
||||
return 0;
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "gethostname.h"
|
||||
#include "ifaddrs.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_event.h"
|
||||
@ -148,6 +149,30 @@ TEST_CASE("gai_strerror()", "[sock_utils]")
|
||||
CHECK(str_error != NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("gethostname()", "[sock_utils]")
|
||||
{
|
||||
const char *test_netif_name = "station";
|
||||
char hostname[32];
|
||||
int ret;
|
||||
|
||||
// expect failure
|
||||
ret = gethostname(hostname, strlen(CONFIG_LWIP_LOCAL_HOSTNAME) - 1);
|
||||
CHECK(ret == -1);
|
||||
|
||||
// happy flow with the default name
|
||||
ret = gethostname(hostname, sizeof(hostname));
|
||||
CHECK(ret == 0);
|
||||
CHECK(strcmp(hostname, CONFIG_LWIP_LOCAL_HOSTNAME) == 0);
|
||||
|
||||
// happy flow with the netif name
|
||||
esp_netif_t *esp_netif = create_test_netif(test_netif_name, 1);
|
||||
REQUIRE(esp_netif != NULL);
|
||||
CHECK(esp_netif_set_hostname(esp_netif, test_netif_name) == ESP_OK);
|
||||
ret = gethostname(hostname, sizeof(hostname));
|
||||
CHECK(ret == 0);
|
||||
CHECK(strcmp(hostname, test_netif_name) == 0);
|
||||
esp_netif_destroy(esp_netif);
|
||||
}
|
||||
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
|
Reference in New Issue
Block a user