From 7140312c170c6534657801aad9efe3a83889f051 Mon Sep 17 00:00:00 2001
From: Joerg Wunsch <j@uriah.heep.sax.de>
Date: Mon, 15 Jan 2018 22:44:22 +0000
Subject: [PATCH] Submitted by Dennis Reimers: patch #8580: FT245r support to
 select device by serial number * ft245r.c (ft245r_open): Add serial number
 parsing.

git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@1415 81a1dc3b-b13d-400b-aceb-764788c761c2
---
 ChangeLog |  6 ++++++
 NEWS      |  1 +
 ft245r.c  | 56 +++++++++++++++++++++++++++++++++++++++++--------------
 3 files changed, 49 insertions(+), 14 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 6a2a3b39..134ae8a4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2018-01-15  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Dennis Reimers:
+	patch #8580: FT245r support to select device by serial number
+	* ft245r.c (ft245r_open): Add serial number parsing.
+
 2018-01-15  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
 
 	Submitted by Axel Simon:
diff --git a/NEWS b/NEWS
index 9aa33d37..3eac6fff 100644
--- a/NEWS
+++ b/NEWS
@@ -55,6 +55,7 @@ Current:
     patch #9222: Enable silent build
     patch #8924: Enable TPI for usbtiny
     patch #9033: avrdoper backend uses libhidapi instead of libusb
+    patch #8580: FT245r support to select device by serial number
 
   * Internals:
     - New avrdude.conf keyword "family_id", used to verify SIB attributes
diff --git a/ft245r.c b/ft245r.c
index cc1061df..7f9883f1 100644
--- a/ft245r.c
+++ b/ft245r.c
@@ -479,6 +479,7 @@ static inline unsigned char extract_data(PROGRAMMER * pgm, unsigned char *buf, i
 }
 
 /* to check data */
+#if 0
 static inline unsigned char extract_data_out(PROGRAMMER * pgm, unsigned char *buf, int offset) {
     int j;
     int buf_pos = 1;
@@ -495,6 +496,7 @@ static inline unsigned char extract_data_out(PROGRAMMER * pgm, unsigned char *bu
     }
     return r;
 }
+#endif
 
 
 /*
@@ -537,8 +539,10 @@ static const struct pin_checklist_t pin_checklist[] = {
 static int ft245r_open(PROGRAMMER * pgm, char * port) {
     int rv;
     int devnum = -1;
+    char device[9] = "";
 
     rv = pins_check(pgm,pin_checklist,sizeof(pin_checklist)/sizeof(pin_checklist[0]), true);
+
     if(rv) {
         pgm->display(pgm, progbuf);
         return rv;
@@ -546,22 +550,46 @@ static int ft245r_open(PROGRAMMER * pgm, char * port) {
 
     strcpy(pgm->port, port);
 
-    if (strcmp(port,DEFAULT_USB) != 0) {
-        if (strncasecmp("ft", port, 2) == 0) {
-            char *startptr = port + 2;
-            char *endptr = NULL;
-            devnum = strtol(startptr,&endptr,10);
-            if ((startptr==endptr) || (*endptr != '\0')) {
-                devnum = -1;
-            }
-        }
-        if (devnum < 0) {
-            avrdude_message(MSG_INFO, "%s: invalid portname '%s': use 'ft[0-9]+'\n",
-                            progname,port);
-            return -1;
-        }
+    // read device string cut after 8 chars (max. length of serial number)
+    if ((sscanf(port, "usb:%8s", device) != 1)) {
+      avrdude_message(MSG_INFO,
+          "%s: ft245r_open(): invalid device identifier '%8s'\n",
+          progname, device);
+      return -1;
     } else {
+      if (strlen(device) == 8 ){ // serial number
+        if (verbose >= 2) {
+          avrdude_message(MSG_INFO,
+              "%s: ft245r_open(): serial number parsed as: "
+              "%s\n",
+              progname,
+              device);
+        }
+        // copy serial number to pgm struct
+        strcpy(pgm->usbsn, device);
+        // and use first device with matching serial (should be unique)
         devnum = 0;
+      }
+      else if (strncmp("ft", device, 2) || strlen(device) <= 8)  { // classic device number
+        char *startptr = device + 2;
+        char *endptr = NULL;
+        devnum = strtol(startptr,&endptr,10);
+        if ((startptr==endptr) || (*endptr != '\0')) {
+          devnum = -1;
+        }
+        avrdude_message(MSG_INFO,
+            "%s: ft245r_open(): device number parsed as: "
+            "%d\n",
+            progname,
+            devnum);
+      }
+    }
+
+    // if something went wrong before abort with helpful message
+    if (devnum < 0) {
+      avrdude_message(MSG_INFO, "%s: ft245r_open(): invalid portname '%s': use^ 'ft[0-9]+' or serial number\n",
+          progname,port);
+      return -1;
     }
 
     handle = malloc (sizeof (struct ftdi_context));