From 328314aae350a99647435f6766292bc69c9eb316 Mon Sep 17 00:00:00 2001
From: mludvig <mludvig@81a1dc3b-b13d-400b-aceb-764788c761c2>
Date: Sat, 10 Oct 2009 01:41:40 +0000
Subject: [PATCH] 	Support for Arduino auto-reset: 	* serial.h,
 ser_avrdoper.c, ser_posix.c, ser_win32.c: Added 	 
 serial_device.set_dtr_rts implementations. 	* arduino.c, stk500.c,
 stk500.h: Call serial_set_dtr_rts() 	  to reset Arduino board before
 program upload. 	Inspired by patch #6866, resolves bug #26703

git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@845 81a1dc3b-b13d-400b-aceb-764788c761c2
---
 ChangeLog      |  9 +++++++++
 arduino.c      | 31 +++++++++++++++++++++++++++++--
 ser_avrdoper.c |  9 +++++++++
 ser_posix.c    | 32 ++++++++++++++++++++++++++++++++
 ser_win32.c    | 15 +++++++++++++++
 serial.h       |  3 +++
 stk500.c       |  4 ++--
 stk500.h       |  4 ++++
 8 files changed, 103 insertions(+), 4 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 591c74e2..5c411d1d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2009-10-10  Michal Ludvig  <mludvig@logix.net.nz>
+
+	Support for Arduino auto-reset:
+	* serial.h, ser_avrdoper.c, ser_posix.c, ser_win32.c: Added 
+	  serial_device.set_dtr_rts implementations.
+	* arduino.c, stk500.c, stk500.h: Call serial_set_dtr_rts()
+	  to reset Arduino board before program upload.
+	Inspired by patch #6866, resolves bug #26703
+
 2009-10-08  Michal Ludvig  <mludvig@logix.net.nz>
 
 	* buspirate.c: Optimised buspirate_cmd() - reading 1kB EEPROM now
diff --git a/arduino.c b/arduino.c
index 2f37c108..247f21a7 100644
--- a/arduino.c
+++ b/arduino.c
@@ -82,13 +82,40 @@ static int arduino_read_sig_bytes(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m)
   return 3;
 }
 
+static int arduino_open(PROGRAMMER * pgm, char * port)
+{
+  strcpy(pgm->port, port);
+  serial_open(port, pgm->baudrate? pgm->baudrate: 115200, &pgm->fd);
+
+  /* Clear DTR and RTS to unload the RESET capacitor 
+   * (for example in Arduino) */
+  serial_set_dtr_rts(&pgm->fd, 0);
+  usleep(50*1000);
+  /* Set DTR and RTS back to high */
+  serial_set_dtr_rts(&pgm->fd, 1);
+  usleep(50*1000);
+
+  /*
+   * drain any extraneous input
+   */
+  stk500_drain(pgm, 0);
+
+  if (stk500_getsync(pgm) < 0)
+    return -1;
+
+  return 0;
+}
+
+
 void arduino_initpgm(PROGRAMMER * pgm)
 {
 	/* This is mostly a STK500; just the signature is read
-     differently than on real STK500v1 */
+     differently than on real STK500v1 
+     and the DTR signal is set when opening the serial port
+     for the Auto-Reset feature */
   stk500_initpgm(pgm);
 
   strcpy(pgm->type, "Arduino");
   pgm->read_sig_bytes = arduino_read_sig_bytes;
-
+  pgm->open = arduino_open;
 }
diff --git a/ser_avrdoper.c b/ser_avrdoper.c
index ad3564ad..ed0af07a 100644
--- a/ser_avrdoper.c
+++ b/ser_avrdoper.c
@@ -634,6 +634,14 @@ static int avrdoper_drain(union filedescriptor *fdp, int display)
 
 /* ------------------------------------------------------------------------- */
 
+static int avrdoper_set_dtr_rts(union filedescriptor *fdp, int is_on)
+{
+	fprintf(stderr, "%s: AVR-Doper doesn't support DTR/RTS setting\n", progname);
+    return -1;
+}
+
+/* ------------------------------------------------------------------------- */
+
 struct serial_device avrdoper_serdev =
 {
   .open = avrdoper_open,
@@ -641,6 +649,7 @@ struct serial_device avrdoper_serdev =
   .send = avrdoper_send,
   .recv = avrdoper_recv,
   .drain = avrdoper_drain,
+  .set_dtr_rts = avrdoper_set_dtr_rts,
   .flags = SERDEV_FL_NONE,
 };
 
diff --git a/ser_posix.c b/ser_posix.c
index 2408f9f0..751738eb 100644
--- a/ser_posix.c
+++ b/ser_posix.c
@@ -32,6 +32,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <sys/ioctl.h>
 #include <sys/types.h>
 #include <sys/time.h>
 #include <sys/socket.h>
