From 2589b176405ad5024f1f4d041efea5b179f152f6 Mon Sep 17 00:00:00 2001
From: MCUdude <hansibull@gmail.com>
Date: Thu, 17 Feb 2022 11:24:59 +0100
Subject: [PATCH 01/14] Add support for memory "fill" mode Syntax: write
 <memtype> <start addr> <no. byte to write> <byte to write> ...

---
 src/term.c | 48 +++++++++++++++++++++++++++++++++++++-----------
 src/term.h |  4 ++++
 2 files changed, 41 insertions(+), 11 deletions(-)

diff --git a/src/term.c b/src/term.c
index 5c91931c..295ae612 100644
--- a/src/term.c
+++ b/src/term.c
@@ -336,11 +336,13 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
   unsigned char b;
   int rc;
   int werror;
+  int write_mode;
   AVRMEM * mem;
 
   if (argc < 4) {
-    avrdude_message(MSG_INFO, "Usage: write <memtype> <addr> <byte1> "
-            "<byte2> ... <byteN>\n");
+    avrdude_message(MSG_INFO,
+      "Usage: write <memtype> <start addr> <data1> <data2> <dataN>\n"
+      "       write <memtype> <start addr> <no. bytes> <data1> <dataN> <...>\n");
     return -1;
   }
 
@@ -368,8 +370,19 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
     return -1;
   }
 
