esp-idf/examples/protocols/icmp_echo/main/cmd_ping.c
2019-10-22 04:38:09 +00:00

162 lines
5.9 KiB
C

/* Ping command
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include "sdkconfig.h"
#include "esp_log.h"
#include "cmd_ping.h"
#include "argtable3/argtable3.h"
#include "lwip/inet.h"
#include "lwip/netdb.h"
#include "lwip/sockets.h"
#include "esp_console.h"
#include "ping/ping_sock.h"
static void cmd_ping_on_ping_success(esp_ping_handle_t hdl, void *args)
{
uint8_t ttl;
uint16_t seqno;
uint32_t elapsed_time, recv_len;
ip_addr_t target_addr;
esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
esp_ping_get_profile(hdl, ESP_PING_PROF_TTL, &ttl, sizeof(ttl));
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
esp_ping_get_profile(hdl, ESP_PING_PROF_SIZE, &recv_len, sizeof(recv_len));
esp_ping_get_profile(hdl, ESP_PING_PROF_TIMEGAP, &elapsed_time, sizeof(elapsed_time));
printf("%d bytes from %s icmp_seq=%d ttl=%d time=%d ms\n",
recv_len, inet_ntoa(target_addr.u_addr.ip4), seqno, ttl, elapsed_time);
}
static void cmd_ping_on_ping_timeout(esp_ping_handle_t hdl, void *args)
{
uint16_t seqno;
ip_addr_t target_addr;
esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
printf("From %s icmp_seq=%d timeout\n", inet_ntoa(target_addr.u_addr.ip4), seqno);
}
static void cmd_ping_on_ping_end(esp_ping_handle_t hdl, void *args)
{
ip_addr_t target_addr;
uint32_t transmitted;
uint32_t received;
uint32_t total_time_ms;
esp_ping_get_profile(hdl, ESP_PING_PROF_REQUEST, &transmitted, sizeof(transmitted));
esp_ping_get_profile(hdl, ESP_PING_PROF_REPLY, &received, sizeof(received));
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
esp_ping_get_profile(hdl, ESP_PING_PROF_DURATION, &total_time_ms, sizeof(total_time_ms));
uint32_t loss = (uint32_t)((1 - ((float)received) / transmitted) * 100);
if (IP_IS_V4(&target_addr)) {
printf("\n--- %s ping statistics ---\n", inet_ntoa(*ip_2_ip4(&target_addr)));
} else {
printf("\n--- %s ping statistics ---\n", inet6_ntoa(*ip_2_ip6(&target_addr)));
}
printf("%d packets transmitted, %d received, %d%% packet loss, time %dms\n",
transmitted, received, loss, total_time_ms);
// delete the ping sessions, so that we clean up all resources and can create a new ping session
// we don't have to call delete function in the callback, instead we can call delete function from other tasks
esp_ping_delete_session(hdl);
}
static struct {
struct arg_dbl *timeout;
struct arg_dbl *interval;
struct arg_int *data_size;
struct arg_int *count;
struct arg_int *tos;
struct arg_str *host;
struct arg_end *end;
} ping_args;
static int do_ping_cmd(int argc, char **argv)
{
esp_ping_config_t config = ESP_PING_DEFAULT_CONFIG();
int nerrors = arg_parse(argc, argv, (void **)&ping_args);
if (nerrors != 0) {
arg_print_errors(stderr, ping_args.end, argv[0]);
return 1;
}
if (ping_args.timeout->count > 0) {
config.timeout_ms = (uint32_t)(ping_args.timeout->dval[0] * 1000);
}
if (ping_args.interval->count > 0) {
config.interval_ms = (uint32_t)(ping_args.interval->dval[0] * 1000);
}
if (ping_args.data_size->count > 0) {
config.data_size = (uint32_t)(ping_args.data_size->ival[0]);
}
if (ping_args.count->count > 0) {
config.count = (uint32_t)(ping_args.count->ival[0]);
}
if (ping_args.tos->count > 0) {
config.tos = (uint32_t)(ping_args.tos->ival[0]);
}
// parse IP address
ip_addr_t target_addr;
struct addrinfo hint;
struct addrinfo *res = NULL;
memset(&hint, 0, sizeof(hint));
memset(&target_addr, 0, sizeof(target_addr));
/* convert domain name to IP address */
if (getaddrinfo(ping_args.host->sval[0], NULL, &hint, &res) != 0) {
printf("ping: unknown host %s\n", ping_args.host->sval[0]);
return 1;
}
if (res->ai_family == AF_INET) {
struct in_addr addr4 = ((struct sockaddr_in *) (res->ai_addr))->sin_addr;
inet_addr_to_ip4addr(ip_2_ip4(&target_addr), &addr4);
} else {
struct in6_addr addr6 = ((struct sockaddr_in6 *) (res->ai_addr))->sin6_addr;
inet6_addr_to_ip6addr(ip_2_ip6(&target_addr), &addr6);
}
freeaddrinfo(res);
config.target_addr = target_addr;
/* set callback functions */
esp_ping_callbacks_t cbs = {
.on_ping_success = cmd_ping_on_ping_success,
.on_ping_timeout = cmd_ping_on_ping_timeout,
.on_ping_end = cmd_ping_on_ping_end,
.cb_args = NULL
};
esp_ping_handle_t ping;
esp_ping_new_session(&config, &cbs, &ping);
esp_ping_start(ping);
return 0;
}
void register_ping(void)
{
ping_args.timeout = arg_dbl0("W", "timeout", "<t>", "Time to wait for a response, in seconds");
ping_args.interval = arg_dbl0("i", "interval", "<t>", "Wait interval seconds between sending each packet");
ping_args.data_size = arg_int0("s", "size", "<n>", "Specify the number of data bytes to be sent");
ping_args.count = arg_int0("c", "count", "<n>", "Stop after sending count packets");
ping_args.tos = arg_int0("Q", "tos", "<n>", "Set Type of Service related bits in IP datagrams");
ping_args.host = arg_str1(NULL, NULL, "<host>", "Host address");
ping_args.end = arg_end(1);
const esp_console_cmd_t ping_cmd = {
.command = "ping",
.help = "send ICMP ECHO_REQUEST to network hosts",
.hint = NULL,
.func = &do_ping_cmd,
.argtable = &ping_args
};
ESP_ERROR_CHECK(esp_console_cmd_register(&ping_cmd));
}