Skip to content

Commit 5332ceb

Browse files
authored
feat(ping): Add ping component (#525)
* feat(ping): Add ping component * fix sa / comments * fix seqno * Refactor some * readme: update * cleanup includes / requirements * move simple after cli to allow running on fresh hardware * minor fix
1 parent 143f589 commit 5332ceb

File tree

18 files changed

+1076
-2
lines changed

18 files changed

+1076
-2
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ jobs:
149149
target: esp32
150150
- path: 'components/pid/example'
151151
target: esp32
152+
- path: 'components/ping/example'
153+
target: esp32s3
152154
- path: 'components/qmi8658/example'
153155
target: esp32s3
154156
- path: 'components/qtpy/example'

.github/workflows/upload_components.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ jobs:
9595
components/odrive_ascii
9696
components/pi4ioe5v
9797
components/pid
98+
components/ping
9899
components/pcf85063
99100
components/qmi8658
100101
components/qtpy

components/ping/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
idf_component_register(
2+
INCLUDE_DIRS "include"
3+
SRC_DIRS "src"
4+
REQUIRES "base_component" "cli" "lwip"
5+
)

components/ping/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Ping Component
2+
[![Badge](https://components.espressif.com/components/espp/ping/badge.svg)](https://components.espressif.com/components/espp/ping)
3+
4+
A C++ wrapper around `esp_ping` providing a functional callback interface and an optional CLI menu.
5+
6+
- Simple config with target host, count, interval, timeout, data size, TTL
7+
- std::function callbacks for session start, per-reply, timeout, and end
8+
- CLI submenu for quick testing and integration alongside other menus
9+
10+
## Example
11+
12+
The [./example](./example) directory contains a simple example demonstrating the
13+
use of the `Ping` component and how it can be used with a CLI menu.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
cmake_minimum_required(VERSION 3.20)
2+
3+
set(ENV{IDF_COMPONENT_MANAGER} "0")
4+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
5+
6+
set(EXTRA_COMPONENT_DIRS
7+
"../../../components/"
8+
)
9+
10+
set(
11+
COMPONENTS
12+
"main esptool_py cli ping wifi"
13+
CACHE STRING
14+
"List of components to include"
15+
)
16+
17+
project(ping_example)
18+
19+
set(CMAKE_CXX_STANDARD 20)

components/ping/example/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Ping Example
2+
3+
This example demonstrates using the `Ping` component to run `esp_ping` with a simple CLI menu.
4+
5+
Run the app, then use serial CLI:
6+
- `sta ...` to bring up WiFi (see WiFi STA menu), e.g. `sta connect <ssid> <password>`
7+
- `ping` to enter the `ping` submenu to start/stop pinging a target IP address
8+
- `ping google.com`, or `ping 127.0.0.1` for example
9+
10+
## How to use example
11+
12+
### Hardware Required
13+
14+
This example should run on any espressif development board as it requires no
15+
peripheral connections.
16+
17+
### Build and Flash
18+
19+
Build the project and flash it to the board, then run monitor tool to view serial output:
20+
21+
```
22+
idf.py -p PORT flash monitor
23+
```
24+
25+
(Replace PORT with the name of the serial port to use.)
26+
27+
(To exit the serial monitor, type ``Ctrl-]``.)
28+
29+
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
30+
31+
## Example Output
32+
33+
<img width="708" height="1603" alt="CleanShot 2025-09-26 at 15 18 36" src="https://github.com/user-attachments/assets/47f6701b-c231-40b2-ae64-33601a7eaa5c" />
34+
<img width="594" height="872" alt="CleanShot 2025-09-26 at 15 23 24" src="https://github.com/user-attachments/assets/9c45e505-6b06-4f14-a64e-3c6f2c8fe5af" />
35+
<img width="639" height="275" alt="CleanShot 2025-09-26 at 15 24 20" src="https://github.com/user-attachments/assets/ea30e6ab-dc68-4031-a282-d6d8fb601fb7" />
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
idf_component_register(SRC_DIRS "."
2+
INCLUDE_DIRS ".")
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#include <sdkconfig.h>
2+
#include <string>
3+
4+
#include "cli.hpp"
5+
#include "ping.hpp"
6+
#include "wifi_sta.hpp"
7+
#include "wifi_sta_menu.hpp"
8+
9+
extern "C" void app_main(void) {
10+
espp::Logger logger({.tag = "ping_example", .level = espp::Logger::Verbosity::INFO});
11+
logger.info("Starting Ping example...");
12+
13+
#if CONFIG_ESP32_WIFI_NVS_ENABLED
14+
// Initialize NVS
15+
esp_err_t ret = nvs_flash_init();
16+
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
17+
ESP_ERROR_CHECK(nvs_flash_erase());
18+
ret = nvs_flash_init();
19+
}
20+
ESP_ERROR_CHECK(ret);
21+
#endif
22+
23+
{
24+
//! [ping_cli_example]
25+
// Simple WiFi STA bring-up assumed configured via menu
26+
espp::WifiSta wifi_sta({.ssid = "",
27+
.password = "",
28+
.num_connect_retries = 5,
29+
.on_connected = nullptr,
30+
.on_disconnected = nullptr,
31+
.on_got_ip =
32+
[&](ip_event_got_ip_t *eventdata) {
33+
logger.info("got IP: {}.{}.{}.{}",
34+
IP2STR(&eventdata->ip_info.ip));
35+
},
36+
.log_level = espp::Logger::Verbosity::INFO});
37+
// create the wifi menu to allow connecting to APs
38+
espp::WifiStaMenu wifi_menu(wifi_sta);
39+
40+
// create the ping instance and menu
41+
espp::Ping ping({.session =
42+
{
43+
.target_host = "1.1.1.1",
44+
.task_stack_size = 8192,
45+
},
46+
.callbacks = {
47+
.on_session_start = [&]() { logger.info("Ping session started"); },
48+
.on_reply =
49+
[&](uint32_t seq, uint32_t ttl, uint32_t time_ms, uint32_t bytes) {
50+
logger.info("Reply: seq={} ttl={} time={}ms bytes={}", seq, ttl,
51+
time_ms, bytes);
52+
},
53+
.on_timeout = [&]() { logger.warn("Request timed out"); },
54+
.on_end =
55+
[&](const espp::Ping::Stats &stats) {
56+
logger.info("Ping session ended: {}", stats);
57+
},
58+
},
59+
.log_level = espp::Logger::Verbosity::DEBUG});
60+
espp::Ping::Menu ping_menu(ping);
61+
62+
auto root = std::make_unique<cli::Menu>("root", "root menu");
63+
root->Insert(wifi_menu.get());
64+
root->Insert(ping_menu.get());
65+
66+
cli::Cli cli(std::move(root));
67+
cli::SetColor();
68+
cli.ExitAction([](auto &out) { out << "Goodbye and thanks for all the fish.\n"; });
69+
70+
espp::Cli input(cli);
71+
input.SetInputHistorySize(10);
72+
input.Start();
73+
//! [ping_cli_example]
74+
}
75+
76+
// run the simple example after the CLI so that the user can set the
77+
// SSID/password, which will allow the second wifi_sta to auto-connect, since
78+
// it will use the stored config in NVS
79+
{
80+
//! [ping_simple_example]
81+
std::atomic<bool> got_ip{false};
82+
// Simple WiFi STA bring-up assumed configured via menu
83+
espp::WifiSta wifi_sta({.ssid = "",
84+
.password = "",
85+
.num_connect_retries = 5,
86+
.on_connected = nullptr,
87+
.on_disconnected = nullptr,
88+
.on_got_ip =
89+
[&](ip_event_got_ip_t *eventdata) {
90+
logger.info("got IP: {}.{}.{}.{}",
91+
IP2STR(&eventdata->ip_info.ip));
92+
got_ip = true;
93+
},
94+
.log_level = espp::Logger::Verbosity::INFO});
95+
// create the ping instance
96+
espp::Ping ping({.session =
97+
{
98+
.target_host = "google.com",
99+
},
100+
.callbacks = {
101+
.on_session_start = [&]() { logger.info("Ping session started"); },
102+
.on_reply =
103+
[&](uint32_t seq, uint32_t ttl, uint32_t time_ms, uint32_t bytes) {
104+
logger.info("Reply: seq={} ttl={} time={}ms bytes={}", seq, ttl,
105+
time_ms, bytes);
106+
},
107+
.on_timeout = [&]() { logger.warn("Request timed out"); },
108+
.on_end =
109+
[&](const espp::Ping::Stats &stats) {
110+
logger.info("Ping session ended: {}", stats);
111+
},
112+
},
113+
.log_level = espp::Logger::Verbosity::DEBUG});
114+
// wait for wifi connection
115+
while (!got_ip) {
116+
std::this_thread::sleep_for(std::chrono::milliseconds(100));
117+
}
118+
// run the ping session (synchronously)
119+
std::error_code ec;
120+
if (!ping.run(ec)) {
121+
logger.error("Ping failed to start: {}", ec.message());
122+
}
123+
//! [ping_simple_example]
124+
}
125+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# ESP-IDF Partition Table
2+
# Name, Type, SubType, Offset, Size, Flags
3+
nvs, data, nvs, 0x9000, 0x6000,
4+
phy_init, data, phy, 0xf000, 0x1000,
5+
factory, app, factory, 0x10000, 1800K,
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# CONFIG_ESP32_WIFI_NVS_ENABLED=n
2+
3+
CONFIG_PARTITION_TABLE_CUSTOM=y
4+
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
5+
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
6+
CONFIG_PARTITION_TABLE_OFFSET=0x8000
7+
CONFIG_PARTITION_TABLE_MD5=y
8+
9+
# Common ESP-related
10+
#
11+
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=4096
12+
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192

0 commit comments

Comments
 (0)