From 3fd1765025ad7574729c290ec8c4957ab53eef8b Mon Sep 17 00:00:00 2001 From: Joerg Wunsch Date: Tue, 25 Nov 2014 20:00:33 +0000 Subject: [PATCH] patch #8437: [PATCH] Serial-over-ethernet for Win32 * configure.ac: Check for ws2_32 library * ser_win32.c: Add hooks for forwarding serial data over TCP connections * avrdude.1: Drop previous restriction of -P net: * doc/avrdude.conf: (Dito.) git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@1350 81a1dc3b-b13d-400b-aceb-764788c761c2 --- ChangeLog | 9 ++ NEWS | 5 + avrdude.1 | 1 - configure.ac | 3 + doc/avrdude.texi | 2 - ser_win32.c | 348 +++++++++++++++++++++++++++++++++++++++++++---- 6 files changed, 335 insertions(+), 33 deletions(-) diff --git a/ChangeLog b/ChangeLog index 197c51bd..42a6795d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2014-11-25 Joerg Wunsch + + patch #8437: [PATCH] Serial-over-ethernet for Win32 + * configure.ac: Check for ws2_32 library + * ser_win32.c: Add hooks for forwarding serial data over + TCP connections + * avrdude.1: Drop previous restriction of -P net: + * doc/avrdude.conf: (Dito.) + 2014-11-24 Joerg Wunsch bug #42908: no external reset at JTAGICE3 diff --git a/NEWS b/NEWS index 19c23e15..d2be83fd 100644 --- a/NEWS +++ b/NEWS @@ -25,6 +25,10 @@ Current: - buspirate: Also support "cpufreq" extended parameter in binary mode (patch #8504 ) + - The "-P net:" syntax (forwarding of serial data over TCP) is now + also implemented for Win32 systems. + + * New devices supported: - AT90PWM216 (bug #42310: New part description for AT90PWM216) - ATmega32M1 (patch #7694 Add support for the atmega32m1) @@ -52,6 +56,7 @@ Current: - bug #43137: Writing and reading incorrect pages when using jtagicemkI - bug #40870: config nitpick: ATtiny25/45/85 have 1 calibration byte not 2 - bug #42908: no external reset at JTAGICE3 + - patch #8437: [PATCH] Serial-over-ethernet for Win32 * Internals: - Removing exit calls from config parser diff --git a/avrdude.1 b/avrdude.1 index 906f375f..a5e98ef5 100644 --- a/avrdude.1 +++ b/avrdude.1 @@ -511,7 +511,6 @@ actual programmer has been attached to. The port is assumed to be properly configured, for example using a transparent 8-bit data connection without parity at 115200 Baud for a STK500. -.Em This feature is currently not implemented for Win32 systems. .It Fl q Disable (or quell) output of the progress bar while reading or writing to the device. Specify it a second time for even quieter operation. diff --git a/configure.ac b/configure.ac index 97a6d023..7586bd6e 100644 --- a/configure.ac +++ b/configure.ac @@ -191,6 +191,9 @@ AC_CHECK_HEADERS([ddk/hidsdi.h],,,[#include AC_C_CONST AC_HEADER_TIME +# WinSock2 +AC_CHECK_LIB([ws2_32], [puts]) + # Checks for library functions. AC_CHECK_FUNCS([memset select strcasecmp strdup strerror strncasecmp strtol strtoul gettimeofday usleep]) diff --git a/doc/avrdude.texi b/doc/avrdude.texi index 240dd206..383764f0 100644 --- a/doc/avrdude.texi +++ b/doc/avrdude.texi @@ -561,8 +561,6 @@ The port is assumed to be properly configured, for example using a transparent 8-bit data connection without parity at 115200 Baud for a STK500. -@emph{This feature is currently not implemented for Win32 systems.} - @item -q Disable (or quell) output of the progress bar while reading or writing diff --git a/ser_win32.c b/ser_win32.c index ed5c6bb7..b0c3d63c 100644 --- a/ser_win32.c +++ b/ser_win32.c @@ -23,11 +23,19 @@ * Native Win32 serial interface for avrdude. */ +#include "ac_cfg.h" + #if defined(WIN32NATIVE) +#ifdef HAVE_LIBWS2_32 +/* winsock2.h must be included before windows.h from avrdude.h... */ +# include +#endif + #include #include #include /* for isprint */ +#include /* ENOTTY */ #include "avrdude.h" #include "libavrdude.h" @@ -41,6 +49,8 @@ struct baud_mapping { DWORD speed; }; +static unsigned char serial_over_ethernet = 0; + /* HANDLE hComPort=INVALID_HANDLE_VALUE; */ static struct baud_mapping baud_lookup_table [] = { @@ -89,24 +99,122 @@ static BOOL serial_w32SetTimeOut(HANDLE hComPort, DWORD timeout) // in ms static int ser_setspeed(union filedescriptor *fd, long baud) { - DCB dcb; - HANDLE hComPort = (HANDLE)fd->pfd; + if (serial_over_ethernet) { + return -ENOTTY; + } else { + DCB dcb; + HANDLE hComPort = (HANDLE)fd->pfd; - ZeroMemory (&dcb, sizeof(DCB)); - dcb.DCBlength = sizeof(DCB); - dcb.BaudRate = serial_baud_lookup (baud); - dcb.fBinary = 1; - dcb.fDtrControl = DTR_CONTROL_DISABLE; - dcb.fRtsControl = RTS_CONTROL_DISABLE; - dcb.ByteSize = 8; - dcb.Parity = NOPARITY; - dcb.StopBits = ONESTOPBIT; + ZeroMemory (&dcb, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + dcb.BaudRate = serial_baud_lookup (baud); + dcb.fBinary = 1; + dcb.fDtrControl = DTR_CONTROL_DISABLE; + dcb.fRtsControl = RTS_CONTROL_DISABLE; + dcb.ByteSize = 8; + dcb.Parity = NOPARITY; + dcb.StopBits = ONESTOPBIT; - if (!SetCommState(hComPort, &dcb)) + if (!SetCommState(hComPort, &dcb)) + return -1; + + return 0; + } +} + +#ifdef HAVE_LIBWS2_32 +static int +net_open(const char *port, union filedescriptor *fdp) +{ + WSADATA wsaData; + LPVOID lpMsgBuf; + + char *hstr, *pstr, *end; + unsigned int pnum; + int fd; + struct sockaddr_in sockaddr; + struct hostent *hp; + + if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) { + avrdude_message(MSG_INFO, "%s: net_open(): WSAStartup() failed\n", progname); return -1; + } + if ((hstr = strdup(port)) == NULL) { + avrdude_message(MSG_INFO, "%s: net_open(): Out of memory!\n", progname); + return -1; + } + + if (((pstr = strchr(hstr, ':')) == NULL) || (pstr == hstr)) { + avrdude_message(MSG_INFO, "%s: net_open(): Mangled host:port string \"%s\"\n", progname, hstr); + free(hstr); + return -1; + } + + /* + * Terminate the host section of the description. + */ + *pstr++ = '\0'; + + pnum = strtoul(pstr, &end, 10); + + if ((*pstr == '\0') || (*end != '\0') || (pnum == 0) || (pnum > 65535)) { + avrdude_message(MSG_INFO, "%s: net_open(): Bad port number \"%s\"\n", progname, pstr); + free(hstr); + return -1; + } + + if ((hp = gethostbyname(hstr)) == NULL) { + avrdude_message(MSG_INFO, "%s: net_open(): unknown host \"%s\"\n", progname, hstr); + free(hstr); + return -1; + } + + free(hstr); + + if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + WSAGetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&lpMsgBuf, + 0, + NULL); + avrdude_message(MSG_INFO, "%s: net_open(): Cannot open socket: %s\n", progname, (char *)lpMsgBuf); + LocalFree(lpMsgBuf); + return -1; + } + + memset(&sockaddr, 0, sizeof(struct sockaddr_in)); + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons(pnum); + memcpy(&(sockaddr.sin_addr.s_addr), hp->h_addr, sizeof(struct in_addr)); + + if (connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) { + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + WSAGetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&lpMsgBuf, + 0, + NULL); + avrdude_message(MSG_INFO, "%s: net_open(): Connect failed: %s\n", progname, (char *)lpMsgBuf); + LocalFree(lpMsgBuf); + return -1; + } + + fdp->ifd = fd; + + serial_over_ethernet = 1; return 0; } +#endif static int ser_open(char * port, union pinfo pinfo, union filedescriptor *fdp) @@ -118,14 +226,16 @@ static int ser_open(char * port, union pinfo pinfo, union filedescriptor *fdp) /* * If the port is of the form "net::", then * handle it as a TCP connection to a terminal server. - * - * This is curently not implemented for Win32. */ if (strncmp(port, "net:", strlen("net:")) == 0) { - avrdude_message(MSG_INFO, "%s: ser_open(): network connects are currently not" - "implemented for Win32 environments\n", +#ifdef HAVE_LIBWS2_32 + return net_open(port + strlen("net:"), fdp); +#else + avrdude_message(MSG_INFO, "%s: ser_open(): " + "not configured for TCP connections\n", progname); return -1; +#endif } if (strncasecmp(port, "com", strlen("com")) == 0) { @@ -148,9 +258,9 @@ static int ser_open(char * port, union pinfo pinfo, union filedescriptor *fdp) OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hComPort == INVALID_HANDLE_VALUE) { - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), @@ -198,30 +308,106 @@ static int ser_open(char * port, union pinfo pinfo, union filedescriptor *fdp) static void ser_close(union filedescriptor *fd) { - HANDLE hComPort=(HANDLE)fd->pfd; - if (hComPort != INVALID_HANDLE_VALUE) - CloseHandle (hComPort); + if (serial_over_ethernet) { + closesocket(fd->ifd); + WSACleanup(); + } else { + HANDLE hComPort=(HANDLE)fd->pfd; + if (hComPort != INVALID_HANDLE_VALUE) + CloseHandle (hComPort); - hComPort = INVALID_HANDLE_VALUE; + hComPort = INVALID_HANDLE_VALUE; + } } static int ser_set_dtr_rts(union filedescriptor *fd, int is_on) { - HANDLE hComPort=(HANDLE)fd->pfd; - - if (is_on) { - EscapeCommFunction(hComPort, SETDTR); - EscapeCommFunction(hComPort, SETRTS); + if (serial_over_ethernet) { + return 0; } else { - EscapeCommFunction(hComPort, CLRDTR); - EscapeCommFunction(hComPort, CLRRTS); + HANDLE hComPort=(HANDLE)fd->pfd; + + if (is_on) { + EscapeCommFunction(hComPort, SETDTR); + EscapeCommFunction(hComPort, SETRTS); + } else { + EscapeCommFunction(hComPort, CLRDTR); + EscapeCommFunction(hComPort, CLRRTS); + } + return 0; } +} + +#ifdef HAVE_LIBWS2_32 +static int net_send(union filedescriptor *fd, unsigned char * buf, size_t buflen) +{ + LPVOID lpMsgBuf; + int rc; + unsigned char *p = buf; + size_t len = buflen; + + if (fd->ifd < 0) { + avrdude_message(MSG_NOTICE, "%s: net_send(): connection not open\n", progname); + exit(1); + } + + if (!len) { + return 0; + } + + if (verbose > 3) { + avrdude_message(MSG_TRACE, "%s: Send: ", progname); + + while (buflen) { + unsigned char c = *buf; + if (isprint(c)) { + avrdude_message(MSG_TRACE, "%c ", c); + } else { + avrdude_message(MSG_TRACE, ". "); + } + avrdude_message(MSG_TRACE, "[%02x] ", c); + + buf++; + buflen--; + } + + avrdude_message(MSG_TRACE, "\n"); + } + + while (len) { + rc = send(fd->ifd, p, (len > 1024) ? 1024 : len, 0); + if (rc < 0) { + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + WSAGetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&lpMsgBuf, + 0, + NULL); + avrdude_message(MSG_INFO, "%s: net_send(): send error: %s\n", progname, (char *)lpMsgBuf); + LocalFree(lpMsgBuf); + exit(1); + } + p += rc; + len -= rc; + } + return 0; } +#endif static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t buflen) { +#ifdef HAVE_LIBWS2_32 + if (serial_over_ethernet) { + return net_send(fd, buf, buflen); + } +#endif + size_t len = buflen; unsigned char c='\0'; DWORD written; @@ -275,8 +461,110 @@ static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t } +#ifdef HAVE_LIBWS2_32 +static int net_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen) +{ + LPVOID lpMsgBuf; + struct timeval timeout, to2; + fd_set rfds; + int nfds; + int rc; + unsigned char *p = buf; + size_t len = 0; + + if (fd->ifd < 0) { + avrdude_message(MSG_INFO, "%s: net_recv(): connection not open\n", progname); + exit(1); + } + + timeout.tv_sec = serial_recv_timeout / 1000L; + timeout.tv_usec = (serial_recv_timeout % 1000L) * 1000; + to2 = timeout; + + while (len < buflen) { +reselect: + FD_ZERO(&rfds); + FD_SET(fd->ifd, &rfds); + + nfds = select(fd->ifd + 1, &rfds, NULL, NULL, &to2); + if (nfds == 0) { + if (verbose > 1) { + avrdude_message(MSG_NOTICE, "%s: ser_recv(): programmer is not responding\n", progname); + } + return -1; + } else if (nfds == -1) { + if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEINPROGRESS) { + avrdude_message(MSG_NOTICE, "%s: ser_recv(): programmer is not responding, reselecting\n", progname); + goto reselect; + } else { + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + WSAGetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&lpMsgBuf, + 0, + NULL); + avrdude_message(MSG_INFO, "%s: ser_recv(): select(): %s\n", progname, (char *)lpMsgBuf); + LocalFree(lpMsgBuf); + exit(1); + } + } + + rc = recv(fd->ifd, p, (buflen - len > 1024) ? 1024 : buflen - len, 0); + if (rc < 0) { + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + WSAGetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&lpMsgBuf, + 0, + NULL); + avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n", progname, (char *)lpMsgBuf); + LocalFree(lpMsgBuf); + exit(1); + } + p += rc; + len += rc; + } + + p = buf; + + if (verbose > 3) { + avrdude_message(MSG_TRACE, "%s: Recv: ", progname); + + while (len) { + unsigned char c = *p; + if (isprint(c)) { + avrdude_message(MSG_TRACE, "%c ", c); + } else { + avrdude_message(MSG_TRACE, ". "); + } + avrdude_message(MSG_TRACE, "[%02x] ", c); + + p++; + len--; + } + avrdude_message(MSG_TRACE, "\n"); + } + + return 0; +} +#endif + static int ser_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen) { +#ifdef HAVE_LIBWS2_32 + if (serial_over_ethernet) { + return net_recv(fd, buf, buflen); + } +#endif + unsigned char c; unsigned char * p = buf; DWORD read;