-  /* number of bytes to write at the specified address */
-  len = argc - 3;
+  // Figure out how many bytes to write to memory
+  if(strcmp(argv[5], "...") == 0) {
+    write_mode = WRITE_MODE_FILL;
+    len = strtoul(argv[3], &e, 0);
+    if (*e || (e == argv[3])) {
+      avrdude_message(MSG_INFO, "%s (write ...): can't parse address \"%s\"\n",
+            progname, argv[3]);
+      return -1;
+    }
+  } else {
+    write_mode = WRITE_MODE_STANDARD;
+    len = argc - 3;
+  }
 
   if ((addr + len) > maxsize) {
     avrdude_message(MSG_INFO, "%s (write): selected address and # bytes exceed "
@@ -384,13 +397,26 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
     return -1;
   }
 
-  for (i=3; i<argc; i++) {
-    buf[i-3] = strtoul(argv[i], &e, 0);
-    if (*e || (e == argv[i])) {
-      avrdude_message(MSG_INFO, "%s (write): can't parse byte \"%s\"\n",
-              progname, argv[i]);
-      free(buf);
-      return -1;
+  if(write_mode == WRITE_MODE_STANDARD) {
+    for (i=3; i<argc; i++) {
+      buf[i-3] = strtoul(argv[i], &e, 0);
+      if (*e || (e == argv[i])) {
+        avrdude_message(MSG_INFO, "%s (write): can't parse byte \"%s\"\n",
+                progname, argv[i]);
+        free(buf);
+        return -1;
+      }
+    }
+  } else if(write_mode == WRITE_MODE_FILL) {
+    unsigned char fill_val = strtoul(argv[4], &e, 0);
+    if (*e || (e == argv[4])) {
+        avrdude_message(MSG_INFO, "%s (write ...): can't parse byte \"%s\"\n",
+                progname, argv[4]);
+        free(buf);
+        return -1;
+    }
+    for (i = 0; i < len; i++) {
+      buf[i] = fill_val;
     }
   }
 
diff --git a/src/term.h b/src/term.h
index fca3aac8..fc5ad4f4 100644
--- a/src/term.h
+++ b/src/term.h
@@ -27,6 +27,10 @@
 extern "C" {
 #endif
 
+// Macros for determining write mode
+#define WRITE_MODE_STANDARD 0
+#define WRITE_MODE_FILL     1
+
 int terminal_mode(PROGRAMMER * pgm, struct avrpart * p);
 char * terminal_get_input(const char *prompt);
 

From c007dc7d2497835bd592ca13692e2248bd19c901 Mon Sep 17 00:00:00 2001
From: MCUdude <hansibull@gmail.com>
Date: Thu, 17 Feb 2022 11:55:05 +0100
Subject: [PATCH 02/14] Add support for writing single characters  Now this is
 possible: write eeprom 0x00 a b c d e f 0x80 0x90 ! H E L L O

---
 src/term.c | 27 +++++++++++++++++++--------
 1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/src/term.c b/src/term.c
index 295ae612..ce58c19c 100644
--- a/src/term.c
+++ b/src/term.c
@@ -399,21 +399,32 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
 
   if(write_mode == WRITE_MODE_STANDARD) {
     for (i=3; i<argc; i++) {
-      buf[i-3] = strtoul(argv[i], &e, 0);
+      unsigned char write_val = strtoul(argv[i], &e, 0);
       if (*e || (e == argv[i])) {
-        avrdude_message(MSG_INFO, "%s (write): can't parse byte \"%s\"\n",
-                progname, argv[i]);
-        free(buf);
-        return -1;
+        // If passed argument is a single character
+        if(argv[i][1] == '\0') {
+          write_val = argv[i][0];
+        } else {
+          avrdude_message(MSG_INFO, "%s (write): can't parse byte \"%s\"\n",
+                  progname, argv[i]);
+          free(buf);
+          return -1;
+        }
       }
+      buf[i-3] = write_val;
     }
   } else if(write_mode == WRITE_MODE_FILL) {
     unsigned char fill_val = strtoul(argv[4], &e, 0);
     if (*e || (e == argv[4])) {
-        avrdude_message(MSG_INFO, "%s (write ...): can't parse byte \"%s\"\n",
+        // If passed argument is a single character
+        if(argv[4][1] == '\0') {
+          fill_val = argv[4][0];
+        } else {
+          avrdude_message(MSG_INFO, "%s (write ...): can't parse byte \"%s\"\n",
                 progname, argv[4]);
-        free(buf);
-        return -1;
+          free(buf);
+          return -1;
+        }
     }
     for (i = 0; i < len; i++) {
       buf[i] = fill_val;

From 2a92b8cce42c73e51681df1a786937f17a66b74e Mon Sep 17 00:00:00 2001
From: MCUdude <hansibull@gmail.com>
Date: Thu, 17 Feb 2022 13:00:30 +0100
Subject: [PATCH 03/14] Add support for memory "fill" with arbitrary data too
 If you run the following command: $ write eeprom 0x00 0x10 A B C ...

It will write the following data to EEPROM:
|ABCCCCCCCCCCCCCC|
starting from address 0x00
---
 src/term.c | 62 +++++++++++++++++++++++++-----------------------------
 1 file changed, 29 insertions(+), 33 deletions(-)

diff --git a/src/term.c b/src/term.c
index ce58c19c..fc2e5d3c 100644
--- a/src/term.c
+++ b/src/term.c
@@ -336,7 +336,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
   unsigned char b;
   int rc;
   int werror;
-  int write_mode;
+  int write_mode, start_offset;
   AVRMEM * mem;
 
   if (argc < 4) {
@@ -370,8 +370,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
     return -1;
   }
 
-  // Figure out how many bytes to write to memory
-  if(strcmp(argv[5], "...") == 0) {
+  // Figure out how many bytes there is to write to memory
+  if(strcmp(argv[argc - 1], "...") == 0) {
     write_mode = WRITE_MODE_FILL;
     len = strtoul(argv[3], &e, 0);
     if (*e || (e == argv[3])) {
@@ -397,38 +397,34 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
     return -1;
   }
 
-  if(write_mode == WRITE_MODE_STANDARD) {
-    for (i=3; i<argc; i++) {
-      unsigned char write_val = strtoul(argv[i], &e, 0);
-      if (*e || (e == argv[i])) {
-        // If passed argument is a single character
-        if(argv[i][1] == '\0') {
-          write_val = argv[i][0];
-        } else {
-          avrdude_message(MSG_INFO, "%s (write): can't parse byte \"%s\"\n",
-                  progname, argv[i]);
-          free(buf);
-          return -1;
-        }
+  if (write_mode == WRITE_MODE_STANDARD)
+    start_offset = 3; // Data to write from argument no. 3
+  else if (write_mode == WRITE_MODE_FILL)
+    start_offset = 4;
+  else {
+    avrdude_message(MSG_INFO, "%s (write): invalid write mode %d\n",
+                    progname, write_mode);
+    return -1;
+  }
+
+  unsigned char write_val;
+  for (i = start_offset; i < argc - start_offset + 3; i++) {
+    write_val = strtoul(argv[i], &e, 0);
+    if (*e || (e == argv[i])) {
+      // Accept if passed argument is a single character
+      if (argv[i][1] == '\0') {
+        write_val = argv[i][0];
+      } else {
+        avrdude_message(MSG_INFO, "%s (write ...): can't parse byte \"%s\"\n",
+              progname, argv[i]);
+        free(buf);
+        return -1;
       }
-      buf[i-3] = write_val;
-    }
-  } else if(write_mode == WRITE_MODE_FILL) {
-    unsigned char fill_val = strtoul(argv[4], &e, 0);
-    if (*e || (e == argv[4])) {
-        // If passed argument is a single character
-        if(argv[4][1] == '\0') {
-          fill_val = argv[4][0];
-        } else {
-          avrdude_message(MSG_INFO, "%s (write ...): can't parse byte \"%s\"\n",
-                progname, argv[4]);
-          free(buf);
-          return -1;
-        }
-    }
-    for (i = 0; i < len; i++) {
-      buf[i] = fill_val;
     }
+    buf[i - start_offset] = write_val;
+  }
+  for (; i < len + start_offset; i++) {
+    buf[i - start_offset] = write_val;
   }
 
   pgm->err_led(pgm, OFF);

From 551046052e866163c14d5337f108a2afbf861b66 Mon Sep 17 00:00:00 2001
From: MCUdude <hansibull@gmail.com>
Date: Thu, 17 Feb 2022 22:40:26 +0100
Subject: [PATCH 04/14] Add support for writing floats

---
 src/term.c | 79 +++++++++++++++++++++++++++++++++---------------------
 1 file changed, 49 insertions(+), 30 deletions(-)

diff --git a/src/term.c b/src/term.c
index fc2e5d3c..4adb36b3 100644
--- a/src/term.c
+++ b/src/term.c
@@ -371,7 +371,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
   }
 
   // Figure out how many bytes there is to write to memory
-  if(strcmp(argv[argc - 1], "...") == 0) {
+  if (strcmp(argv[argc - 1], "...") == 0) {
     write_mode = WRITE_MODE_FILL;
     len = strtoul(argv[3], &e, 0);
     if (*e || (e == argv[3])) {
@@ -381,25 +381,18 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
     }
   } else {
     write_mode = WRITE_MODE_STANDARD;
-    len = argc - 3;
   }
 
-  if ((addr + len) > maxsize) {
-    avrdude_message(MSG_INFO, "%s (write): selected address and # bytes exceed "
-                    "range for %s memory\n",
-                    progname, memtype);
-    return -1;
-  }
-
-  buf = malloc(len);
+  buf = malloc(mem->size);
   if (buf == NULL) {
     avrdude_message(MSG_INFO, "%s (write): out of memory\n", progname);
     return -1;
   }
 
-  if (write_mode == WRITE_MODE_STANDARD)
-    start_offset = 3; // Data to write from argument no. 3
-  else if (write_mode == WRITE_MODE_FILL)
+  if (write_mode == WRITE_MODE_STANDARD) {
+    start_offset = 3; // Argument number where data to write starts
+    len = argc - start_offset;
+  } else if (write_mode == WRITE_MODE_FILL)
     start_offset = 4;
   else {
     avrdude_message(MSG_INFO, "%s (write): invalid write mode %d\n",
@@ -407,29 +400,55 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
     return -1;
   }
 
-  unsigned char write_val;
-  for (i = start_offset; i < argc - start_offset + 3; i++) {
-    write_val = strtoul(argv[i], &e, 0);
-    if (*e || (e == argv[i])) {
-      // Accept if passed argument is a single character
-      if (argv[i][1] == '\0') {
-        write_val = argv[i][0];
-      } else {
-        avrdude_message(MSG_INFO, "%s (write ...): can't parse byte \"%s\"\n",
-              progname, argv[i]);
-        free(buf);
-        return -1;
+  long write_val;
+  int bytes_grown = 0;
+  for (i = start_offset; i < len + start_offset - bytes_grown; i++) {
+    char* ptr = NULL;
+    // Handle the next argument
+    if (i < argc - start_offset + 3) {
+      // Try integers
+      write_val = strtol(argv[i], &e, 0);
+      if (*e || (e == argv[i])) {
+        // Try float
+        float f = strtof(argv[i], &e);
+        ptr = (char*)&f;
+        write_val = ((char)*(ptr+3)<<24) + ((char)*(ptr+2)<<16) + ((char)*(ptr+1)<<8) + (char)*ptr;
+        if (*e || (e == argv[i])) {
+          ptr = NULL;
+          // Try single character
+          if (argv[i][1] == '\0') {
+            write_val = argv[i][0];
+          } else {
+            avrdude_message(MSG_INFO, "%s (write): can't parse data \"%s\"\n",
+                  progname, argv[i]);
+            free(buf);
+            return -1;
+          }
+        }
       }
     }
-    buf[i - start_offset] = write_val;
+    buf[i - start_offset + bytes_grown]     = (write_val >> 0) & 0xFF;
+    if (write_val > 0xFF || ptr)
+      buf[i - start_offset + ++bytes_grown] = (write_val >> 8) & 0xFF;
+    if (write_val > 0xFFFF || ptr) {
+      buf[i - start_offset + ++bytes_grown] = (write_val >> 16) & 0xFF;
+      buf[i - start_offset + ++bytes_grown] = (write_val >> 24) & 0xFF;
+    }
   }
-  for (; i < len + start_offset; i++) {
-    buf[i - start_offset] = write_val;
+
+  // When in "fill" mode, the maximum size is already predefined
+  if (write_mode == WRITE_MODE_FILL)
+    bytes_grown = 0;
+
+  if ((addr + len + bytes_grown) > maxsize) {
+    avrdude_message(MSG_INFO, "%s (write): selected address and # bytes exceed "
+                    "range for %s memory\n",
+                    progname, memtype);
+    return -1;
   }
 
   pgm->err_led(pgm, OFF);
-  for (werror=0, i=0; i<len; i++) {
-
+  for (werror=0, i=0; i < (len + bytes_grown); i++) {
     rc = avr_write_byte(pgm, p, mem, addr+i, buf[i]);
     if (rc) {
       avrdude_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx, rc=%d\n",

From 10e05eed21a8a0b3120bf347a7211e86af4e0fc9 Mon Sep 17 00:00:00 2001
From: MCUdude <hansibull@gmail.com>
Date: Thu, 17 Feb 2022 22:43:23 +0100
Subject: [PATCH 05/14] Require single quotes when writing characters

---
 src/term.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/term.c b/src/term.c
index 4adb36b3..1d0bca98 100644
--- a/src/term.c
+++ b/src/term.c
@@ -416,8 +416,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
         if (*e || (e == argv[i])) {
           ptr = NULL;
           // Try single character
-          if (argv[i][1] == '\0') {
-            write_val = argv[i][0];
+          if (argv[i][0] == '\'' && argv[i][2] == '\'') {
+            write_val = argv[i][1];
           } else {
             avrdude_message(MSG_INFO, "%s (write): can't parse data \"%s\"\n",
                   progname, argv[i]);

From 6e7f38e81fcf47545a4cde9f1e15f6b35c47a014 Mon Sep 17 00:00:00 2001
From: MCUdude <hansibull@gmail.com>
Date: Fri, 18 Feb 2022 08:33:09 +0100
Subject: [PATCH 06/14] Properly handle negative numbers Now -3.141592 and
 -32768 are valid numbers that's stored correctly in memory

---
 src/term.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/term.c b/src/term.c
index 1d0bca98..84c9e243 100644
--- a/src/term.c
+++ b/src/term.c
@@ -428,9 +428,9 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
       }
     }
     buf[i - start_offset + bytes_grown]     = (write_val >> 0) & 0xFF;
-    if (write_val > 0xFF || ptr)
+    if (labs(write_val) > 0xFF || ptr)
       buf[i - start_offset + ++bytes_grown] = (write_val >> 8) & 0xFF;
-    if (write_val > 0xFFFF || ptr) {
+    if (labs(write_val) > 0xFFFF || ptr) {
       buf[i - start_offset + ++bytes_grown] = (write_val >> 16) & 0xFF;
       buf[i - start_offset + ++bytes_grown] = (write_val >> 24) & 0xFF;
     }

From 62f3b84eee869015f690fa06cb3dfffba58270ab Mon Sep 17 00:00:00 2001
From: MCUdude <hansibull@gmail.com>
Date: Sat, 19 Feb 2022 20:15:52 +0100
Subject: [PATCH 07/14] Use union for simpler data representation It is a bit
 hacky, but for this purpose it fits surprisingly well

---
 src/term.c | 36 +++++++++++++++++++++---------------
 1 file changed, 21 insertions(+), 15 deletions(-)

diff --git a/src/term.c b/src/term.c
index 84c9e243..4b363bf1 100644
--- a/src/term.c
+++ b/src/term.c
@@ -23,6 +23,7 @@
 #include <ctype.h>
 #include <string.h>
 #include <stdio.h>
+//#include <stdint.h>
 #include <stdlib.h>
 #include <limits.h>
 
@@ -400,24 +401,29 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
     return -1;
   }
 
-  long write_val;
-  int bytes_grown = 0;
+  // Union to represent the data to write to memory
+  union Data {
+    float f;
+    int32_t i;
+    uint8_t a[4];
+  } data;
+
+  int32_t bytes_grown = 0;
   for (i = start_offset; i < len + start_offset - bytes_grown; i++) {
-    char* ptr = NULL;
+    bool is_float = false;
     // Handle the next argument
     if (i < argc - start_offset + 3) {
       // Try integers
-      write_val = strtol(argv[i], &e, 0);
+      data.i = strtol(argv[i], &e, 0);
       if (*e || (e == argv[i])) {
         // Try float
-        float f = strtof(argv[i], &e);
-        ptr = (char*)&f;
-        write_val = ((char)*(ptr+3)<<24) + ((char)*(ptr+2)<<16) + ((char)*(ptr+1)<<8) + (char)*ptr;
+        data.f = strtof(argv[i], &e);
+        is_float = true;
         if (*e || (e == argv[i])) {
-          ptr = NULL;
+          is_float = false;
           // Try single character
           if (argv[i][0] == '\'' && argv[i][2] == '\'') {
-            write_val = argv[i][1];
+            data.i = argv[i][1];
           } else {
             avrdude_message(MSG_INFO, "%s (write): can't parse data \"%s\"\n",
                   progname, argv[i]);
@@ -427,12 +433,12 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
         }
       }
     }
-    buf[i - start_offset + bytes_grown]     = (write_val >> 0) & 0xFF;
-    if (labs(write_val) > 0xFF || ptr)
-      buf[i - start_offset + ++bytes_grown] = (write_val >> 8) & 0xFF;
-    if (labs(write_val) > 0xFFFF || ptr) {
-      buf[i - start_offset + ++bytes_grown] = (write_val >> 16) & 0xFF;
-      buf[i - start_offset + ++bytes_grown] = (write_val >> 24) & 0xFF;
+    buf[i - start_offset + bytes_grown]     = data.a[0];
+    if (labs(data.i) > 0xFF || is_float)
+      buf[i - start_offset + ++bytes_grown] = data.a[1];
+    if (labs(data.i) > 0xFFFF || is_float) {
+      buf[i - start_offset + ++bytes_grown] = data.a[2];
+      buf[i - start_offset + ++bytes_grown] = data.a[3];
     }
   }
 

From 4b9219edee62165e4722d23f91e9e74812f52ffa Mon Sep 17 00:00:00 2001
From: MCUdude <hansibull@gmail.com>
Date: Sat, 19 Feb 2022 22:48:58 +0100
Subject: [PATCH 08/14] Add support for suffixes for manually specifying data
 size  H/h/S/s: 16-bit, L/l: 32-bit, F/f: 32-bit float

---
 src/term.c | 36 +++++++++++++++++++++++++++++++-----
 1 file changed, 31 insertions(+), 5 deletions(-)

diff --git a/src/term.c b/src/term.c
index 4b363bf1..36849da9 100644
--- a/src/term.c
+++ b/src/term.c
@@ -343,7 +343,9 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
   if (argc < 4) {
     avrdude_message(MSG_INFO,
       "Usage: write <memtype> <start addr> <data1> <data2> <dataN>\n"
-      "       write <memtype> <start addr> <no. bytes> <data1> <dataN> <...>\n");
+      "       write <memtype> <start addr> <no. bytes> <data1> <dataN> <...>\n\n"
+      "       Add a suffix to manually specify the size for each field:\n"
+      "       H/h/S/s: 16-bit, L/l: 32-bit, F/f: 32-bit float\n");
     return -1;
   }
 
@@ -411,8 +413,22 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
   int32_t bytes_grown = 0;
   for (i = start_offset; i < len + start_offset - bytes_grown; i++) {
     bool is_float = false;
+    uint8_t data_length = 0;
+
     // Handle the next argument
     if (i < argc - start_offset + 3) {
+      // Get suffix if present
+      char suffix = argv[i][strlen(argv[i]) - 1];
+      if ((suffix == 'F' || suffix == 'f' || suffix == 'L' || suffix == 'l') && \
+          strncmp(argv[i], "0x", 2) != 0) {
+        argv[i][strlen(argv[i]) - 1] = '\0';
+        data_length = 4;
+      } else if (suffix == 'H' || suffix == 'h' || suffix == 'S' || suffix == 's') {
+        argv[i][strlen(argv[i]) - 1] = '\0';
+        data_length = 2;
+      } else if (suffix == '\'') {
+        data_length = 1;
+      } 
       // Try integers
       data.i = strtol(argv[i], &e, 0);
       if (*e || (e == argv[i])) {
@@ -422,21 +438,31 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
         if (*e || (e == argv[i])) {
           is_float = false;
           // Try single character
-          if (argv[i][0] == '\'' && argv[i][2] == '\'') {
+          if (argv[i][0] == '\'') {
             data.i = argv[i][1];
           } else {
-            avrdude_message(MSG_INFO, "%s (write): can't parse data \"%s\"\n",
+            avrdude_message(MSG_INFO, "\n%s (write): can't parse data \"%s\"\n",
                   progname, argv[i]);
             free(buf);
             return -1;
           }
         }
       }
+      // Print warning if data size might be ambiguous
+      if(!data_length && \
+        (((strncmp(argv[i], "0x", 2) == 0) && strlen(argv[i]) > 3) || \
+        (data.i > 0xFF && strlen(argv[i]) > 2))) {
+        avrdude_message(MSG_INFO, "Warning: no size suffix specified for \"%s\". "
+                                  "Writing %d bytes\n",
+                                  argv[i],
+                                  is_float || labs(data.i) > 0xFFFF ? 4 : \
+                                  labs(data.i) > 0x00FF ? 2 : 1);
+      }
     }
     buf[i - start_offset + bytes_grown]     = data.a[0];
-    if (labs(data.i) > 0xFF || is_float)
+    if (is_float || labs(data.i) > 0x00FF || data_length >= 2)
       buf[i - start_offset + ++bytes_grown] = data.a[1];
-    if (labs(data.i) > 0xFFFF || is_float) {
+    if (is_float || labs(data.i) > 0xFFFF || data_length >= 4) {
       buf[i - start_offset + ++bytes_grown] = data.a[2];
       buf[i - start_offset + ++bytes_grown] = data.a[3];
     }

From 0e29b43bd0c06840425a82910f392468ecc68ccd Mon Sep 17 00:00:00 2001
From: MCUdude <hansibull@gmail.com>
Date: Sat, 19 Feb 2022 23:34:50 +0100
Subject: [PATCH 09/14] Add support for 64-bit integers Also, move everything
 data related into a struct, to keep tings a little more organized

---
 src/term.c | 90 +++++++++++++++++++++++++++++++++---------------------
 1 file changed, 55 insertions(+), 35 deletions(-)

diff --git a/src/term.c b/src/term.c
index 36849da9..77da4a4d 100644
--- a/src/term.c
+++ b/src/term.c
@@ -332,7 +332,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
   char * e;
   int len, maxsize;
   char * memtype;
-  unsigned long addr, i;
+  long addr;
+  long i;
   unsigned char * buf;
   unsigned char b;
   int rc;
@@ -345,7 +346,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
       "Usage: write <memtype> <start addr> <data1> <data2> <dataN>\n"
       "       write <memtype> <start addr> <no. bytes> <data1> <dataN> <...>\n\n"
       "       Add a suffix to manually specify the size for each field:\n"
-      "       H/h/S/s: 16-bit, L/l: 32-bit, F/f: 32-bit float\n");
+      "       H/h/S/s: 16-bit, L/l: 32-bit, LL/ll: 6-bit, F/f: 32-bit float\n");
     return -1;
   }
 
@@ -403,43 +404,55 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
     return -1;
   }
 
-  // Union to represent the data to write to memory
-  union Data {
-    float f;
-    int32_t i;
-    uint8_t a[4];
+  // Structure related to data that is being written to memory
+  struct Data {
+    // Data info
+    int32_t bytes_grown;
+    uint8_t size;
+    bool is_float;
+    // Data union
+    union {
+      float f;
+      int64_t ll;
+      uint8_t a[8];
+    };
   } data;
 
-  int32_t bytes_grown = 0;
-  for (i = start_offset; i < len + start_offset - bytes_grown; i++) {
-    bool is_float = false;
-    uint8_t data_length = 0;
+  for (i = start_offset; i < len + start_offset - data.bytes_grown; i++) {
+    data.is_float = false;
+    data.size = 0;
 
     // Handle the next argument
     if (i < argc - start_offset + 3) {
       // Get suffix if present
-      char suffix = argv[i][strlen(argv[i]) - 1];
-      if ((suffix == 'F' || suffix == 'f' || suffix == 'L' || suffix == 'l') && \
-          strncmp(argv[i], "0x", 2) != 0) {
+      char suffix  = argv[i][strlen(argv[i]) - 1];
+      char lsuffix = argv[i][strlen(argv[i]) - 2];
+      if ((suffix == 'L' && lsuffix == 'L') || (suffix == 'l' && lsuffix == 'l')) {
+        argv[i][strlen(argv[i]) - 2] = '\0';
+        data.size = 8;
+      } else if (suffix == 'L' || suffix == 'l') {
         argv[i][strlen(argv[i]) - 1] = '\0';
-        data_length = 4;
+        data.size = 4;
+      } else if ((suffix == 'F' || suffix == 'f') && strncmp(argv[i], "0x", 2) != 0) {
+        argv[i][strlen(argv[i]) - 1] = '\0';
+        data.size = 4;
       } else if (suffix == 'H' || suffix == 'h' || suffix == 'S' || suffix == 's') {
         argv[i][strlen(argv[i]) - 1] = '\0';
-        data_length = 2;
+        data.size = 2;
       } else if (suffix == '\'') {
-        data_length = 1;
-      } 
+        data.size = 1;
+      }
       // Try integers
-      data.i = strtol(argv[i], &e, 0);
+      data.ll = strtoll(argv[i], &e, 0);
       if (*e || (e == argv[i])) {
         // Try float
         data.f = strtof(argv[i], &e);
-        is_float = true;
+        data.is_float = true;
         if (*e || (e == argv[i])) {
-          is_float = false;
+          data.is_float = false;
           // Try single character
           if (argv[i][0] == '\'') {
-            data.i = argv[i][1];
+            data.ll = argv[i][1];
           } else {
             avrdude_message(MSG_INFO, "\n%s (write): can't parse data \"%s\"\n",
                   progname, argv[i]);
@@ -449,30 +462,37 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
         }
       }
       // Print warning if data size might be ambiguous
-      if(!data_length && \
+      if(!data.size && \
         (((strncmp(argv[i], "0x", 2) == 0) && strlen(argv[i]) > 3) || \
-        (data.i > 0xFF && strlen(argv[i]) > 2))) {
+        (data.ll > 0xFF && strlen(argv[i]) > 2))) {
         avrdude_message(MSG_INFO, "Warning: no size suffix specified for \"%s\". "
                                   "Writing %d bytes\n",
                                   argv[i],
-                                  is_float || labs(data.i) > 0xFFFF ? 4 : \
-                                  labs(data.i) > 0x00FF ? 2 : 1);
+                                  llabs(data.ll) > 0xFFFFFFFF ? 8 :
+                                  llabs(data.ll) > 0x0000FFFF || data.is_float ? 4 : \
+                                  llabs(data.ll) > 0x000000FF ? 2 : 1);
       }
     }
-    buf[i - start_offset + bytes_grown]     = data.a[0];
-    if (is_float || labs(data.i) > 0x00FF || data_length >= 2)
-      buf[i - start_offset + ++bytes_grown] = data.a[1];
-    if (is_float || labs(data.i) > 0xFFFF || data_length >= 4) {
-      buf[i - start_offset + ++bytes_grown] = data.a[2];
-      buf[i - start_offset + ++bytes_grown] = data.a[3];
+    buf[i - start_offset + data.bytes_grown]     = data.a[0];
+    if (llabs(data.ll) > 0x000000FF || data.size >= 2 || data.is_float)
+      buf[i - start_offset + ++data.bytes_grown] = data.a[1];
+    if (llabs(data.ll) > 0x0000FFFF || data.size >= 4 || data.is_float) {
+      buf[i - start_offset + ++data.bytes_grown] = data.a[2];
+      buf[i - start_offset + ++data.bytes_grown] = data.a[3];
+    }
+    if (llabs(data.ll) > 0xFFFFFFFF || data.size == 8) {
+      buf[i - start_offset + ++data.bytes_grown] = data.a[4];
+      buf[i - start_offset + ++data.bytes_grown] = data.a[5];
+      buf[i - start_offset + ++data.bytes_grown] = data.a[6];
+      buf[i - start_offset + ++data.bytes_grown] = data.a[7];
     }
   }
 
   // When in "fill" mode, the maximum size is already predefined
   if (write_mode == WRITE_MODE_FILL)
-    bytes_grown = 0;
+    data.bytes_grown = 0;
 
-  if ((addr + len + bytes_grown) > maxsize) {
+  if ((addr + len + data.bytes_grown) > maxsize) {
     avrdude_message(MSG_INFO, "%s (write): selected address and # bytes exceed "
                     "range for %s memory\n",
                     progname, memtype);
@@ -480,7 +500,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
   }
 
   pgm->err_led(pgm, OFF);
-  for (werror=0, i=0; i < (len + bytes_grown); i++) {
+  for (werror=0, i=0; i < (len + data.bytes_grown); i++) {
     rc = avr_write_byte(pgm, p, mem, addr+i, buf[i]);
     if (rc) {
       avrdude_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx, rc=%d\n",

From a9b756e5c7595126c3babacf016f3a606d7e0d69 Mon Sep 17 00:00:00 2001
From: MCUdude <hansibull@gmail.com>
Date: Sun, 20 Feb 2022 12:46:53 +0100
Subject: [PATCH 10/14] Add struct initialization list

---
 src/term.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/term.c b/src/term.c
index 77da4a4d..cb92e1ca 100644
--- a/src/term.c
+++ b/src/term.c
@@ -416,7 +416,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
       int64_t ll;
       uint8_t a[8];
     };
-  } data;
+  } data = {.bytes_grown = 0, .size = 0, .is_float = false, .ll = 0};
 
   for (i = start_offset; i < len + start_offset - data.bytes_grown; i++) {
     data.is_float = false;

From bb99a36a146e9af2c6ef2c46dda020f6353b8d35 Mon Sep 17 00:00:00 2001
From: MCUdude <hansibull@gmail.com>
Date: Sun, 20 Feb 2022 19:08:30 +0100
Subject: [PATCH 11/14] Formatting Use enums for write mode, and change
 datatypes from int/long/char to int32_t/uint8_t where possible

---
 src/term.c | 58 ++++++++++++++++++++++++------------------------------
 src/term.h |  7 ++++---
 2 files changed, 30 insertions(+), 35 deletions(-)

diff --git a/src/term.c b/src/term.c
index cb92e1ca..773f6d35 100644
--- a/src/term.c
+++ b/src/term.c
@@ -23,7 +23,7 @@
 #include <ctype.h>
 #include <string.h>
 #include <stdio.h>
-//#include <stdint.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <limits.h>
 
@@ -329,18 +329,6 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p,
 static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
 		     int argc, char * argv[])
 {
-  char * e;
-  int len, maxsize;
-  char * memtype;
-  long addr;
-  long i;
-  unsigned char * buf;
-  unsigned char b;
-  int rc;
-  int werror;
-  int write_mode, start_offset;
-  AVRMEM * mem;
-
   if (argc < 4) {
     avrdude_message(MSG_INFO,
       "Usage: write <memtype> <start addr> <data1> <data2> <dataN>\n"
@@ -350,19 +338,22 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
     return -1;
   }
 
-  memtype = argv[1];
-
-  mem = avr_locate_mem(p, memtype);
+  int32_t i;
+  uint8_t write_mode;       // Operation mode, "standard" or "fill"
+  uint8_t start_offset;     // Which argc argument
+  int32_t len;              // Number of bytes to write to memory
+  char * memtype = argv[1]; // Memory name string
+  AVRMEM * mem = avr_locate_mem(p, memtype);
   if (mem == NULL) {
     avrdude_message(MSG_INFO, "\"%s\" memory type not defined for part \"%s\"\n",
             memtype, p->desc);
     return -1;
   }
+  uint32_t maxsize = mem->size;
 
-  maxsize = mem->size;
-
-  addr = strtoul(argv[2], &e, 0);
-  if (*e || (e == argv[2])) {
+  char * end_ptr;
+  int32_t addr = strtoul(argv[2], &end_ptr, 0);
+  if (*end_ptr || (end_ptr == argv[2])) {
     avrdude_message(MSG_INFO, "%s (write): can't parse address \"%s\"\n",
             progname, argv[2]);
     return -1;
@@ -377,8 +368,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
   // Figure out how many bytes there is to write to memory
   if (strcmp(argv[argc - 1], "...") == 0) {
     write_mode = WRITE_MODE_FILL;
-    len = strtoul(argv[3], &e, 0);
-    if (*e || (e == argv[3])) {
+    len = strtoul(argv[3], &end_ptr, 0);
+    if (*end_ptr || (end_ptr == argv[3])) {
       avrdude_message(MSG_INFO, "%s (write ...): can't parse address \"%s\"\n",
             progname, argv[3]);
       return -1;
@@ -387,7 +378,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
     write_mode = WRITE_MODE_STANDARD;
   }
 
-  buf = malloc(mem->size);
+  uint8_t * buf = malloc(mem->size);
   if (buf == NULL) {
     avrdude_message(MSG_INFO, "%s (write): out of memory\n", progname);
     return -1;
@@ -442,13 +433,14 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
       } else if (suffix == '\'') {
         data.size = 1;
       }
+
       // Try integers
-      data.ll = strtoll(argv[i], &e, 0);
-      if (*e || (e == argv[i])) {
+      data.ll = strtoll(argv[i], &end_ptr, 0);
+      if (*end_ptr || (end_ptr == argv[i])) {
         // Try float
-        data.f = strtof(argv[i], &e);
+        data.f = strtof(argv[i], &end_ptr);
         data.is_float = true;
-        if (*e || (e == argv[i])) {
+        if (*end_ptr || (end_ptr == argv[i])) {
           data.is_float = false;
           // Try single character
           if (argv[i][0] == '\'') {
@@ -466,7 +458,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
         (((strncmp(argv[i], "0x", 2) == 0) && strlen(argv[i]) > 3) || \
         (data.ll > 0xFF && strlen(argv[i]) > 2))) {
         avrdude_message(MSG_INFO, "Warning: no size suffix specified for \"%s\". "
-                                  "Writing %d bytes\n",
+                                  "Writing %d byte(s)\n",
                                   argv[i],
                                   llabs(data.ll) > 0xFFFFFFFF ? 8 :
                                   llabs(data.ll) > 0x0000FFFF || data.is_float ? 4 : \
@@ -500,22 +492,24 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
   }
 
   pgm->err_led(pgm, OFF);
-  for (werror=0, i=0; i < (len + data.bytes_grown); i++) {
-    rc = avr_write_byte(pgm, p, mem, addr+i, buf[i]);
+  bool werror = false;
+  for (i = 0; i < (len + data.bytes_grown); i++) {
+    int32_t rc = avr_write_byte(pgm, p, mem, addr+i, buf[i]);
     if (rc) {
       avrdude_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx, rc=%d\n",
               progname, buf[i], addr+i, rc);
       if (rc == -1)
         avrdude_message(MSG_INFO, "write operation not supported on memory type \"%s\"\n",
                         mem->desc);
-      werror = 1;
+      werror = true;
     }
 
+    uint8_t b;
     rc = pgm->read_byte(pgm, p, mem, addr+i, &b);
     if (b != buf[i]) {
       avrdude_message(MSG_INFO, "%s (write): error writing 0x%02x at 0x%05lx cell=0x%02x\n",
                       progname, buf[i], addr+i, b);
-      werror = 1;
+      werror = true;
     }
 
     if (werror) {
diff --git a/src/term.h b/src/term.h
index fc5ad4f4..f114d4b0 100644
--- a/src/term.h
+++ b/src/term.h
@@ -27,9 +27,10 @@
 extern "C" {
 #endif
 
-// Macros for determining write mode
-#define WRITE_MODE_STANDARD 0
-#define WRITE_MODE_FILL     1
+typedef enum {
+  WRITE_MODE_STANDARD = 0,
+  WRITE_MODE_FILL     = 1,
+} mode;
 
 int terminal_mode(PROGRAMMER * pgm, struct avrpart * p);
 char * terminal_get_input(const char *prompt);

From 3532c567ac68524ae35bc0effb3f5f76bb115a75 Mon Sep 17 00:00:00 2001
From: MCUdude <hansibull@gmail.com>
Date: Sun, 20 Feb 2022 22:23:15 +0100
Subject: [PATCH 12/14] Add suffix for 8-bit data use [val]HH or [val]hh to
 force 8-bit writes to memory

---
 src/term.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/term.c b/src/term.c
index 773f6d35..2129643e 100644
--- a/src/term.c
+++ b/src/term.c
@@ -424,9 +424,14 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
       } else if (suffix == 'L' || suffix == 'l') {
         argv[i][strlen(argv[i]) - 1] = '\0';
         data.size = 4;
-      } else if ((suffix == 'F' || suffix == 'f') && strncmp(argv[i], "0x", 2) != 0) {
+      } else if ((suffix == 'F' || suffix == 'f') &&
+          strncmp(argv[i], "0x", 2) != 0 && strncmp(argv[i], "-0x", 3) != 0) {
         argv[i][strlen(argv[i]) - 1] = '\0';
+        avrdude_message(MSG_INFO, "snip\n");
         data.size = 4;
+      } else if ((suffix == 'H' && lsuffix == 'H') || (suffix == 'h' && lsuffix == 'h')) {
+        argv[i][strlen(argv[i]) - 2] = '\0';
+        data.size = 1;
       } else if (suffix == 'H' || suffix == 'h' || suffix == 'S' || suffix == 's') {
         argv[i][strlen(argv[i]) - 1] = '\0';
         data.size = 2;

From fa706f0d0139926c34125ddac6e8d7ee82c5377b Mon Sep 17 00:00:00 2001
From: MCUdude <hansibull@gmail.com>
Date: Sun, 20 Feb 2022 22:39:04 +0100
Subject: [PATCH 13/14] Handle data size warning better Now it only outputs a
 warning when the size of the data the user input is actually ambiguous

---
 src/term.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/src/term.c b/src/term.c
index 2129643e..407d77f2 100644
--- a/src/term.c
+++ b/src/term.c
@@ -427,7 +427,6 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
       } else if ((suffix == 'F' || suffix == 'f') &&
           strncmp(argv[i], "0x", 2) != 0 && strncmp(argv[i], "-0x", 3) != 0) {
         argv[i][strlen(argv[i]) - 1] = '\0';
-        avrdude_message(MSG_INFO, "snip\n");
         data.size = 4;
       } else if ((suffix == 'H' && lsuffix == 'H') || (suffix == 'h' && lsuffix == 'h')) {
         argv[i][strlen(argv[i]) - 2] = '\0';
@@ -448,7 +447,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
         if (*end_ptr || (end_ptr == argv[i])) {
           data.is_float = false;
           // Try single character
-          if (argv[i][0] == '\'') {
+          if (argv[i][0] == '\'' && argv[i][2] == '\'') {
             data.ll = argv[i][1];
           } else {
             avrdude_message(MSG_INFO, "\n%s (write): can't parse data \"%s\"\n",
@@ -459,9 +458,16 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
         }
       }
       // Print warning if data size might be ambiguous
-      if(!data.size && \
-        (((strncmp(argv[i], "0x", 2) == 0) && strlen(argv[i]) > 3) || \
-        (data.ll > 0xFF && strlen(argv[i]) > 2))) {
+      bool is_hex       = (strncmp(argv[i], "0x",  2) == 0);
+      bool is_neg_hex   = (strncmp(argv[i], "-0x", 3) == 0);
+      bool leading_zero = (strncmp(argv[i], "0x0", 3) == 0);
+      int8_t hex_digits = (strlen(argv[i]) - 2);
+
+      if(!data.size                                                                      // No pre-defined size
+        && (is_neg_hex                                                                   // Hex with - sign in front
+        || (is_hex && leading_zero && (hex_digits & (hex_digits - 1)))                   // Hex with 3, 5, 6 or 7 digits
+        || (!is_hex && !data.is_float && llabs(data.ll) > 0xFF && strlen(argv[i]) > 2))) // Base10 int greater than 255
+      {
         avrdude_message(MSG_INFO, "Warning: no size suffix specified for \"%s\". "
                                   "Writing %d byte(s)\n",
                                   argv[i],

From a73567893b6763e5d7d29ffab388c563b51040d9 Mon Sep 17 00:00:00 2001
From: MCUdude <hansibull@gmail.com>
Date: Mon, 21 Feb 2022 13:43:38 +0100
Subject: [PATCH 14/14] Properly handle negative number sizes

---
 src/term.c | 23 ++++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)

diff --git a/src/term.c b/src/term.c
index 407d77f2..c004b801 100644
--- a/src/term.c
+++ b/src/term.c
@@ -401,13 +401,14 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
     int32_t bytes_grown;
     uint8_t size;
     bool is_float;
+    bool is_signed;
     // Data union
     union {
       float f;
       int64_t ll;
       uint8_t a[8];
     };
-  } data = {.bytes_grown = 0, .size = 0, .is_float = false, .ll = 0};
+  } data = {.bytes_grown = 0, .size = 0, .is_float = false, .ll = 0, .is_signed = false};
 
   for (i = start_offset; i < len + start_offset - data.bytes_grown; i++) {
     data.is_float = false;
@@ -457,12 +458,12 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
           }
         }
       }
+
       // Print warning if data size might be ambiguous
       bool is_hex       = (strncmp(argv[i], "0x",  2) == 0);
       bool is_neg_hex   = (strncmp(argv[i], "-0x", 3) == 0);
       bool leading_zero = (strncmp(argv[i], "0x0", 3) == 0);
       int8_t hex_digits = (strlen(argv[i]) - 2);
-
       if(!data.size                                                                      // No pre-defined size
         && (is_neg_hex                                                                   // Hex with - sign in front
         || (is_hex && leading_zero && (hex_digits & (hex_digits - 1)))                   // Hex with 3, 5, 6 or 7 digits
@@ -471,9 +472,21 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
         avrdude_message(MSG_INFO, "Warning: no size suffix specified for \"%s\". "
                                   "Writing %d byte(s)\n",
                                   argv[i],
-                                  llabs(data.ll) > 0xFFFFFFFF ? 8 :
-                                  llabs(data.ll) > 0x0000FFFF || data.is_float ? 4 : \
-                                  llabs(data.ll) > 0x000000FF ? 2 : 1);
+                                  llabs(data.ll) > UINT32_MAX ? 8 :
+                                  llabs(data.ll) > UINT16_MAX || data.is_float ? 4 : \
+                                  llabs(data.ll) > UINT8_MAX ? 2 : 1);
+      }
+      // Flag if signed integer and adjust size
+      if (data.ll < 0 && !data.is_float) {
+        data.is_signed = true;
+        if (data.ll < INT32_MIN)
+          data.size = 8;
+        else if (data.ll < INT16_MIN)
+          data.size = 4;
+        else if (data.ll < INT8_MIN)
+          data.size = 2;
+        else
+          data.size = 1;
       }
     }
     buf[i - start_offset + data.bytes_grown]     = data.a[0];