Przeglądaj źródła

esp32: dump config on USB serial port; add mDNS support; Arduino 2.0.6

- Make ESP32 dump the configuration onto the USB console port. Should
  still improve the handling of log messages so they go to both ports.

- Add mDNS support to find the host on the network.

- Update the source to be compatible with Arduino ESP32 2.0.6.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
H. Peter Anvin 2 lat temu
rodzic
commit
12f13c26f3

+ 2 - 1
esp32/max80/boardinfo.c

@@ -74,7 +74,8 @@ int board_info_init(void)
 
 bad:
     if (!memcmp(board_info_flash->b, "MAX80 ", 6) &&
-	strnlen(board_info_flash->b, sizeof board_info.version_str)
+	strnlen((const char *)board_info_flash->b,
+		sizeof board_info.version_str)
 	< sizeof board_info.version_str) {
 	/*
 	 * Contains board version string but nothing else; this

+ 7 - 0
esp32/max80/common.h

@@ -87,3 +87,10 @@ extern_c volatile bool time_net_sync_status;
 struct timeval;
 extern_c void time_net_sync(const struct timeval *tv);
 extern_c void print_time(const char *msg, const struct timeval *tv);
+
+/*
+ * Log output
+ */
+extern_c volatile bool do_log_config_status;
+extern_c void __fmt_printf(2,3)
+  logmsg(const char *module, const char *fmt, ...);

+ 36 - 3
esp32/max80/config.c

@@ -14,6 +14,7 @@ static const struct env_var default_config[] = {
     {"TZ", "CET-1CEST,M3.5.0,M10.5.0/3"}, /* Sweden */
     {"tzname", "Europe/Stockholm"},
     {"hostname", "max80"},
+    {"mdns.enabled", "1"},
     {"sntp.enabled", "1"},
     {"sntp.server","time.max80.abc80.org"},
     {"abc.hosttype","auto"}
@@ -34,16 +35,23 @@ int setenv_config(const char *name, const char *value)
 
 int setenv_cond(const char *name, const char *value)
 {
+    const char *pfx;
+
+    if (!strncmp("status.", name, 7))
+	pfx = "STAT";
+    else
+	pfx = "CONF";
+
     if (value) {
-	printf("env: %s=%s\n", name, value);
+	logmsg(pfx, "%s: %s\n", name, value);
 	return setenv(name, value, 1);
     } else {
-	printf("env: %s undefined\n", name);
+	logmsg(pfx, "%s: <deleted>\n", name);
 	return unsetenv(name);
     }
 }
 
-static int reset_config(void)
+static void reset_config(void)
 {
     while (1) {
 	char **envp;
@@ -306,3 +314,28 @@ void setenv_bool(const char *var, bool val)
 {
     return setenv_ul(var, val);
 }
+
+const char *getenv_notempty(const char *env)
+{
+    const char *str = getenv(env);
+    if (str && !*str)
+	str = NULL;
+    return str;
+}
+
+void log_config_status(void)
+{
+    const char *pfx;
+    size_t skip;
+
+    for (char **var = environ; *var; var++) {
+	if (!strncmp(*var, "status.", 7)) {
+	    pfx = "STAT";
+	    skip = 7;
+	} else {
+	    pfx = "CONF";
+	    skip = 0;
+	}
+	logmsg(pfx, "%s\n", *var+skip);
+    }
+}

+ 2 - 0
esp32/max80/config.h

@@ -21,3 +21,5 @@ extern_c unsigned long getenv_ul(const char *var, unsigned long def);
 extern_c void setenv_ul(const char *var, unsigned long val);
 extern_c bool getenv_bool(const char *var);
 extern_c void setenv_bool(const char *var, bool val);
+extern_c const char *getenv_notempty(const char *var);
+extern_c void log_config_status(void);

+ 0 - 1
esp32/max80/esplink.c

@@ -89,7 +89,6 @@ void esplink_start(const struct esplink_head *head)
 {
     struct fpga_iov iov[4];
     static unsigned int gen_count;
-    static bool started = false;
 
     xSemaphoreTake(elink.mutex, portMAX_DELAY);
 

+ 0 - 1
esp32/max80/fpgajtag.c

@@ -233,6 +233,5 @@ int fpga_reset(void)
     tap_run_test_idle(JTAG_FPGA_MS);
 
     /* Common finish */
-fail:
     return fpga_finish(err);
 }

+ 2 - 5
esp32/max80/fpgasvc.c

@@ -140,8 +140,6 @@ void fpga_service_enable(bool on)
 
 esp_err_t fpga_service_init(void)
 {
-    esp_err_t err;
-
     pinMode(PIN_FPGA_INT, INPUT);
 
     setenv_bool("status.max80.fpga", false);
@@ -560,8 +558,6 @@ static void fpga_ota_update(void)
 static void fpga_service_task(void *dummy)
 {
     (void)dummy;
-    uint32_t status;
-    bool fpga_initialized = false;
     enum fpga_state {
 	FPGA_DISABLED,		/* FPGA services disabled */
 	FPGA_OFFLINE,		/* FPGA services enabled, waiting for FPGA */
@@ -571,7 +567,8 @@ static void fpga_service_task(void *dummy)
     fputs("[FPGA] Starting FPGA services task\n", stdout);
 
     while (1) {
-	uint32_t notifiers, status;
+	uint32_t notifiers = 0;
+	uint32_t status;
 
 	switch (fpga_state) {
 	case FPGA_DISABLED:

+ 0 - 4
esp32/max80/fwupdate.c

@@ -470,7 +470,6 @@ const char *firmware_errstr(int err)
 static TaskHandle_t fwupdate_task;
 static spz_stream *fwupdate_spz;
 static SemaphoreHandle_t fwupdate_done;
-static int fwupdate_err;
 static bool do_reboot;
 
 static void firmware_update_task(void *pvt)
@@ -543,9 +542,6 @@ static int firmware_update_cleanup(void)
 
 int firmware_update_start(read_func_t read_data, token_t token, bool autoreboot)
 {
-    int err;
-    SemaphoreHandle_t done = NULL;
-
     do_reboot = autoreboot;
 
     if (fwupdate_spz)

+ 5 - 4
esp32/max80/httpd.c

@@ -286,10 +286,12 @@ static esp_err_t httpd_err_enoent(httpd_req_t *req)
     return HTTP_ERR(req, 404, "URI not found");
 }
 
+#if 0
 static esp_err_t httpd_send_ok(httpd_req_t *req)
 {
     return HTTP_ERR(req, 200, "OK");
 }
+#endif
 
 static esp_err_t httpd_err_enomem(httpd_req_t *req)
 {
@@ -353,7 +355,6 @@ static esp_err_t httpd_firmware_update(httpd_req_t *req)
 static esp_err_t httpd_set_config(httpd_req_t *req, const char *query)
 {
     FILE *f;
-    size_t qlen;
 
     int rv1 = 0;
     if (query) {
@@ -498,7 +499,7 @@ static void httpd_get_status_extra(FILE *f, httpd_req_t *req)
     gettimeofday(&tv,NULL);
     const struct tm *tm = localtime(&tv.tv_sec);
     len = strftime(timebuf, sizeof timebuf, "localtime=%Y-%m-%d %H:%M:%S.", tm);
-    snprintf(timebuf+len, sizeof timebuf - len, "%06u",
+    snprintf(timebuf+len, sizeof timebuf - len, "%06lu",
 	     (unsigned long)tv.tv_usec);
     len += 3;
     len += strftime(timebuf+len, sizeof timebuf - len, " %z (%Z)\n", tm);
@@ -802,7 +803,7 @@ static esp_err_t httpd_static_handler(httpd_req_t *req)
      * is strong enough to quality for a "strong" ETag
      */
     char etag[16+3+1];
-    snprintf(etag, sizeof etag, "\"%08x:%08x\"",
+    snprintf(etag, sizeof etag, "\"%08lx:%08lx\"",
 	     fileinfo.dosDate, fileinfo.crc);
 
     bool skip_body = req->method == HTTP_HEAD || !fileinfo.uncompressed_size;
@@ -831,7 +832,7 @@ static esp_err_t httpd_static_handler(httpd_req_t *req)
 
 	len += snprintf(buffer + len, buffer_size-2 - len,
 			"Content-Type: %s%s\r\n"
-			"Content-Length: %u\r\n"
+			"Content-Length: %lu\r\n"
 			"Allow: GET, HEAD\r\n"
 			"Connection: close\r\n"
 			"Last-Modified: %s\r\n",

+ 0 - 3
esp32/max80/jtag_esp32.c

@@ -354,7 +354,6 @@ static int jtag_do_chunk(void)
     spi_dev_t * const hw = jtag.spi->dev;
     unsigned int bits;
     unsigned int tdo_bits_read;
-    unsigned int words;
     unsigned int i;
     const uint32_t *tdi = jtag.tdi;
     uint32_t *tdo = jtag.tdo;
@@ -549,8 +548,6 @@ static inline void jtag_pulse_sleep(void)
 
 uint32_t jtag_pulse(unsigned int bits, uint32_t tdi, uint32_t tms)
 {
-    unsigned int i;
-    uint32_t gpio_in;
     uint32_t tdo = 0;
     uint32_t bit_val;
 

+ 7 - 0
esp32/max80/max80.ino

@@ -156,6 +156,8 @@ static void dump_tasks(void)
     }
 }
 
+volatile bool do_log_config_status;
+
 void loop() {
     if (0) {
 	printf("loop task: %s\n", pcTaskGetName(xTaskGetCurrentTaskHandle()));
@@ -165,6 +167,11 @@ void loop() {
 	putchar('\n');
     }
 
+    if (do_log_config_status) {
+	do_log_config_status = false;
+	log_config_status();
+    }
+
     TTY::ping();
     vTaskDelay(5 * configTICK_RATE_HZ);
 }

+ 0 - 1
esp32/max80/spiflash.c

@@ -177,7 +177,6 @@ static int spiflash_read(uint32_t addr, void *buffer, size_t len)
 
 static int spiflash_write_enable(void)
 {
-    uint8_t sr1;
     int rv;
 
     rv = spiflash_wait_status(1, 0);

+ 0 - 1
esp32/max80/time.c

@@ -6,7 +6,6 @@ void print_time(const char *msg, const struct timeval *tv)
 {
     const struct tm *tm = localtime(&tv->tv_sec);
     char tb1[48], tb2[16];
-    size_t len;
 
     strftime(tb1, sizeof tb1, "%a %Y-%m-%d %H:%M:%S", tm);
     strftime(tb2, sizeof tb2, "%z (%Z)", tm);

+ 34 - 3
esp32/max80/tty.cpp

@@ -357,6 +357,7 @@ void TTY::_onrx()
 
 void TTY::_onconnect()
 {
+    do_log_config_status = true;
     port().write(XON);
 }
 
@@ -370,7 +371,10 @@ void TTY::_ondisconnect()
     reset();
 }
 
-static TTY *usb_tty;
+static TTY *ttys[2];
+#define uart_tty (ttys[0])
+#define usb_tty  (ttys[1])
+
 static TaskHandle_t usb_tty_task;
 
 #define USB_NOTIFY_INDEX     0   /* Seems to be the only available... */
@@ -420,8 +424,6 @@ static void usb_flush()
     Serial.flush();
 }
 
-static TTY *uart_tty;
-
 void TTY::uart_onrx(void)
 {
     uart_tty->_onrx();
@@ -466,3 +468,32 @@ void TTY::init()
 void TTY::ping()
 {
 }
+
+void logmsg(const char *module, const char *fmt, ...)
+{
+    char buf[128];
+    int len = 0;
+    va_list ap;
+
+    if (module)
+	len = snprintf(buf, sizeof buf-1, "%-7s : ", module);
+
+    va_start(ap, fmt);
+    len += vsnprintf(buf+len, sizeof buf-len, fmt, ap);
+    va_end(ap);
+
+    if (len > sizeof buf - 2) {
+	len = sizeof buf - 2;
+	buf[len-1] = '\n';
+    }
+    if (buf[len-1] == '\n') {
+	buf[len-1] = '\r';
+	buf[len++] = '\n';
+    }
+    buf[len] = '\0';
+
+    for (int i = 0; i < ARRAY_SIZE(ttys); i++) {
+	if (ttys[i])
+	    ttys[i]->port().write(buf, len);
+    }
+}

+ 77 - 26
esp32/max80/wifi.cpp

@@ -1,16 +1,21 @@
 #include "common.h"
-#include "WiFi.h"
 #include "wifi.h"
 #include "config.h"
 #include "httpd.h"
 #include "led.h"
 
+#include <WiFi.h>
+
+#include <mdns.h>
+
 #include <lwip/dns.h>
 #include <lwip/inet.h>
 #include <lwip/apps/sntp.h>
 #include <esp_sntp.h>
 #include <esp_wifi.h>
 
+WiFiUDP UDP;
+
 static const char *ssid, *password, *hostname, *dnsserver;
 static TimerHandle_t sta_failure_timer;
 
@@ -70,7 +75,6 @@ static void sta_timeout_disable(void)
 
 static void sntp_sync_cb(struct timeval *tv)
 {
-    static uint8_t prev_sync_status = SNTP_SYNC_STATUS_RESET;
     uint8_t sync_status = sntp_get_sync_status();
 
     switch (sync_status) {
@@ -85,8 +89,6 @@ static void sntp_sync_cb(struct timeval *tv)
     default:
 	break;
     }
-
-    prev_sync_status = sync_status;
 }
 
 static void my_sntp_start(void)
@@ -159,10 +161,10 @@ static void sntp_set_server(const char *name)
 	sntp_server_found(name, &addr, NULL);
 }
 
-static void start_services(void)
+static void dns_setup(void)
 {
-    /* Always run after (re)connect */
     const ip_addr_t *dns_ip = dns_getserver(0);
+
     if (invalid_ip(dns_ip) || getenv_bool("ip4.dhcp.nodns")) {
 	/* Static DNS server configuration */
 	ip_addr_t addr;
@@ -172,12 +174,70 @@ static void start_services(void)
 	}
     }
 
-    {
-	dns_ip = dns_getserver(0);
-	const char *dns_server_str = inet_ntoa(*dns_ip);
-	printf("[DNS]  DNS server: %s\n", dns_server_str);
-	setenv_cond("status.net.dns.server", dns_server_str);
+    dns_ip = dns_getserver(0);
+    const char *dns_server_str = inet_ntoa(*dns_ip);
+    printf("[DNS]  DNS server: %s\n", dns_server_str);
+    setenv_cond("status.net.dns.server", dns_server_str);
+}
+
+static esp_ip_addr_t ipaddr_toesp(IPAddress ip)
+{
+    esp_ip_addr_t eip;
+    memset(&eip, 0, sizeof eip);
+    eip.u_addr.ip4.addr = (uint32_t)ip;
+    return eip;
+}
+
+static void mdns_setup(void)
+{
+    static bool mdns_started;
+    static const struct mdns_service {
+	const char *type, *proto;
+	uint16_t port;
+    } mdns_services[] = {
+	{ "_http", "_tcp", 80 },
+	{ NULL, NULL, 0 }
+    };
+    char unique_name[32];
+
+    if (mdns_started)
+	mdns_free();
+
+    if (!getenv_bool("mdns.enabled"))
+	return;
+
+    mdns_started = mdns_init() == ESP_OK;
+    if (!mdns_started)
+	return;
+
+    mdns_hostname_set(hostname);
+    mdns_instance_name_set(hostname);
+
+    unique_name[0] = 0;
+
+    if (connected & CON_STA) {
+	mdns_ip_addr_t iplist;
+
+	iplist.addr = ipaddr_toesp(WiFi.localIP());
+	iplist.next = NULL;
+	snprintf(unique_name, sizeof unique_name, "MAX80-%s", serial_number);
+	mdns_delegate_hostname_add(unique_name, &iplist);
+    }
+
+    for (const struct mdns_service *svc = mdns_services; svc->type; svc++) {
+	mdns_service_add(NULL, svc->type, svc->proto, svc->port, NULL, 0);
+	if (unique_name[0]) {
+	    mdns_service_add_for_host(NULL, svc->type, svc->proto,
+				      unique_name, svc->port, NULL, 0);
+	}
     }
+}
+
+static void start_services(void)
+{
+    /* Always run after (re)connect */
+    dns_setup();
+    mdns_setup();
 
     // If Arduino supported both of these at the same that would be
     // awesome, but it requires ESP-IDF reconfiguration...
@@ -412,7 +472,6 @@ static void wifi_config_ap(void)
     IPAddress AP_Gateway = IPAddress(0,0,0,0); // No gateway
     unsigned int channel = (time(NULL) % 11) + 1;	   // Pseudo-random
     uint8_t mac[6];
-    char mac_str[6*3];
     static char ap_ssid[64];
 
     WiFi.softAPmacAddress(mac);
@@ -423,7 +482,8 @@ static void wifi_config_ap(void)
 	     efuse_default_mac[4], efuse_default_mac[5]);
 
     printf("[WIFI] AP SSID %s IP %s netmask %s channel %u\n",
-	       ap_ssid, AP_IP.toString(), AP_Netmask.toString(), channel);
+	   ap_ssid, AP_IP.toString().c_str(),
+	   AP_Netmask.toString().c_str(), channel);
     setenv_cond("status.net.ap.ssid", ap_ssid);
     setenv_ip("status.net.ap.ip4", AP_IP);
     setenv_ip("status.net.ap.ip4.mask", AP_Netmask);
@@ -434,7 +494,7 @@ static void wifi_config_ap(void)
     printf("WiFi.softAPConfig\n");
     WiFi.softAPConfig(AP_IP, AP_Gateway, AP_Netmask);
     printf("WiFi.softAPsetHostname\n");
-    WiFi.softAPsetHostname("max80");
+    WiFi.softAPsetHostname(hostname);
 
     // Conservative setting: 20 MHz (single channel) only; this is for
     // reliability, not performance.
@@ -442,7 +502,6 @@ static void wifi_config_ap(void)
     esp_wifi_set_bandwidth((wifi_interface_t)ESP_IF_WIFI_AP, WIFI_BW_HT20);
 
     // Enable AP immediately if no SSID configured
-    printf("WiFi.enableAP\n");
     WiFi.enableAP(!ssid);
 }
 
@@ -477,19 +536,11 @@ static void wifi_config_sta(void)
     WiFi.begin(ssid, password);
 }
 
-static const char *getenv_notempty(const char *env)
-{
-    const char *str = getenv(env);
-    if (str && !*str)
-	str = NULL;
-    return str;
-}
-
 static void wifi_config(void)
 {
     ssid         = getenv_notempty("wifi.ssid");
     password     = getenv_notempty("wifi.psk");
-    hostname     = getenv_notempty("hostname");
+    hostname     = getenv_def("hostname", "max80");
     dnsserver    = getenv_notempty("ip4.dns");
 
     force_conn_update = true;
@@ -501,8 +552,8 @@ static void wifi_config(void)
 
     WiFi.setTxPower(WIFI_POWER_19_5dBm);
 
-    if (hostname)
-	WiFi.hostname(hostname);
+    setenv_config("status.hostname", hostname);
+    WiFi.hostname(hostname);
 
     printf("wifi_config_ap\n");
     wifi_config_ap();

BIN
esp32/output/max80.ino.bin


+ 8 - 0
esp32/www/config.html

@@ -12,6 +12,14 @@
 	  onsubmit="uploadform()" data-ref="10" data-ref-url="status.html">
       <fieldset class="network">
 	<legend>Network</legend>
+	<label class="hostname">
+	  <b>Host name</b>
+	  <input type="text" name="hostname" />
+	</label>
+	<label class="mdns">
+	  <b>mDNS</b>
+	  <input type="checkbox" name="mdns.enabled" />
+	</label>
 	<label class="wifi-ssid">
 	  <b>Network name (SSID)</b>
 	  <input type="text" name="wifi.ssid" />

+ 1 - 0
esp32/www/lang/sv

@@ -8,6 +8,7 @@ title.abcbus=MAX80: ABC-buss
 title.config=MAX80: Konfiguration
 title.update=MAX80: Uppdatera
 .fw legend=Mjukvara
+.hostname b=Systemnamn
 .network legend=Nätverk
 .wifi-ssid b=Nätverksnamn (SSID)
 .wifi-psk b=Lösenord (PSK)

+ 4 - 0
esp32/www/status.html

@@ -20,6 +20,10 @@
 	  <b>Serial Number</b>
 	  <input type="text" name="max80.hw.serial" />
 	</label>
+	<label class="hostname">
+	  <b>Host Name</b>
+	  <input type="text" name="hostname" />
+	</label>
 	<label class="fpgaok">
 	  <b>FPGA online</b>
 	  <input type="checkbox" name="max80.fpga" />

+ 3 - 3
fpga/max80.qpf

@@ -19,15 +19,15 @@
 #
 # Quartus Prime
 # Version 21.1.0 Build 842 10/21/2021 SJ Lite Edition
-# Date created = 02:47:26  December 22, 2022
+# Date created = 14:01:37  December 22, 2022
 #
 # -------------------------------------------------------------------------- #
 
 QUARTUS_VERSION = "21.1"
-DATE = "02:47:26  December 22, 2022"
+DATE = "14:01:37  December 22, 2022"
 
 # Revisions
 
-PROJECT_REVISION = "v1"
 PROJECT_REVISION = "v2"
+PROJECT_REVISION = "v1"
 PROJECT_REVISION = "bypass"

BIN
fpga/output/bypass.rpd.gz


BIN
fpga/output/max80.fw


BIN
fpga/output/v1.fw


BIN
fpga/output/v1.jic


BIN
fpga/output/v1.rbf.gz


BIN
fpga/output/v1.rpd.gz


BIN
fpga/output/v1.sof


BIN
fpga/output/v1.svf.gz


BIN
fpga/output/v1.xsvf.gz


BIN
fpga/output/v2.fw


BIN
fpga/output/v2.jic


BIN
fpga/output/v2.rbf.gz


BIN
fpga/output/v2.rpd.gz


BIN
fpga/output/v2.sof


BIN
fpga/output/v2.svf.gz


BIN
fpga/output/v2.xsvf.gz