summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2022-08-09 19:03:03 -0700
committerH. Peter Anvin <hpa@zytor.com>2022-08-09 19:03:03 -0700
commit12519f981f85c98c49b61b009c9ab2f666ffa84e (patch)
tree251b2a1324f3631d06143b8495a00fd1bcb166c5
parent3347303ea551b241eb4643619e434cc59f382b81 (diff)
downloadblinktest-12519f981f85c98c49b61b009c9ab2f666ffa84e.tar.gz
blinktest-12519f981f85c98c49b61b009c9ab2f666ffa84e.tar.xz
blinktest-12519f981f85c98c49b61b009c9ab2f666ffa84e.zip
update: it is slow, but now firmware upload via serial port & USB work
Still slow, but now "make upload-vX PORT=..." can be used to upload a firmware image (*.fw) to update everything from bare metal, including ESP32 bootloader and partition table.
-rwxr-xr-xesp32/flashesp.pl120
-rw-r--r--esp32/max80/config.c18
-rw-r--r--esp32/max80/fpgajtag.c9
-rw-r--r--esp32/max80/fw.h2
-rw-r--r--esp32/max80/fwupdate.c44
-rw-r--r--esp32/max80/httpd.c2
-rw-r--r--esp32/max80/max80.ino41
-rw-r--r--esp32/max80/tty.cpp241
-rw-r--r--esp32/max80/tty.h10
-rw-r--r--esp32/max80/wifi.cpp68
-rw-r--r--esp32/output/max80.ino.binbin796896 -> 796304 bytes
-rw-r--r--fpga/max80.qpf6
-rw-r--r--fpga/output/bypass.rbf.gzbin8209 -> 8209 bytes
-rw-r--r--fpga/output/bypass.rpd.gzbin64733 -> 64733 bytes
-rw-r--r--fpga/output/bypass.sofbin496887 -> 496887 bytes
-rw-r--r--fpga/output/bypass.svf.gzbin21277 -> 21274 bytes
-rw-r--r--fpga/output/bypass.xsvf.gzbin15231 -> 15231 bytes
-rw-r--r--fpga/output/v1.fwbin760109 -> 760180 bytes
-rw-r--r--fpga/output/v1.jicbin16777443 -> 16777443 bytes
-rw-r--r--fpga/output/v1.rbf.gzbin161096 -> 161044 bytes
-rw-r--r--fpga/output/v1.rpd.gzbin218493 -> 216183 bytes
-rw-r--r--fpga/output/v1.sofbin509098 -> 509096 bytes
-rw-r--r--fpga/output/v1.svf.gzbin183138 -> 183083 bytes
-rw-r--r--fpga/output/v1.xsvf.gzbin165476 -> 165428 bytes
-rw-r--r--fpga/output/v2.fwbin761031 -> 761156 bytes
-rw-r--r--fpga/output/v2.jicbin16777443 -> 16777443 bytes
-rw-r--r--fpga/output/v2.rbf.gzbin161654 -> 161584 bytes
-rw-r--r--fpga/output/v2.rpd.gzbin217811 -> 217922 bytes
-rw-r--r--fpga/output/v2.sofbin509098 -> 509096 bytes
-rw-r--r--fpga/output/v2.svf.gzbin184167 -> 184083 bytes
-rw-r--r--fpga/output/v2.xsvf.gzbin165827 -> 165775 bytes
31 files changed, 413 insertions, 148 deletions
diff --git a/esp32/flashesp.pl b/esp32/flashesp.pl
index 3402711..bc17958 100755
--- a/esp32/flashesp.pl
+++ b/esp32/flashesp.pl
@@ -33,6 +33,42 @@ my $FDF_OPTIONAL = 0x0001;
my $STRING_MAX_LEN = 4095;
+# For debug; DC1-4 replaced with functional names
+my @ascii = qw(NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI
+ DLE XON WRST XOFF WGO NAK SYN ETB CAN EM SUB ESC FS GS RS US);
+foreach my $i (9, 10, 13, 32..126) {
+ $ascii[$i] = chr($i);
+}
+$ascii[127] = 'DEL';
+for (my $i = 128; $i < 256; $i++) {
+ $ascii[$i] = sprintf("%02X", $i);
+}
+my @a = map { length($_) == 1 ? $_ : '<'.$_.'>' } @ascii;
+
+# Simple base64 encode using 3F-7E, bytewise bigendian
+sub mybaseencode {
+ my $nbits = 0;
+ my $bitbuf = 0;
+ my $out = '';
+
+ foreach my $s (@_) {
+ foreach my $c (unpack('C*', $s)) {
+ $nbits += 8;
+ $bitbuf = ($bitbuf << 8) + $c;
+ while ($nbits >= 6) {
+ $nbits -= 6;
+ $out .= pack('C', 63 + (($bitbuf >> $nbits) & 63));
+ }
+ }
+ }
+
+ if ($nbits) {
+ $out .= pack('C', 63 + ($bitbuf & ((1 << $nbits) - 1)));
+ }
+
+ return $out;
+}
+
sub getint($) {
my($s) = @_;
@@ -313,6 +349,7 @@ sub tty_write($$) {
my $found = 0;
my $tt = time();
my $start_enq = $tt;
+tty_write($tty, "\005"); # ENQ
while (($tt = time()) - $start_enq < 30) {
my $d = tty_read($tty, \$ttybuf, 1000);
if ($d eq '') {
@@ -341,44 +378,83 @@ while (!defined($winspc)) {
}
tty_write($tty, "\034\001: /// MAX80 FW UPLOAD \~\@\~ \$\r\n\035");
my $d;
- do {
+ while (1) {
$d = tty_read($tty, \$ttybuf, 1000);
- if ($d eq "\036") {
+ last if ($d eq '');
+ my $dc = unpack('C', $d);
+ if ($dc == 036) {
$winspc = 0;
last;
} else {
- print $d;
+ print STDERR $a[$dc];
}
- } while ($d ne '');
+ }
}
my $bytes = length($fpgadata);
my $offset = 0;
-while ($offset < $bytes) {
- my $chunk = $bytes - $offset;
- $chunk = 64 if ($chunk > 64);
- $chunk = $winspc if ($chunk > $winspc);
-
- my $d = tty_read($tty, \$ttybuf, $chunk ? undef : 1000);
- if ($d ne '') {
- if ($d eq "\022") {
+my $maxchunk = 64;
+my $maxahead = 256;
+my $last_ack = 0;
+my @pktends = ();
+
+print STDERR "\nStarting packet transmit...\n";
+
+while ($last_ack < $bytes) {
+ my $chunk;
+
+ while (1) {
+ $chunk = $bytes - $offset;
+ $chunk = $winspc if ($chunk > $winspc);
+ if ($offset + $chunk > $last_ack + $maxahead) {
+ $chunk = $last_ack + $maxahead - $offset;
+ }
+ $chunk = 0 if ($chunk <= 0);
+ $chunk = $maxchunk if ($chunk > $maxchunk);
+
+ my $d = tty_read($tty, \$ttybuf, $chunk ? 0 : 1000);
+ last if ($d eq '');
+
+ my $dc = unpack('C', $d);
+ if ($dc == 022) {
$winspc = 0;
- } elsif ($d eq "\024") {
- $winspc += 256;
- } elsif ($d eq "\027" || $d eq "\030" || $d eq "\025") {
- die "$0: $port: upload terminated by MAX80\n";
- } elsif ($d ne "\006") {
- print STDERR $d;
+ print STDERR "WRST, window: $winspc\n";
+ } elsif ($dc == 024) {
+ if (defined($winspc)) {
+ $winspc += 256;
+ print STDERR "WGO, window: $winspc\n";
+ }
+ } elsif ($dc == 006) {
+ $last_ack = shift(@pktends) || $last_ack;
+ print STDERR "ACK to $last_ack\n";
+ } else {
+ print STDERR $a[$dc];
+ if ($dc == 025 || $dc == 031 || $dc == 037) {
+ print STDERR "\n$0: $port: resetting upload to $last_ack\n";
+ $offset = $last_ack;
+ @pktends = ();
+ undef $winspc; # Wait for WRST before resuming
+ } elsif ($dc == 030) {
+ print STDERR "\n";
+ die "$0: $port: upload aborted by target system\n";
+ }
}
}
- next unless($chunk);
+ print STDERR "Send offset: $offset, window: $winspc, chunk: $chunk\n";
+ if (!$chunk) {
+ if ($bytes > $offset) {
+ tty_write($tty, "\026"); # Request to resynchronize credits
+ }
+ next;
+ }
my $data = substr($fpgadata, $offset, $chunk);
- my $hdr = pack("CCvVV", 2, $chunk-1, 0, $offset, crc32($data));
+ my $hdr = pack("CvVV", $chunk-1, 0, $offset, crc32($data));
- tty_write($tty, $hdr.$data);
+ tty_write($tty, "\002".mybaseencode($hdr, $data));
+ push(@pktends, $offset + $chunk);
$offset += $chunk;
$winspc -= $chunk;
}
@@ -386,4 +462,6 @@ while ($offset < $bytes) {
tty_write($tty, "\004"); # EOT
$tty->close;
+print STDERR "$0: $port: firmware upload complete\n";
+
exit 0;
diff --git a/esp32/max80/config.c b/esp32/max80/config.c
index f497312..aca6688 100644
--- a/esp32/max80/config.c
+++ b/esp32/max80/config.c
@@ -34,10 +34,13 @@ int setenv_config(const char *name, const char *value)
int setenv_cond(const char *name, const char *value)
{
- if (value)
+ if (value) {
+ printf("env: %s=%s\n", name, value);
return setenv(name, value, 1);
- else
+ } else {
+ printf("env: %s undefined\n", name);
return unsetenv(name);
+ }
}
static int reset_config(void)
@@ -56,16 +59,19 @@ static int reset_config(void)
break;
const char *eq = strchr(*envp, '=');
+ if (!eq)
+ continue; /* This should never happen... */
+
char ename[eq - *envp + 1];
memcpy(ename, *envp, eq - *envp);
ename[eq - *envp] = '\0';
- unsetenv(ename);
+ setenv_cond(ename, NULL);
}
size_t i;
for (i = 0; i < ARRAY_SIZE(default_config); i++)
- setenv(default_config[i].var, default_config[i].val, 1);
+ setenv_cond(default_config[i].var, default_config[i].val);
config_changed = true;
}
@@ -260,7 +266,7 @@ void setenv_l(const char *var, long val)
{
char vbuf[2+3*sizeof val];
snprintf(vbuf, sizeof vbuf, "%ld", val);
- setenv(var, vbuf, 1);
+ setenv_cond(var, vbuf);
}
unsigned long getenv_ul(const char *var, unsigned long def)
@@ -279,7 +285,7 @@ void setenv_ul(const char *var, unsigned long val)
{
char vbuf[2+3*sizeof val];
snprintf(vbuf, sizeof vbuf, "%lu", val);
- setenv(var, vbuf, 1);
+ setenv_cond(var, vbuf);
}
bool getenv_bool(const char *var)
diff --git a/esp32/max80/fpgajtag.c b/esp32/max80/fpgajtag.c
index ba8cb70..d57d555 100644
--- a/esp32/max80/fpgajtag.c
+++ b/esp32/max80/fpgajtag.c
@@ -203,16 +203,23 @@ int fpga_program_spz(spz_stream *spz)
//
// XXX: Actually try to detect board revision 2.1...
//
+// YYY: IO26 is CS# för PSRAM! This is invalid usage... probably will need
+// a rework on the 2.1 board!
+//
void fpga_enable_nce(void)
{
- pinMode(PIN_FPGA_nCE, INPUT_PULLDOWN);
+#if 0
+ pinMode(PIN_FPGA_nCE, INPUT_PULLDOWN);
delayMicroseconds(100); /* Just in case */
+#endif
}
int fpga_reset(void)
{
int err = 0;
+ printf("[FPGA] Resetting FPGA via JTAG\n");
+
fpga_enable_nce();
jtag_enable(&jtag_config_fpga);
tap_run_test_idle(JTAG_FPGA_MS);
diff --git a/esp32/max80/fw.h b/esp32/max80/fw.h
index 464a538..8012790 100644
--- a/esp32/max80/fw.h
+++ b/esp32/max80/fw.h
@@ -25,7 +25,7 @@
#define FWUPDATE_ERR_CONFIG_READ (-24)
#define FWUPDATE_ERR_CONFIG_SAVE (-25)
-extern_c int firmware_update_start(read_func_t read_data, token_t token);
+extern_c int firmware_update_start(read_func_t read_data, token_t token, bool autoreboot);
extern_c int firmware_update_wait(TickType_t delay);
extern_c int esp_update(read_func_t read_func, token_t token, size_t size);
extern_c const char *firmware_errstr(int err);
diff --git a/esp32/max80/fwupdate.c b/esp32/max80/fwupdate.c
index 4b2672d..7fca4fe 100644
--- a/esp32/max80/fwupdate.c
+++ b/esp32/max80/fwupdate.c
@@ -25,16 +25,25 @@
#define FWUPDATE_STACK 8192
#define FWUPDATE_PRIORITY 3
+static void heap_info(void)
+{
+#if DEBUG > 1
+ MSG("Heap: sram ");
+ MSG("%u/", heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL));
+ MSG("%u, spiram ", heap_caps_get_free_size(MALLOC_CAP_INTERNAL));
+ MSG("%u/", heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM));
+ MSG("%u\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
+#endif
+}
+
static void *spz_calloc(void *opaque, unsigned int items, unsigned int size)
{
spz_stream *spz = opaque;
- MSG("spz_calloc(%u), sram %u/%u, spiram %u/%u = ", items*size,
- heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL),
- heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
- heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM),
- heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
+ heap_info();
+ MSG("spz_calloc(%u,%u) = %u = ", items, size, items*size);
void *p = calloc(items, size);
CMSG("%p\n", p);
+ heap_info();
if (!p)
spz->err = Z_MEM_ERROR;
return p;
@@ -42,13 +51,11 @@ static void *spz_calloc(void *opaque, unsigned int items, unsigned int size)
static void *spz_malloc(void *opaque, unsigned int size)
{
spz_stream *spz = opaque;
- MSG("spz_malloc(%u), sram %u/%u, spiram %u/%u = ", size,
- heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL),
- heap_caps_get_free_size(MALLOC_CAP_INTERNAL),
- heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM),
- heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
+ heap_info();
+ MSG("spz_malloc(%u) = ", size);
void *p = malloc(size);
CMSG("%p\n", p);
+ heap_info();
if (!p)
spz->err = Z_MEM_ERROR;
return p;
@@ -56,8 +63,11 @@ static void *spz_malloc(void *opaque, unsigned int size)
static void spz_free(void *opaque, void *ptr)
{
+ heap_info();
+ MSG("spz_free(%p)\n", ptr);
(void)opaque;
free(ptr);
+ heap_info();
}
int spz_read_data(spz_stream *spz, void *buf, size_t len)
@@ -358,6 +368,7 @@ 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)
{
@@ -391,7 +402,14 @@ fail:
if (spz->err)
MSG("failed (err %d)\n", spz->err);
xSemaphoreGive(fwupdate_done);
- exit_task();
+
+ if (do_reboot) {
+ printf("[FWUP] rebooting in %d seconds\n", reboot_delayed());
+ while (1)
+ vTaskSuspend(NULL);
+ } else {
+ exit_task();
+ }
}
static int firmware_update_cleanup(void)
@@ -420,11 +438,13 @@ static int firmware_update_cleanup(void)
return err;
}
-int firmware_update_start(read_func_t read_data, token_t token)
+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)
return FWUPDATE_ERR_IN_PROGRESS;
diff --git a/esp32/max80/httpd.c b/esp32/max80/httpd.c
index 333a6fd..5d99acc 100644
--- a/esp32/max80/httpd.c
+++ b/esp32/max80/httpd.c
@@ -329,7 +329,7 @@ static esp_err_t httpd_firmware_update(httpd_req_t *req)
int rv;
/* XXX: use httpd_fopen_read() here */
- rv = firmware_update_start((read_func_t)httpd_req_recv, (token_t)req);
+ rv = firmware_update_start((read_func_t)httpd_req_recv, (token_t)req, false);
if (!rv)
rv = firmware_update_wait(portMAX_DELAY);
diff --git a/esp32/max80/max80.ino b/esp32/max80/max80.ino
index 1a7cea8..b4e38cb 100644
--- a/esp32/max80/max80.ino
+++ b/esp32/max80/max80.ino
@@ -38,6 +38,16 @@ void setup_usb_ids()
USB.serialNumber(serial);
}
+static void heap_info()
+{
+ size_t il = heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL);
+ size_t ia = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
+ size_t sl = heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM);
+ size_t sa = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
+
+ printf("Heap: sram %zu/%zu, spiram %zu/%zu\n", il, ia, sl, sa);
+}
+
static void dump_config()
{
printf("--- Configuration:\n");
@@ -68,6 +78,7 @@ static void init_hw()
pinMode(PIN_USB_PWR_SINK, OUTPUT); // IO8: USB_PWR_SINK
digitalWrite(PIN_USB_PWR_SINK, 0); // This is a power sink
+ #if 0
pinMode(PIN_USB_PWR_EN, OUTPUT);
digitalWrite(PIN_USB_PWR_EN, 0);
delayMicroseconds(100);
@@ -79,6 +90,9 @@ static void init_hw()
delayMicroseconds(50);
max80_board_version = digitalRead(PIN_USB_PWR_EN) ? 1 : 2;
+#else
+ max80_board_version = 2;
+#endif
pinMode(PIN_USB_PWR_EN, OUTPUT);
digitalWrite(PIN_USB_PWR_EN, 0);
@@ -95,34 +109,26 @@ void setup() {
init_hw();
// Enable external PSRAM for heap
- heap_caps_malloc_extmem_enable(2048); // >= 2K allocations in PSRAM
+ heap_caps_malloc_extmem_enable(3000); // >= 3K allocations in PSRAM
+ heap_info();
TTY::init();
+ heap_info();
printf("[PCB] MAX80 board version: %u\n", max80_board_version);
setenv_ul("status.max80.hw.ver", max80_board_version);
Serial.println("MAX80 start");
- fpga_service_init();
- Serial.println("0.2");
init_config();
- Serial.println("0.3");
setenv_cond("status.max80.fw.date", fwdate);
+ fpga_service_init();
fpga_service_enable(true);
- Serial.println("0.4");
SetupWiFi();
- Serial.println("0.5");
- printf("[RDY]\n");
+ Serial.println("[RDY]");
dump_config();
led_set(LED_BLUE, LED_ON); // Software ready
- Serial.println("0.5");
- printf("Total heap: %d\n"
- "Free heap: %d\n"
- "Total PSRAM: %d\n"
- "Free PSRAM: %d\n",
- ESP.getHeapSize(), ESP.getFreeHeap(),
- ESP.getPsramSize(), ESP.getFreePsram());
+ heap_info();
}
static inline char task_state(eTaskState state)
@@ -161,15 +167,14 @@ static void dump_tasks(void)
}
void loop() {
- if (1) {
+ if (0) {
printf("loop task: %s\n", pcTaskGetName(xTaskGetCurrentTaskHandle()));
printf("idle task: %s\n", pcTaskGetName(xTaskGetIdleTaskHandle()));
-
dump_tasks();
-
+ heap_info();
putchar('\n');
}
TTY::ping();
- vTaskDelay(30 * configTICK_RATE_HZ);
+ vTaskDelay(5 * configTICK_RATE_HZ);
}
diff --git a/esp32/max80/tty.cpp b/esp32/max80/tty.cpp
index 3b59c99..ee61c7c 100644
--- a/esp32/max80/tty.cpp
+++ b/esp32/max80/tty.cpp
@@ -31,7 +31,7 @@
#define WGO_CHUNK 256
#define STREAMBUF_SIZE 2048
-#define BUF_SLACK 32
+#define BUF_SLACK (STREAMBUF_SIZE >> 1)
static char enq_str[] = "\026\035MAX80 v0\004\r\n";
static const char fwupload_start[] =
@@ -39,15 +39,16 @@ static const char fwupload_start[] =
void TTY::reset()
{
- rx.rlen = 0;
- rx.state = rx_state::normal;
+ rx.rlen = 0;
+ rx.state = rx_state::normal;
+ rx.b64_bits = 0;
}
TTY::TTY(Stream &port)
{
_port = &port;
- rx_sbuf = NULL;
+ rx_sbuf = true ? xStreamBufferCreate(STREAMBUF_SIZE, 1) : NULL;
reset();
}
@@ -64,13 +65,30 @@ int TTY::rxdata(void *buf, size_t len)
if (!rx_sbuf)
return 0;
- while (tx_credits_ok - tx_credits_sent >= WGO_CHUNK &&
- port().write(WGO)) {
- tx_credits_sent += WGO_CHUNK;
- }
+ int rcv = 0;
+ while (!rcv) {
+ if (tx_credits_reset) {
+ // Drain input before WRST
+ rcv = xStreamBufferReceive(rx_sbuf, buf, len, 0);
+
+ if (rcv)
+ break;
- int rcv = xStreamBufferReceive(rx_sbuf, buf, len, portMAX_DELAY);
- tx_credits_ok += rcv;
+ if (port().write(WRST)) {
+ tx_credits_reset = false;
+ tx_credits = STREAMBUF_SIZE - BUF_SLACK;
+ } else {
+ // Uhm... wait one tick and then try again to sent WRST?
+ rcv = xStreamBufferReceive(rx_sbuf, buf, len, 1);
+ }
+ } else {
+ while (tx_credits >= WGO_CHUNK && port().write(WGO))
+ tx_credits -= WGO_CHUNK;
+
+ rcv = xStreamBufferReceive(rx_sbuf, buf, len, 1);
+ tx_credits += rcv;
+ }
+ }
printf("got %d\n", rcv);
return rcv;
@@ -97,13 +115,14 @@ void TTY::_upload_begin()
goto can;
port().write(RS);
- tx_credits_sent = 0;
- tx_credits_ok = STREAMBUF_SIZE - BUF_SLACK;
- rx.state = rx_state::hdr;
+ tx_credits_reset = true;
+ rx.state = rx_state::stxwait;
+ rx.last_ack = 0;
rx.rlen = 0;
+ rx.b64_bits = 0;
printf("[TTY] firmware_update_start()\n");
- if (firmware_update_start(TTY::rxdata, (token_t)this))
+ if (firmware_update_start(TTY::rxdata, (token_t)this, true))
goto can;
return;
@@ -116,24 +135,54 @@ can:
void TTY::_onerr()
{
- if (rx.state != rx_state::normal)
- port().write(WRST);
+ if (rx.state != rx_state::normal) {
+ port().write(NAK);
+ }
+}
+
+static int filter_echo(int byte)
+{
+ if (byte >= ' ' && byte < 127)
+ return byte;
+ if (byte == '\t' || byte == '\r' || byte == '\n')
+ return byte;
+
+ return -1;
+}
+
+// Decode a base64 data byte (using simple offset-63)
+// Call with -1 or any invalid value to invalidate the input buffer
+int TTY::_decode_data(int input)
+{
+ unsigned int buf = rx.b64_buf;
+ unsigned int inval = input - '?';
+
+ if (inval > 63) {
+ rx.b64_bits = 0;
+ return -2; // Invalid input
+ }
+
+ rx.b64_buf = buf = (buf << 6) + inval;
+ rx.b64_bits += 6;
+
+ if (rx.b64_bits >= 8) {
+ rx.b64_bits -= 8;
+ return (uint8_t)(buf >> rx.b64_bits);
+ } else {
+ return -1;
+ }
}
// Change this to be a buffer...
void TTY::_onrx()
{
- int byte;
- int len;
-
- while (1) {
- int byte = port().read();
- if (byte == -1)
- break; // No more data
+ int byte, data;
+ while ((byte = port().read()) >= 0) {
switch (rx.state) {
case rx_state::normal:
- if (byte == fwupload_start[rx.rlen]) {
+ if (rx.rlen < sizeof fwupload_start &&
+ byte == fwupload_start[rx.rlen]) {
if (!fwupload_start[++rx.rlen]) {
_upload_begin();
byte = -1;
@@ -151,69 +200,137 @@ void TTY::_onrx()
byte = ETB; // Not in file upload state
break;
default:
- // Normal echo
+ // Echo if printable
+ byte = filter_echo(byte);
break;
}
}
break;
- case rx_state::hdr:
- if (rx.rlen > 0 || byte == STX) {
+ case rx_state::stxwait:
+ switch (byte) {
+ case STX:
+ rx.rlen = 0;
rx.hdr_raw[rx.rlen++] = byte;
+ rx.b64_bits = 0;
+ rx.state = rx_state::hdr;
+ byte = -1;
+ break;
+ case ETX:
+ case CAN:
+ printf("[UPLD] Received <%02X> waiting for STX\n", byte);
+ reset();
+ byte = CAN;
+ break;
+ case ENQ:
+ rx.rlen = 0;
+ byte = GS; // In upload wait for STX state
+ break;
+ case SYN:
+ rx.rlen = 0;
+ tx_credits_reset = true; // Request to resync credits
byte = -1;
+ break;
+ case EOT:
+ // Upload complete, no more data
+ byte = ETB;
+ break;
+ default:
+ byte = -1; // No echo
+ break;
+ }
+ break;
+
+ case rx_state::hdr:
+ data = _decode_data(byte);
+ byte = -1;
+ if (data < -1) {
+ rx.state = rx_state::stxwait;
+ rx.rlen = 0;
+ tx_credits_reset = true;
+ byte = US; // Framing error
+ } else if (data == -1) {
+ // Nothing to do
+ } else if (rx.rlen >= sizeof rx.hdr_raw) {
+ // ERROR THIS SHOULD NEVER HAPPEN
+ printf("[UPLD] Header buffer overrun!!!\n");
+ reset();
+ byte = CAN;
+ } else {
+ rx.hdr_raw[rx.rlen++] = data;
if (rx.rlen == sizeof rx.hdr) {
// Start of data packet
+ printf("[UPLD] Start packet hdr %d length %d offset %d last_ack %d\n",
+ rx.rlen, rx.hdr.len+1, rx.hdr.offs, rx.last_ack);
rx.state = rx_state::data;
rx.rlen = 0;
}
- } else {
- switch (byte) {
- case ETX:
- case EOT:
- case CAN:
- reset();
- byte = CAN;
- break;
- case ENQ:
- byte = SYN; // In file upload state
- break;
- default:
- // Normal echo
- break;
- }
}
break;
case rx_state::data:
- rx_data[rx.rlen++] = byte;
+ data = _decode_data(byte);
byte = -1;
- // rx.hdr.len = packet data len - 1
- if (rx.rlen > rx.hdr.len) {
- int have = rx.rlen;
- uint32_t crc = crc32_le(0, rx_data, have);
-
- if (crc != rx.hdr.crc) {
- byte = NAK;
- } else if (rx.hdr.offs > rx.last_ack) {
- byte = EM;
- } else {
- int sent = 0;
-
- if (rx.hdr.offs + rx.rlen <= rx.last_ack) {
- have = 0;
+ if (data < -1) {
+ rx.state = rx_state::stxwait;
+ rx.rlen = 0;
+ tx_credits_reset = true;
+ byte = US; // Framing error
+ } else if (data == -1) {
+ // Nothing to do
+ } else if (rx.rlen >= sizeof rx_data) {
+ // ERROR THIS SHOULD NEVER HAPPEN
+ printf("[UPLD] Packet data buffer overrun!!!\n");
+ reset();
+ byte = CAN;
+ } else {
+ rx_data[rx.rlen++] = data;
+ // rx.hdr.len = packet data len - 1
+ if (rx.rlen > rx.hdr.len) {
+ int have = rx.rlen;
+ uint32_t crc;
+
+ if (have != rx.hdr.len + 1) {
+ printf("[UPLD] Invalid packet length (should not happen...)\n");
+ byte = NAK;
+ } else if ((crc = crc32_le(0, rx_data, have))
+ != rx.hdr.crc) {
+ printf("[UPLD] Packet CRC error hdr %08x data %08x\n", rx.hdr.crc, crc);
+ printf("\"");
+ for (int i = 0; i < have; i++)
+ printf("\\x%02x", rx_data[i]);
+ printf("\"\n");
+ byte = NAK;
+ } else if (rx.hdr.offs > rx.last_ack) {
+ printf("[UPLD] Invalid packet offsets [%d..%d) at %d\n",
+ rx.hdr.offs, rx.hdr.offs + have, rx.last_ack);
+ byte = EM;
+ } else if (rx.hdr.offs + have <= rx.last_ack) {
+ // Ack and discard packet below current window (transmitter is catching up)
+ byte = ACK;
} else {
+ int sent = 0;
+
uint32_t skip = rx.last_ack - rx.hdr.offs;
have -= skip;
sent = xStreamBufferSend(rx_sbuf, rx_data+skip, have, 0);
rx.last_ack += sent;
- }
- byte = (sent == have) ? ACK : WRST;
+ if (sent != have) {
+ printf("[UPLD] Packet underrun, got %d, expected %d\n", sent, have);
+ byte = NAK;
+ } else {
+ printf("[UPLD] %d bytes received OK\n", sent);
+ byte = ACK;
+ }
+ }
+ if (byte != ACK)
+ tx_credits_reset = true;
+ rx.state = rx_state::stxwait;
+ rx.rlen = 0;
}
-
- rx.state = rx_state::hdr;
- rx.rlen = 0;
}
+
break;
}
diff --git a/esp32/max80/tty.h b/esp32/max80/tty.h
index 7339942..e6b2784 100644
--- a/esp32/max80/tty.h
+++ b/esp32/max80/tty.h
@@ -22,7 +22,7 @@ struct tty_packet_hdr {
uint16_t resv;
uint32_t offs;
uint32_t crc;
-};
+} __attribute__((packed));
class TTY {
private:
@@ -56,16 +56,20 @@ private:
enum rx_state {
normal, // Normal console mode
+ stxwait, // Waiting for header STX
hdr, // Getting header
data // Getting data packet
};
void _upload_begin();
void _update_window(bool rst = false);
+ int _decode_data(int);
// Packet receive state machine
struct {
enum rx_state state;
+ uint8_t b64_buf;
+ uint8_t b64_bits;
union {
struct tty_packet_hdr hdr;
uint8_t hdr_raw[sizeof(struct tty_packet_hdr)];
@@ -74,7 +78,7 @@ private:
uint32_t last_ack;
} rx;
StreamBufferHandle_t rx_sbuf;
- uint32_t tx_credits_ok;
- uint32_t tx_credits_sent;
+ uint32_t tx_credits;
+ volatile bool tx_credits_reset;
uint8_t rx_data[256];
};
diff --git a/esp32/max80/wifi.cpp b/esp32/max80/wifi.cpp
index ec6a85a..e4744e5 100644
--- a/esp32/max80/wifi.cpp
+++ b/esp32/max80/wifi.cpp
@@ -11,7 +11,7 @@
#include <esp_sntp.h>
#include <esp_wifi.h>
-static String ssid, password, hostname, dnsserver;
+static const char *ssid, *password, *hostname, *dnsserver;
static TimerHandle_t sta_failure_timer;
static bool sta_timeout_enabled;
@@ -102,7 +102,7 @@ static void sntp_server_show(void)
printf("[SNTP] Time server: %s\n", sntp_server);
setenv_cond("status.net.sntp.server", sntp_server);
} else {
- unsetenv("status.net.sntp.server");
+ setenv_cond("status.net.sntp.server", NULL);
}
}
@@ -137,7 +137,7 @@ static void start_services(void)
if (invalid_ip(dns_ip) || getenv_bool("ip4.dhcp.nodns")) {
/* Static DNS server configuration */
ip_addr_t addr;
- if (dnsserver != "" && inet_aton(dnsserver.c_str(), &addr)) {
+ if (dnsserver && inet_aton(dnsserver, &addr)) {
if (memcmp(dns_ip, &addr, sizeof addr))
dns_setserver(0, &addr);
}
@@ -314,7 +314,7 @@ static void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
sta_timeout_disable();
if (!ap_clients)
WiFi.enableAP(false);
- } else if (ssid != "") {
+ } else if (ssid) {
sta_timeout_enable();
}
@@ -341,7 +341,7 @@ static void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
setenv_ip("status.net.eth.ip4.gw", WiFi.gatewayIP());
}
- if (ssid == "") {
+ if (!ssid) {
// No network configured
led_set(LED_GREEN, connected & CON_AP ? LED_FLASH_SLOW : LED_OFF);
} else {
@@ -368,7 +368,7 @@ static void setenv_mac(const char *var, const uint8_t mac[6])
snprintf(mac_str, sizeof mac_str, "%02x:%02x:%02x:%02x:%02x:%02x",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
- setenv(var, mac_str, 1);
+ setenv_cond(var, mac_str);
}
static void wifi_config_ap(void)
@@ -377,10 +377,10 @@ static void wifi_config_ap(void)
IPAddress AP_IP = IPAddress(192,168,0,1);
IPAddress AP_Netmask = IPAddress(255,255,255,0);
IPAddress AP_Gateway = IPAddress(0,0,0,0); // No gateway
- unsigned int channel = time(NULL) % 11; // Pseudo-random
+ unsigned int channel = (time(NULL) % 11) + 1; // Pseudo-random
uint8_t mac[6];
char mac_str[6*3];
- char ap_ssid[64];
+ static char ap_ssid[64];
WiFi.softAPmacAddress(mac);
setenv_mac("status.net.ap.mac", mac);
@@ -388,64 +388,92 @@ static void wifi_config_ap(void)
snprintf(ap_ssid, sizeof ap_ssid, "MAX80_%02X%02X", mac[4], mac[5]);
printf("[WIFI] AP SSID %s IP %s netmask %s channel %u\n",
- ap_ssid, AP_IP.toString(), AP_Netmask.toString(), channel+1);
+ ap_ssid, AP_IP.toString(), AP_Netmask.toString(), 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);
setenv_ul("status.net.ap.clients", 0);
- WiFi.softAP(ap_ssid, NULL, channel+1, 0, 4, true);
+ printf("WiFi.softAP\n");
+ WiFi.softAP(ap_ssid, NULL, channel, 0, 4, true);
+ printf("WiFi.softAPConfig\n");
WiFi.softAPConfig(AP_IP, AP_Gateway, AP_Netmask);
+ printf("WiFi.softAPsetHostname\n");
WiFi.softAPsetHostname(ap_ssid);
// Conservative setting: 20 MHz (single channel) only; this is for
// reliability, not performance.
+ printf("esp_wifi_set_bandwidth\n");
esp_wifi_set_bandwidth((wifi_interface_t)ESP_IF_WIFI_AP, WIFI_BW_HT20);
// Enable unconditionally if no SSID
- WiFi.enableAP(ssid == "");
+ printf("WiFi.enableAP\n");
+ WiFi.enableAP(!ssid);
}
static void wifi_config_sta(void)
{
uint8_t mac[6];
+
+ printf("WiFi.macAddress\n");
WiFi.macAddress(mac);
+ printf("setenv_mac\n");
setenv_mac("status.net.sta.mac", mac);
- setenv_cond("status.net.sta.ssid", ssid.c_str());
- if (ssid == "") {
+ printf("setenv ssid\n");
+ setenv_cond("status.net.sta.ssid", ssid);
+ if (!ssid) {
WiFi.enableSTA(false);
return;
}
+ printf("xTimerCreate\n");
sta_failure_timer = xTimerCreate("wifi_sta", configTICK_RATE_HZ*30,
pdFALSE, NULL,
(TimerCallbackFunction_t)sta_timeout);
+ printf("sta_timeout_enable\n");
sta_timeout_enable();
- WiFi.begin(ssid.c_str(), password.c_str());
+ printf("WiFi.begin(%s,%s)\n", ssid, password);
+ WiFi.begin(ssid, password);
+ printf("WiFi.setAutoConnect\n");
WiFi.setAutoConnect(true);
+ printf("WiFi.setAutoReconnect\n");
WiFi.setAutoReconnect(true);
+ printf("WiFi.enableSTA\n");
WiFi.enableSTA(true);
}
+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("wifi.ssid");
- password = getenv("wifi.psk");
- hostname = getenv("hostname");
- dnsserver = getenv("ip4.dns");
+ ssid = getenv_notempty("wifi.ssid");
+ password = getenv_notempty("wifi.psk");
+ hostname = getenv_notempty("hostname");
+ dnsserver = getenv_notempty("ip4.dns");
force_conn_update = true;
+ printf("WiFi.persistent\n");
WiFi.persistent(false);
+ printf("WiFi.setSleep\n");
WiFi.setSleep(false);
- if (hostname != "")
+ if (hostname)
WiFi.hostname(hostname);
- wifi_config_sta();
+ printf("wifi_config_ap\n");
wifi_config_ap();
+ printf("wifi_config_sta\n");
+ wifi_config_sta();
+ printf("wifi_config done\n");
}
void SetupWiFi() {
diff --git a/esp32/output/max80.ino.bin b/esp32/output/max80.ino.bin
index 1e9cb9d..d48bc4c 100644
--- a/esp32/output/max80.ino.bin
+++ b/esp32/output/max80.ino.bin
Binary files differ
diff --git a/fpga/max80.qpf b/fpga/max80.qpf
index 80462d8..1694235 100644
--- a/fpga/max80.qpf
+++ b/fpga/max80.qpf
@@ -19,15 +19,15 @@
#
# Quartus Prime
# Version 21.1.0 Build 842 10/21/2021 SJ Lite Edition
-# Date created = 15:34:48 July 30, 2022
+# Date created = 11:36:55 August 08, 2022
#
# -------------------------------------------------------------------------- #
QUARTUS_VERSION = "21.1"
-DATE = "15:34:48 July 30, 2022"
+DATE = "11:36:55 August 08, 2022"
# Revisions
-PROJECT_REVISION = "v1"
PROJECT_REVISION = "v2"
+PROJECT_REVISION = "v1"
PROJECT_REVISION = "bypass"
diff --git a/fpga/output/bypass.rbf.gz b/fpga/output/bypass.rbf.gz
index 9a5f47a..39e3207 100644
--- a/fpga/output/bypass.rbf.gz
+++ b/fpga/output/bypass.rbf.gz
Binary files differ
diff --git a/fpga/output/bypass.rpd.gz b/fpga/output/bypass.rpd.gz
index 79e7c23..5ba2c79 100644
--- a/fpga/output/bypass.rpd.gz
+++ b/fpga/output/bypass.rpd.gz
Binary files differ
diff --git a/fpga/output/bypass.sof b/fpga/output/bypass.sof
index 0f86bd8..a954505 100644
--- a/fpga/output/bypass.sof
+++ b/fpga/output/bypass.sof
Binary files differ
diff --git a/fpga/output/bypass.svf.gz b/fpga/output/bypass.svf.gz
index ed98b70..df1e87a 100644
--- a/fpga/output/bypass.svf.gz
+++ b/fpga/output/bypass.svf.gz
Binary files differ
diff --git a/fpga/output/bypass.xsvf.gz b/fpga/output/bypass.xsvf.gz
index 27f3de9..83a9710 100644
--- a/fpga/output/bypass.xsvf.gz
+++ b/fpga/output/bypass.xsvf.gz
Binary files differ
diff --git a/fpga/output/v1.fw b/fpga/output/v1.fw
index 962c028..15967d1 100644
--- a/fpga/output/v1.fw
+++ b/fpga/output/v1.fw
Binary files differ
diff --git a/fpga/output/v1.jic b/fpga/output/v1.jic
index 958f9a2..7289428 100644
--- a/fpga/output/v1.jic
+++ b/fpga/output/v1.jic
Binary files differ
diff --git a/fpga/output/v1.rbf.gz b/fpga/output/v1.rbf.gz
index 003be8b..33a6018 100644
--- a/fpga/output/v1.rbf.gz
+++ b/fpga/output/v1.rbf.gz
Binary files differ
diff --git a/fpga/output/v1.rpd.gz b/fpga/output/v1.rpd.gz
index a16347a..a2533e5 100644
--- a/fpga/output/v1.rpd.gz
+++ b/fpga/output/v1.rpd.gz
Binary files differ
diff --git a/fpga/output/v1.sof b/fpga/output/v1.sof
index 07404a8..318c90b 100644
--- a/fpga/output/v1.sof
+++ b/fpga/output/v1.sof
Binary files differ
diff --git a/fpga/output/v1.svf.gz b/fpga/output/v1.svf.gz
index 07c8281..db08ba5 100644
--- a/fpga/output/v1.svf.gz
+++ b/fpga/output/v1.svf.gz
Binary files differ
diff --git a/fpga/output/v1.xsvf.gz b/fpga/output/v1.xsvf.gz
index fab29ee..b9da3f6 100644
--- a/fpga/output/v1.xsvf.gz
+++ b/fpga/output/v1.xsvf.gz
Binary files differ
diff --git a/fpga/output/v2.fw b/fpga/output/v2.fw
index 6fdb550..325de83 100644
--- a/fpga/output/v2.fw
+++ b/fpga/output/v2.fw
Binary files differ
diff --git a/fpga/output/v2.jic b/fpga/output/v2.jic
index 3810c87..9d1e745 100644
--- a/fpga/output/v2.jic
+++ b/fpga/output/v2.jic
Binary files differ
diff --git a/fpga/output/v2.rbf.gz b/fpga/output/v2.rbf.gz
index b223c7b..8f61102 100644
--- a/fpga/output/v2.rbf.gz
+++ b/fpga/output/v2.rbf.gz
Binary files differ
diff --git a/fpga/output/v2.rpd.gz b/fpga/output/v2.rpd.gz
index d97a24d..6fa13cb 100644
--- a/fpga/output/v2.rpd.gz
+++ b/fpga/output/v2.rpd.gz
Binary files differ
diff --git a/fpga/output/v2.sof b/fpga/output/v2.sof
index cf9a29b..1f91255 100644
--- a/fpga/output/v2.sof
+++ b/fpga/output/v2.sof
Binary files differ
diff --git a/fpga/output/v2.svf.gz b/fpga/output/v2.svf.gz
index 27215a2..542bb0d 100644
--- a/fpga/output/v2.svf.gz
+++ b/fpga/output/v2.svf.gz
Binary files differ
diff --git a/fpga/output/v2.xsvf.gz b/fpga/output/v2.xsvf.gz
index 117a76c..15d6975 100644
--- a/fpga/output/v2.xsvf.gz
+++ b/fpga/output/v2.xsvf.gz
Binary files differ