@@ -210,6 +211,36 @@ net_open(const char *port, union filedescriptor *fdp)
   fdp->ifd = fd;
 }
 
+
+static int ser_set_dtr_rts(union filedescriptor *fdp, int is_on)
+{
+  unsigned int	ctl;
+  int           r;
+
+  r = ioctl(fdp->ifd, TIOCMGET, &ctl);
+  if (r < 0) {
+    perror("ioctl(\"TIOCMGET\")");
+    return -1;
+  }
+
+  if (is_on) {
+    /* Clear DTR and RTS */
+    ctl &= ~(TIOCM_DTR | TIOCM_RTS);
+  }
+  else {
+    /* Set DTR and RTS */
+    ctl |= (TIOCM_DTR | TIOCM_RTS);
+  }
+
+  r = ioctl(fdp->ifd, TIOCMSET, &ctl);
+  if (r < 0) {
+    perror("ioctl(\"TIOCMSET\")");
+    return -1;
+  }
+
+  return 0;
+}
+
 static void ser_open(char * port, long baud, union filedescriptor *fdp)
 {
   int rc;
@@ -455,6 +486,7 @@ struct serial_device serial_serdev =
   .send = ser_send,
   .recv = ser_recv,
   .drain = ser_drain,
+  .set_dtr_rts = ser_set_dtr_rts,
   .flags = SERDEV_FL_CANSETSPEED,
 };
 
diff --git a/ser_win32.c b/ser_win32.c
index ed8eb29d..bce99f50 100644
--- a/ser_win32.c
+++ b/ser_win32.c
@@ -203,6 +203,20 @@ static void ser_close(union filedescriptor *fd)
 	hComPort = INVALID_HANDLE_VALUE;
 }
 
+static int ser_set_dtr_rts(union filedescriptor *fdp, int is_on)
+{
+	HANDLE hComPort=(HANDLE)fd->pfd;
+
+	if (is_on) {
+		EscapeCommFunction(hComPort, SETDTR);
+		EscapeCommFunction(hComPort, SETRTS);
+	} else {
+		EscapeCommFunction(hComPort, CLRDTR);
+		EscapeCommFunction(hComPort, CLRRTS);
+	}
+	return 0;
+}
+
 
 static int ser_send(union filedescriptor *fd, unsigned char * buf, size_t buflen)
 {
@@ -378,6 +392,7 @@ struct serial_device serial_serdev =
   .send = ser_send,
   .recv = ser_recv,
   .drain = ser_drain,
+  .set_dtr_rts = ser_set_dtr_rts,
   .flags = SERDEV_FL_CANSETSPEED,
 };
 
diff --git a/serial.h b/serial.h
index db9c1237..4a52f19b 100644
--- a/serial.h
+++ b/serial.h
@@ -52,6 +52,8 @@ struct serial_device
   int (*recv)(union filedescriptor *fd, unsigned char * buf, size_t buflen);
   int (*drain)(union filedescriptor *fd, int display);
 
+  int (*set_dtr_rts)(union filedescriptor *fd, int is_on);
+
   int flags;
 #define SERDEV_FL_NONE         0x0000 /* no flags */
 #define SERDEV_FL_CANSETSPEED  0x0001 /* device can change speed */
@@ -69,5 +71,6 @@ extern struct serial_device avrdoper_serdev;
 #define serial_send (serdev->send)
 #define serial_recv (serdev->recv)
 #define serial_drain (serdev->drain)
+#define serial_set_dtr_rts (serdev->set_dtr_rts)
 
 #endif /* serial_h */
diff --git a/stk500.c b/stk500.c
index fe8c9275..4e7c4fff 100644
--- a/stk500.c
+++ b/stk500.c
@@ -73,13 +73,13 @@ static int stk500_recv(PROGRAMMER * pgm, unsigned char * buf, size_t len)
 }
 
 
-static int stk500_drain(PROGRAMMER * pgm, int display)
+int stk500_drain(PROGRAMMER * pgm, int display)
 {
   return serial_drain(&pgm->fd, display);
 }
 
 
-static int stk500_getsync(PROGRAMMER * pgm)
+int stk500_getsync(PROGRAMMER * pgm)
 {
   unsigned char buf[32], resp[32];
 
diff --git a/stk500.h b/stk500.h
index f6ed3f1b..4b22ee05 100644
--- a/stk500.h
+++ b/stk500.h
@@ -28,6 +28,10 @@ extern "C" {
 
 void stk500_initpgm (PROGRAMMER * pgm);
 
+/* used by arduino.c to avoid duplicate code */
+int stk500_getsync(PROGRAMMER * pgm);
+int stk500_drain(PROGRAMMER * pgm, int display);
+
 #ifdef __cplusplus
 }
 #endif