From b89184f48f4ee7611f7388690f6131e465b79902 Mon Sep 17 00:00:00 2001
From: maxgerhardt <maximilian.gerhardt@rub.de>
Date: Sun, 18 Jun 2023 01:24:50 +0200
Subject: [PATCH] User-specifyable serial port per env var, better error
 handling

---
 minichlink/ardulink.c     |  15 ++++++++++++++-
 minichlink/minichlink.exe | Bin 66048 -> 66560 bytes
 minichlink/serial_dev.c   |  30 +++++++++++++++++++++---------
 3 files changed, 35 insertions(+), 10 deletions(-)

diff --git a/minichlink/ardulink.c b/minichlink/ardulink.c
index 44fa144..96c0d93 100644
--- a/minichlink/ardulink.c
+++ b/minichlink/ardulink.c
@@ -101,7 +101,20 @@ void * TryInit_Ardulink(void)
         return NULL;
     }
 
-    if (serial_dev_create(&ctx->serial, DEFAULT_SERIAL_NAME, 115200) == -1) {
+    const char* serial_to_open = NULL;
+    // This is extremely crude. We receive no parameters, yet we have
+    // to find the correct serial port for the programmer.
+    // since the init is executed before the command line parameters are parsed,
+    // we don't get the value of any "--serial-port=..." switch at all.
+    // We at least to make it usable by using an environment variable.
+    // Optimally, we would restructure the init function to include init hints
+    // or try to enumerate all existing serial ports for our Ardulink programmer.
+    if ((serial_to_open = getenv("MINICHLINK_SERIAL")) == NULL) {
+        // fallback
+        serial_to_open = DEFAULT_SERIAL_NAME;
+    }
+
+    if (serial_dev_create(&ctx->serial, serial_to_open, 115200) == -1) {
         perror("create");
         return NULL;
     }
diff --git a/minichlink/minichlink.exe b/minichlink/minichlink.exe
index f366cfcf2e1fb0fd2451a2c4217a62650e72829a..9e237b4d661f6ae951a3010a84948b76e99a133b 100644
GIT binary patch
delta 15113
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
b+O>8Um}VSB0h<c=IH%-)WPY%TpTYkZQX@z`

delta 14825
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
Dz8A;?

diff --git a/minichlink/serial_dev.c b/minichlink/serial_dev.c
index 5a35fbe..f39780f 100644
--- a/minichlink/serial_dev.c
+++ b/minichlink/serial_dev.c
@@ -16,19 +16,31 @@ int serial_dev_create(serial_dev_t *dev, const char* port, unsigned baud) {
 int serial_dev_open(serial_dev_t *dev) {
     fprintf(stderr, "Opening serial port %s at %u baud.\n", dev->port, dev->baud);
 #ifdef IS_WINDOWS
-    dev->handle = CreateFileA(dev->port, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0,0);
+    // Windows quirk: port = "COM10" is invalid, has to be encoded as "\\.\COM10".
+    // This also works for COM below 9. So, let's give the user the ability to use
+    // any "COMx" string and just prepend the "\\.\".
+    char winPortName[64];
+    if(dev->port[0] != '\\') {
+        snprintf(winPortName, sizeof(winPortName), "\\\\.\\%s", dev->port);
+    } else {
+        // copy verbatim if string already starts with a '\'
+        snprintf(winPortName, sizeof(winPortName), "%s", dev->port);
+    }
+    dev->handle = CreateFileA(winPortName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0,0);
     if (dev->handle == INVALID_HANDLE_VALUE) {
         if (GetLastError() == ERROR_FILE_NOT_FOUND) {
             fprintf(stderr, "Serial port %s not found.\n", dev->port);
+            // weird: without this, errno = 0 (no error).
+            _set_errno(ERROR_FILE_NOT_FOUND);
             return -1; // Device not found
         }
         // Error while opening the device
-        return -2;
+        return -1;
     }
     DCB dcbSerialParams;
     dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
     if (!GetCommState(dev->handle, &dcbSerialParams)) {
-        return -3;
+        return -1;
     }
     // set baud and 8N1 serial formatting
     dcbSerialParams.BaudRate = dev->baud;
@@ -37,7 +49,7 @@ int serial_dev_open(serial_dev_t *dev) {
     dcbSerialParams.Parity = NOPARITY;
     // write back
     if (!SetCommState(dev->handle, &dcbSerialParams)){ 
-        return -5;
+        return -1;
     }
     // Set the timeout parameters to "no timeout" (blocking).
     // see https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-commtimeouts
@@ -49,7 +61,7 @@ int serial_dev_open(serial_dev_t *dev) {
     timeouts.WriteTotalTimeoutMultiplier = 0;
     // Write the parameters
     if (!SetCommTimeouts(dev->handle, &timeouts)) {
-        return -6;
+        return -1;
     }
 #else
     struct termios attr;
@@ -60,7 +72,7 @@ int serial_dev_open(serial_dev_t *dev) {
 
     if (tcgetattr(dev->fd, &attr) == -1) {
         perror("tcgetattr");
-        return -2;
+        return -1;
     }
 
     cfmakeraw(&attr);
@@ -68,7 +80,7 @@ int serial_dev_open(serial_dev_t *dev) {
 
     if (tcsetattr(dev->fd, TCSANOW, &attr) == -1) {
         perror("tcsetattr");
-        return -3;
+        return -1;
     }
 #endif
     // all okay if we get here
@@ -118,12 +130,12 @@ int serial_dev_do_dtr_reset(serial_dev_t *dev) {
 
     if (tcdrain(dev->fd) == -1) {
         perror("tcdrain");
-        return -2;
+        return -1;
     }
 
     if (ioctl(dev->fd, TIOCMBIS, &argp) == -1) {
         perror("ioctl");
-        return -3;
+        return -1;
     }
 #endif
     return 0;
-- 
GitLab