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

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");
}