From ad8bafd9703a222f4c20a40a34c122378bb3f03e Mon Sep 17 00:00:00 2001
From: Sylvain Lefebvre <sylvain.lefebvre@inria.fr>
Date: Mon, 9 Oct 2023 09:53:28 +0200
Subject: [PATCH 1/3] Exit main loop upon error in fpga_download

---
 main/fpga_download.c         | 6 +++---
 main/include/fpga_download.h | 2 +-
 main/main.c                  | 3 ++-
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/main/fpga_download.c b/main/fpga_download.c
index 83a10f8..b9b061e 100644
--- a/main/fpga_download.c
+++ b/main/fpga_download.c
@@ -277,7 +277,7 @@ bool fpga_host(xQueueHandle buttonQueue, ICE40* ice40, bool enable_uart, const c
     }
 }
 
-void fpga_download(xQueueHandle buttonQueue, ICE40* ice40) {
+bool fpga_download(xQueueHandle buttonQueue, ICE40* ice40) {
     fpga_display_message(0x325aa8, 0xFFFFFFFF, "FPGA download mode\nPreparing...");
 
     ILI9341* ili9341 = get_ili9341();
@@ -315,12 +315,12 @@ void fpga_download(xQueueHandle buttonQueue, ICE40* ice40) {
         ili9341_init(ili9341);
     }
 
-    return;
+    return true;
 
 error:
     vTaskDelay(1000 / portTICK_PERIOD_MS);
     fpga_req_cleanup();
     fpga_irq_cleanup(ice40);
     fpga_uninstall_uart();
-    return;
+    return false;
 }
diff --git a/main/include/fpga_download.h b/main/include/fpga_download.h
index 0eda90c..8fade81 100644
--- a/main/include/fpga_download.h
+++ b/main/include/fpga_download.h
@@ -4,5 +4,5 @@
 
 #include "ice40.h"
 
-void fpga_download(xQueueHandle button_queue, ICE40* ice40);
+bool fpga_download(xQueueHandle button_queue, ICE40* ice40);
 bool fpga_host(xQueueHandle button_queue, ICE40* ice40, bool enable_uart, const char* prefix);
diff --git a/main/main.c b/main/main.c
index 141a54d..51ecb6e 100644
--- a/main/main.c
+++ b/main/main.c
@@ -434,7 +434,8 @@ void app_main(void) {
     } else if (webusb_mode == 0x02) {
         display_boot_screen("FPGA download mode");
         while (true) {
-            fpga_download(rp2040->queue, ice40);
+            bool ok = fpga_download(rp2040->queue, ice40);
+            if (!ok) break;
         }
     } else if (webusb_mode == 0x03) {
         webusb_new_main(rp2040->queue);

From 3ef8ad3644c12b57f06c5f1cdbc6ca99cd52116a Mon Sep 17 00:00:00 2001
From: Sylvain Lefebvre <sylvain.lefebvre@inria.fr>
Date: Mon, 9 Oct 2023 10:08:11 +0200
Subject: [PATCH 2/3] Add memory allocation failure check for data blocks in
 fpga_download

---
 main/fpga_download.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/main/fpga_download.c b/main/fpga_download.c
index b9b061e..7863a91 100644
--- a/main/fpga_download.c
+++ b/main/fpga_download.c
@@ -205,7 +205,11 @@ static bool fpga_uart_download(ICE40* ice40) {
 
             case 'D':
                 {  // Data block
-                    fpga_req_add_file_data(header.fid, buffer, header.len);
+                    int ret = fpga_req_add_file_data(header.fid, buffer, header.len);
+                    if (ret) {
+                        fpga_display_message(0xa85a32, 0xFFFFFFFF, "FPGA download mode\nUpload failed, out of memory");
+                        return false;
+                    }
                     break;
                 }
 

From 6c1fc8d78c24686e3fcb30dacaadf5af56eb4be4 Mon Sep 17 00:00:00 2001
From: Sylvain Lefebvre <sylvain.lefebvre@inria.fr>
Date: Mon, 9 Oct 2023 10:42:32 +0200
Subject: [PATCH 3/3] Allow data buffer to be captured in req list to avoid
 double allocation

---
 main/fpga_download.c     |  3 ++-
 main/fpga_util.c         | 26 +++++++++++++++++++-------
 main/include/fpga_util.h |  2 +-
 3 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/main/fpga_download.c b/main/fpga_download.c
index 7863a91..b34db3f 100644
--- a/main/fpga_download.c
+++ b/main/fpga_download.c
@@ -205,7 +205,8 @@ static bool fpga_uart_download(ICE40* ice40) {
 
             case 'D':
                 {  // Data block
-                    int ret = fpga_req_add_file_data(header.fid, buffer, header.len);
+                    int ret = fpga_req_add_file_data(header.fid, buffer, header.len, true);
+                    buffer  = NULL; // Buffer has been captured in req list
                     if (ret) {
                         fpga_display_message(0xa85a32, 0xFFFFFFFF, "FPGA download mode\nUpload failed, out of memory");
                         return false;
diff --git a/main/fpga_util.c b/main/fpga_util.c
index ef486f8..87c9c1c 100644
--- a/main/fpga_util.c
+++ b/main/fpga_util.c
@@ -341,6 +341,7 @@ struct req_entry {
     void    *data;
     size_t   len;
     size_t   ofs;
+    bool     external_data;
 };
 
 struct req_entry *g_req_entries;
@@ -361,6 +362,7 @@ static void _fpga_req_delete_entry(uint32_t fid) {
 
             // Release
             if (re->fh) fclose(re->fh);
+            if (re->external_data) free(re->data);
             free(re);
 
             // Done
@@ -468,6 +470,7 @@ void fpga_req_cleanup(void) {
     while (re_cur) {
         re_nxt = re_cur->next;
         if (re_cur->fh) fclose(re_cur->fh);
+        if (re_cur->external_data) free(re_cur->data);
         free(re_cur);
         re_cur = re_nxt;
     }
@@ -488,7 +491,7 @@ int fpga_req_add_file_alias(uint32_t fid, const char *path) {
     return 0;
 }
 
-int fpga_req_add_file_data(uint32_t fid, void *data, size_t len) {
+int fpga_req_add_file_data(uint32_t fid, void *data, size_t len,bool capture_buffer) {
     struct req_entry *re;
     void             *buf;
 
@@ -496,7 +499,11 @@ int fpga_req_add_file_data(uint32_t fid, void *data, size_t len) {
     _fpga_req_delete_entry(fid);
 
     // Alloc new entry
-    buf = malloc(sizeof(struct req_entry) + len);
+    if (capture_buffer) {
+        buf = malloc(sizeof(struct req_entry));
+    } else {
+        buf = malloc(sizeof(struct req_entry) + len);
+    }
     if (!buf) return -ENOMEM;
 
     re = buf;
@@ -508,12 +515,17 @@ int fpga_req_add_file_data(uint32_t fid, void *data, size_t len) {
 
     // Init fields
     re->fid  = fid;
-    re->data = buf + sizeof(struct req_entry);
     re->len  = len;
-
-    // Copy actual data
-    memcpy(re->data, data, len);
-
+    re->external_data = capture_buffer;
+    if (capture_buffer) {
+        // Set data pointer to external buffer
+        re->data = data;
+    } else {
+        // Set data pointer to after record
+        re->data = buf + sizeof(struct req_entry);
+        // Copy actual data
+        memcpy(re->data, data, len);
+    }
     // Done
     return 0;
 }
diff --git a/main/include/fpga_util.h b/main/include/fpga_util.h
index 302fa64..da2a81b 100644
--- a/main/include/fpga_util.h
+++ b/main/include/fpga_util.h
@@ -61,7 +61,7 @@ bool fpga_btn_forward_events(ICE40 *ice40, xQueueHandle buttonQueue, esp_err_t *
 void fpga_req_setup(void);
 void fpga_req_cleanup(void);
 int  fpga_req_add_file_alias(uint32_t fid, const char *path);
-int  fpga_req_add_file_data(uint32_t fid, void *data, size_t len);
+int  fpga_req_add_file_data(uint32_t fid, void *data, size_t len, bool capture_buffer);
 void fpga_req_del_file(uint32_t fid);
 
 bool fpga_req_process(const char *prefix, ICE40 *ice40, TickType_t wait, esp_err_t *err);