You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
342 lines
11 KiB
342 lines
11 KiB
2 years ago
|
#include <freertos/FreeRTOS.h>
|
||
|
#include <freertos/event_groups.h>
|
||
|
#include <esp_wifi.h>
|
||
|
#include <settings.h>
|
||
|
#include <lwip/inet.h>
|
||
|
|
||
|
#include "console/cmd_common.h"
|
||
|
#include <console/cmddef.h>
|
||
|
#include <application.h>
|
||
|
#include <common_utils/utils.h>
|
||
|
#include <sntp_cli.h>
|
||
|
#include <ping.h>
|
||
|
#include <lwip/netdb.h>
|
||
|
|
||
|
static int cmd_ip_status(console_ctx_t *ctx, cmd_signature_t *reg)
|
||
|
{
|
||
|
EMPTY_CMD_SETUP("Show IP status");
|
||
|
|
||
|
if (!gSettings.wifi_enabled || !g_State.wifi_inited) {
|
||
|
console_color_printf(COLOR_RED, "WiFi interface is disabled\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
wifi_config_t config;
|
||
|
if (ESP_OK == esp_wifi_get_config(ESP_IF_WIFI_STA, &config)) {
|
||
|
if (config.sta.ssid[0]) {
|
||
|
EventBits_t bits = xEventGroupGetBits(g_wifi_event_group);
|
||
|
if (bits & WIFI_CONNECTED_BIT) {
|
||
|
console_color_printf(COLOR_GREEN, "Connected to SSID \"%s\"\n", config.sta.ssid);
|
||
|
} else if (bits & WIFI_FAIL_BIT) {
|
||
|
console_color_printf(COLOR_RED, "WiFi connection failed.\n");
|
||
|
console_printf("Saved SSID = \"%s\"\n", config.sta.ssid);
|
||
|
return 0;
|
||
|
} else {
|
||
|
console_color_printf(COLOR_RED, "Not connected, retries may be in progress.\n");
|
||
|
console_printf("Saved SSID = \"%s\"\n", config.sta.ssid);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
tcpip_adapter_ip_info_t ipinfo;
|
||
|
if (ESP_OK == tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ipinfo)) {
|
||
|
// ! inet_ntoa uses a global static buffer, cant use multiple in one printf call
|
||
|
console_printf("DHCP: %s\n", gSettings.dhcp_enable ? MSG_ENABLED : MSG_DISABLED " (static IP)");
|
||
|
console_printf("IP: %s\n", inet_ntoa(ipinfo.ip.addr));
|
||
|
console_printf("Mask: %s\n", inet_ntoa(ipinfo.netmask.addr));
|
||
|
console_printf("Gateway: %s\n", inet_ntoa(ipinfo.gw.addr));
|
||
|
|
||
|
if (!gSettings.dhcp_enable) {
|
||
|
console_printf("DNS: %s\n", inet_ntoa(gSettings.static_dns));
|
||
|
}
|
||
|
|
||
|
uint8_t mac[6];
|
||
|
if (ESP_OK == esp_wifi_get_mac(ESP_IF_WIFI_STA, mac)) {
|
||
|
console_printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
|
||
|
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||
|
}
|
||
|
} else {
|
||
|
console_color_printf(COLOR_RED, "No IP address assigned!\n");
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
console_color_printf(COLOR_RED, "SSID not configured!\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int cmd_ip_pingwd(console_ctx_t *ctx, cmd_signature_t *reg)
|
||
|
{
|
||
|
static struct {
|
||
|
struct arg_str *cmd;
|
||
|
struct arg_end *end;
|
||
|
} cmd_args;
|
||
|
|
||
|
if (reg) {
|
||
|
cmd_args.cmd = arg_str0(NULL, NULL, "<cmd>", "Enable or disable. Omit to check current state");
|
||
|
cmd_args.end = arg_end(1);
|
||
|
|
||
|
reg->argtable = &cmd_args;
|
||
|
reg->help = "Enable/disable ping watchdog, or check the current setting. The watchdog periodically pings the gateway and restarts WiFi on failure.";
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (cmd_args.cmd->count) {
|
||
|
int b = parse_boolean_arg(cmd_args.cmd->sval[0]);
|
||
|
if (b < 0) return CONSOLE_ERR_INVALID_ARG;
|
||
|
gSettings.dhcp_wd_enable = b;
|
||
|
settings_persist(SETTINGS_dhcp_wd_enable);
|
||
|
}
|
||
|
|
||
|
console_printf("Ping WD = %s\n", gSettings.dhcp_wd_enable ? MSG_ENABLED : MSG_DISABLED);
|
||
|
|
||
|
if (cmd_args.cmd->count) {
|
||
|
console_printf("Restart to apply changes\n");
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void ping_success_print_cb(int bytes, const char *ip, int seq, int elapsed_ms) {
|
||
|
console_printf("Rx %d bytes from %s: icmp_seq=%d time=%d ms\n", bytes, ip, seq, (int) elapsed_ms);
|
||
|
}
|
||
|
|
||
|
static void ping_fail_print_cb(int seq) {
|
||
|
console_printf("Request timeout for icmp_seq %d\n", seq);
|
||
|
}
|
||
|
|
||
|
static int cmd_ip_ping(console_ctx_t *ctx, cmd_signature_t *reg)
|
||
|
{
|
||
|
static struct {
|
||
|
struct arg_str *ip;
|
||
|
struct arg_int *num;
|
||
|
struct arg_int *timeout;
|
||
|
struct arg_int *interval;
|
||
|
struct arg_int *size;
|
||
|
struct arg_end *end;
|
||
|
} args;
|
||
|
|
||
|
if (reg) {
|
||
|
args.ip = arg_str1(NULL, NULL, "<IP>", "Target IP");
|
||
|
args.num = arg_int0("n", NULL, "<num>", "Ping count (def 1)");
|
||
|
args.timeout = arg_int0("t", NULL, "<ms>", "Timeout (def 3000)");
|
||
|
args.interval = arg_int0("i", NULL, "<ms>", "Interval (def 1000)");
|
||
|
args.size = arg_int0("s", NULL, "<bytes>", "Payload size (def 32)");
|
||
|
args.end = arg_end(5);
|
||
|
|
||
|
reg->argtable = &args;
|
||
|
reg->help = "Ping a host using ICMP";
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
ping_opts_t opts = PING_CONFIG_DEFAULT();
|
||
|
opts.success_cb = ping_success_print_cb;
|
||
|
opts.fail_cb = ping_fail_print_cb;
|
||
|
opts.count = args.num->count ? args.num->ival[0] : 1;
|
||
|
opts.payload_size = args.size->count ? args.size->ival[0] : 32;
|
||
|
opts.interval_ms = args.interval->count ? args.interval->ival[0] : 1000;
|
||
|
opts.timeout_ms = args.timeout->count ? args.timeout->ival[0] : 3000;
|
||
|
|
||
|
if (0 == inet_aton(args.ip->sval[0], &opts.ip_addr)) {
|
||
|
// we could have received a domain name here
|
||
|
struct hostent * ent = gethostbyname(args.ip->sval[0]);
|
||
|
if (!ent) {
|
||
|
console_println("Could not resolve");
|
||
|
return CONSOLE_ERR_IO;
|
||
|
}
|
||
|
|
||
|
memcpy(&opts.ip_addr, ent->h_addr_list[0], sizeof(ip4_addr_t));
|
||
|
console_printf("Resolved as %s\n", inet_ntoa(opts.ip_addr));
|
||
|
}
|
||
|
|
||
|
ping_result_t result = {};
|
||
|
esp_err_t ret = ping(&opts, &result);
|
||
|
|
||
|
if (ret != ESP_OK) {
|
||
|
console_println("Ping error");
|
||
|
return ret;
|
||
|
} else {
|
||
|
console_printf("%d tx, %d rx, %.1f%% loss, latency min %d ms, max %d ms\n",
|
||
|
result.sent,
|
||
|
result.received,
|
||
|
result.loss_pt,
|
||
|
result.min_time_ms,
|
||
|
result.max_time_ms);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int cmd_ip_static_set(console_ctx_t *ctx, cmd_signature_t *reg)
|
||
|
{
|
||
|
static struct {
|
||
|
struct arg_str *ip;
|
||
|
struct arg_str *gw;
|
||
|
struct arg_str *mask;
|
||
|
struct arg_str *dns;
|
||
|
struct arg_str *cmd;
|
||
|
struct arg_end *end;
|
||
|
} args;
|
||
|
|
||
|
if (reg) {
|
||
|
args.ip = arg_str0("a", NULL, "<IP>", "Set IP address");
|
||
|
args.gw = arg_str0("g", NULL, "<GW>", "Set gateway address");
|
||
|
args.mask = arg_str0("n", NULL, "<MASK>", "Set netmask");
|
||
|
args.dns = arg_str0("d", NULL, "<DNS>", "Set DNS server IP");
|
||
|
args.cmd = arg_str0(NULL, NULL, "{enable|disable}", "Enable or disable static IP");
|
||
|
args.end = arg_end(1);
|
||
|
|
||
|
reg->argtable = &args;
|
||
|
reg->help = "Configure, enable/disable, or check config of static IP.";
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
bool any_change = false;
|
||
|
|
||
|
if (args.ip->count) {
|
||
|
uint32_t a = 0;
|
||
|
if (!inet_aton(args.ip->sval[0], &a)) {
|
||
|
console_println("Invalid IP");
|
||
|
return CONSOLE_ERR_INVALID_ARG;
|
||
|
}
|
||
|
gSettings.static_ip = a; // aton output is already in network byte order
|
||
|
settings_persist(SETTINGS_static_ip);
|
||
|
any_change = true;
|
||
|
}
|
||
|
|
||
|
if (args.gw->count) {
|
||
|
uint32_t a = 0;
|
||
|
if (!inet_aton(args.gw->sval[0], &a)) {
|
||
|
console_println("Invalid GW");
|
||
|
return CONSOLE_ERR_INVALID_ARG;
|
||
|
}
|
||
|
gSettings.static_ip_gw = a; // aton output is already in network byte order
|
||
|
settings_persist(SETTINGS_static_ip_gw);
|
||
|
any_change = true;
|
||
|
}
|
||
|
|
||
|
if (args.mask->count) {
|
||
|
uint32_t a = 0;
|
||
|
if (!inet_aton(args.mask->sval[0], &a)) {
|
||
|
console_println("Invalid mask");
|
||
|
return CONSOLE_ERR_INVALID_ARG;
|
||
|
}
|
||
|
gSettings.static_ip_mask = a; // aton output is already in network byte order
|
||
|
settings_persist(SETTINGS_static_ip_mask);
|
||
|
any_change = true;
|
||
|
}
|
||
|
|
||
|
if (args.dns->count) {
|
||
|
uint32_t a = 0;
|
||
|
if (!inet_aton(args.dns->sval[0], &a)) {
|
||
|
console_println("Invalid DNS IP");
|
||
|
return CONSOLE_ERR_INVALID_ARG;
|
||
|
}
|
||
|
gSettings.static_dns = a; // aton output is already in network byte order
|
||
|
settings_persist(SETTINGS_static_dns);
|
||
|
any_change = true;
|
||
|
}
|
||
|
|
||
|
if (args.cmd->count) {
|
||
|
int b = parse_boolean_arg(args.cmd->sval[0]);
|
||
|
if (b < 0) return CONSOLE_ERR_INVALID_ARG;
|
||
|
gSettings.dhcp_enable = !b;
|
||
|
settings_persist(SETTINGS_dhcp_enable);
|
||
|
any_change = true;
|
||
|
}
|
||
|
|
||
|
console_printf("Static IP: %s\n", gSettings.dhcp_enable ? MSG_DISABLED : MSG_ENABLED);
|
||
|
console_printf("- IP: %s\n", inet_ntoa(gSettings.static_ip));
|
||
|
console_printf("- Mask: %s\n", inet_ntoa(gSettings.static_ip_mask));
|
||
|
console_printf("- Gateway: %s\n", inet_ntoa(gSettings.static_ip_gw));
|
||
|
console_printf("- DNS: %s\n", inet_ntoa(gSettings.static_dns));
|
||
|
|
||
|
if (any_change) {
|
||
|
console_println("Restart to apply changes.");
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int cmd_ip_ntp(console_ctx_t *ctx, cmd_signature_t *reg)
|
||
|
{
|
||
|
static struct {
|
||
|
struct arg_str *cmd;
|
||
|
struct arg_str *addr;
|
||
|
struct arg_end *end;
|
||
|
} cmd_args;
|
||
|
|
||
|
if (reg) {
|
||
|
cmd_args.cmd = arg_str0(NULL, NULL, "<cmd>", "Enable or disable autostart. Omit to check current state. start = start now");
|
||
|
cmd_args.addr = arg_str0("s", NULL, "<server>", "Set NTP server");
|
||
|
cmd_args.end = arg_end(2);
|
||
|
|
||
|
reg->argtable = &cmd_args;
|
||
|
reg->help = "Check or modify NTP client setting, or start it manually.";
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (cmd_args.addr->count) {
|
||
|
strncpy(gSettings.ntp_srv, cmd_args.addr->sval[0], NTP_SRV_LEN);
|
||
|
gSettings.ntp_srv[NTP_SRV_LEN - 1] = 0;
|
||
|
settings_persist(SETTINGS_ntp_srv);
|
||
|
console_printf("NTP server set to %s\n", gSettings.ntp_srv);
|
||
|
}
|
||
|
|
||
|
if (cmd_args.cmd->count) {
|
||
|
if (streq(cmd_args.cmd->sval[0], "start")) {
|
||
|
bool started = sntp_cli_start();
|
||
|
if (started) {
|
||
|
console_printf("NTP client started manually.\n");
|
||
|
} else {
|
||
|
console_color_printf(COLOR_RED, "Start failed. Client may be already running.\n");
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int b = parse_boolean_arg(cmd_args.cmd->sval[0]);
|
||
|
if (b < 0) return CONSOLE_ERR_INVALID_ARG;
|
||
|
gSettings.ntp_enable = b;
|
||
|
|
||
|
settings_persist(SETTINGS_ntp_enable);
|
||
|
}
|
||
|
|
||
|
console_printf("Client status: %s\n", gSettings.ntp_enable ? MSG_ENABLED : MSG_DISABLED);
|
||
|
console_printf("NTP server: %s\n", gSettings.ntp_srv);
|
||
|
|
||
|
/* show the current date */
|
||
|
time_t now;
|
||
|
struct tm timeinfo;
|
||
|
time(&now);
|
||
|
localtime_r(&now, &timeinfo);
|
||
|
|
||
|
if(timeinfo.tm_year < (2016 - 1900)) {
|
||
|
console_printf("Device time is not valid.\n");
|
||
|
} else {
|
||
|
char strftime_buf[64];
|
||
|
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
|
||
|
console_printf("The current UTC date/time is: %s\n", strftime_buf);
|
||
|
}
|
||
|
|
||
|
if (cmd_args.cmd->count) {
|
||
|
// if it was "start", we returned early.
|
||
|
console_printf("Restart to apply changes\n");
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void register_cmd_ip(void)
|
||
|
{
|
||
|
console_group_add("ip", "IP status and settings");
|
||
|
console_cmd_register(cmd_ip_status, "ip status");
|
||
|
console_cmd_register(cmd_ip_pingwd, "ip wd");
|
||
|
console_cmd_register(cmd_ip_ntp, "ip ntp");
|
||
|
console_cmd_register(cmd_ip_ping, "ip ping");
|
||
|
console_cmd_register(cmd_ip_static_set, "ip static");
|
||
|
|
||
|
// this may be used for shortcuts like "ip in"
|
||
|
console_cmd_add_alias_fn(cmd_ip_status, "ip info");
|
||
|
}
|