• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
19  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
21  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
25  * OF SUCH DAMAGE.
26  *
27  * This file is part of the lwIP TCP/IP stack.
28  *
29  */
30 
31 #include <lwip/opt.h>
32 #include <lwip/sys.h>
33 #include <lwip/sio.h>
34 
35 #include <stdio.h>
36 #include <stdarg.h>
37 
38 #ifdef _MSC_VER
39 #pragma warning (push, 3)
40 #endif
41 #include <windows.h>
42 #ifdef _MSC_VER
43 #pragma warning (pop)
44 #endif
45 #include "lwipcfg.h"
46 
47 /** When 1, use COM ports, when 0, use named pipes (for simulation). */
48 #ifndef SIO_USE_COMPORT
49 #define SIO_USE_COMPORT 1
50 #endif
51 
52 /** If SIO_USE_COMPORT==1, use COMx, if 0, use a pipe (default) */
53 #if SIO_USE_COMPORT
54 #define SIO_DEVICENAME "\\\\.\\COM"
55 #else
56 #define SIO_DEVICENAME "\\\\.\\pipe\\lwip"
57 #endif
58 
59 #if SIO_USE_COMPORT
60 #ifndef SIO_COMPORT_SPEED
61 #define SIO_COMPORT_SPEED 115200
62 #endif
63 #ifndef SIO_COMPORT_BYTESIZE
64 #define SIO_COMPORT_BYTESIZE 8
65 #endif
66 #ifndef SIO_COMPORT_STOPBITS
67 #define SIO_COMPORT_STOPBITS 0 /* ONESTOPBIT */
68 #endif
69 #ifndef SIO_COMPORT_PARITY
70 #define SIO_COMPORT_PARITY 0 /* NOPARITY */
71 #endif
72 #endif /* SIO_USE_COMPORT */
73 
74 static int sio_abort = 0;
75 
76 /* \\.\pipe\lwip0 */
77 /* pppd /dev/ttyS0 logfile mylog debug nocrtscts local noauth noccp ms-dns 212.27.54.252 192.168.0.4:192.168.0.5
78  */
79 
80 /**
81  * SIO_DEBUG: Enable debugging for SIO.
82  */
83 #ifndef SIO_DEBUG
84 #define SIO_DEBUG    LWIP_DBG_OFF
85 #endif
86 
87 #if SIO_USE_COMPORT
88 /** When using a real COM port, set up the
89  * serial line settings (baudrate etc.)
90  */
91 static BOOL
sio_setup(HANDLE fd)92 sio_setup(HANDLE fd)
93 {
94   COMMTIMEOUTS cto;
95   DCB dcb;
96 
97   /* set up baudrate and other communication settings */
98   memset(&dcb, 0, sizeof(dcb));
99   /* Obtain the DCB structure for the device */
100   if (!GetCommState(fd, &dcb)) {
101     return FALSE;
102   }
103   /* Set the new data */
104   dcb.BaudRate = SIO_COMPORT_SPEED;
105   dcb.ByteSize = SIO_COMPORT_BYTESIZE;
106   dcb.StopBits = 0; /* ONESTOPBIT */
107   dcb.Parity   = 0; /* NOPARITY */
108   dcb.fParity  = 0; /* parity is not used */
109   /* do not use flow control */
110   /*dcb.fOutxDsrFlow = dcb.fDtrControl = 0;
111   dcb.fOutxCtsFlow = dcb.fRtsControl = 0;
112   dcb.fErrorChar = dcb.fNull = 0;
113   dcb.fInX = dcb.fOutX = 0;
114   dcb.XonChar = dcb.XoffChar = 0;
115   dcb.XonLim = dcb.XoffLim = 100;*/
116 
117   /* Set the new DCB structure */
118   if (!SetCommState(fd, &dcb)) {
119     return FALSE;
120   }
121 
122   memset(&cto, 0, sizeof(cto));
123   if(!GetCommTimeouts(fd, &cto))
124   {
125     return FALSE;
126   }
127   /* change read timeout, leave write timeout as it is */
128   cto.ReadIntervalTimeout = 1;
129   cto.ReadTotalTimeoutMultiplier = 0;
130   cto.ReadTotalTimeoutConstant = 1; /* 1 ms */
131   if(!SetCommTimeouts(fd, &cto)) {
132     return FALSE;
133   }
134 
135   return TRUE;
136 }
137 #endif /* SIO_USE_COMPORT */
138 
139 /**
140  * Opens a serial device for communication.
141  *
142  * @param devnum device number
143  * @return handle to serial device if successful, NULL otherwise
144  */
sio_open(u8_t devnum)145 sio_fd_t sio_open(u8_t devnum)
146 {
147   HANDLE fileHandle = INVALID_HANDLE_VALUE;
148   CHAR   fileName[256];
149   LWIP_DEBUGF(SIO_DEBUG, ("sio_open(%lu)\n", (DWORD)devnum));
150 #if SIO_USE_COMPORT
151   snprintf(fileName, 255, SIO_DEVICENAME"%lu", (DWORD)(devnum));
152 #else /* SIO_USE_COMPORT */
153   snprintf(fileName, 255, SIO_DEVICENAME"%lu", (DWORD)(devnum & ~1));
154   if ((devnum & 1) == 0) {
155     fileHandle = CreateNamedPipeA(fileName, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_NOWAIT,
156       PIPE_UNLIMITED_INSTANCES, 102400, 102400, 100, NULL);
157   } else
158 #endif /* SIO_USE_COMPORT */
159   {
160     fileHandle = CreateFileA(fileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
161   }
162   if (fileHandle != INVALID_HANDLE_VALUE) {
163     sio_abort = 0;
164 #if !SIO_USE_COMPORT
165     if (devnum & 1) {
166       DWORD mode = PIPE_NOWAIT;
167       if (!SetNamedPipeHandleState(fileHandle, &mode, NULL, NULL)) {
168         LWIP_DEBUGF(SIO_DEBUG, ("sio_open(%lu): SetNamedPipeHandleState failed. GetLastError() returns %d\n",
169                   (DWORD)devnum, GetLastError()));
170       }
171     } else
172 #endif /* !SIO_USE_COMPORT */
173     {
174       FlushFileBuffers(fileHandle);
175     }
176 #if SIO_USE_COMPORT
177     if(!sio_setup(fileHandle)) {
178       CloseHandle(fileHandle);
179       LWIP_DEBUGF(SIO_DEBUG, ("sio_open(%lu): sio_setup failed. GetLastError() returns %lu\n",
180                   (DWORD)devnum, GetLastError()));
181       return NULL;
182     }
183 #endif /* SIO_USE_COMPORT */
184     LWIP_DEBUGF(SIO_DEBUG, ("sio_open: file \"%s\" successfully opened.\n", fileName));
185     printf("sio_open: file \"%s\" (%d) successfully opened: 0x%08x\n", fileName, devnum, LWIP_PTR_NUMERIC_CAST(unsigned int, fileHandle));
186     return (sio_fd_t)(fileHandle);
187   }
188   LWIP_DEBUGF(SIO_DEBUG, ("sio_open(%lu) failed. GetLastError() returns %lu\n",
189               (DWORD)devnum, GetLastError()));
190   printf("sio_open(%lu) failed. GetLastError() returns %lu\n",
191               (DWORD)devnum, GetLastError());
192   return NULL;
193 }
194 
195 /**
196  * Sends a single character to the serial device.
197  *
198  * @param c character to send
199  * @param fd serial device handle
200  *
201  * @note This function will block until the character can be sent.
202  */
sio_send(u8_t c,sio_fd_t fd)203 void sio_send(u8_t c, sio_fd_t fd)
204 {
205   DWORD dwNbBytesWritten = 0;
206   LWIP_DEBUGF(SIO_DEBUG, ("sio_send(%lu)\n", (DWORD)c));
207   while ((!WriteFile((HANDLE)(fd), &c, 1, &dwNbBytesWritten, NULL)) || (dwNbBytesWritten < 1)) {
208   }
209 }
210 
211 /**
212  * Receives a single character from the serial device.
213  *
214  * @param fd serial device handle
215  *
216  * @note This function will block until a character is received.
217  */
sio_recv(sio_fd_t fd)218 u8_t sio_recv(sio_fd_t fd)
219 {
220   DWORD dwNbBytesReadden = 0;
221   u8_t byte = 0;
222   LWIP_DEBUGF(SIO_DEBUG, ("sio_recv()\n"));
223   while ((sio_abort == 0) && ((!ReadFile((HANDLE)(fd), &byte, 1, &dwNbBytesReadden, NULL)) || (dwNbBytesReadden < 1)));
224   LWIP_DEBUGF(SIO_DEBUG, ("sio_recv()=%lu\n", (DWORD)byte));
225   return byte;
226 }
227 
228 /**
229  * Reads from the serial device.
230  *
231  * @param fd serial device handle
232  * @param data pointer to data buffer for receiving
233  * @param len maximum length (in bytes) of data to receive
234  * @return number of bytes actually received - may be 0 if aborted by sio_read_abort
235  *
236  * @note This function will block until data can be received. The blocking
237  * can be cancelled by calling sio_read_abort().
238  */
sio_read(sio_fd_t fd,u8_t * data,u32_t len)239 u32_t sio_read(sio_fd_t fd, u8_t* data, u32_t len)
240 {
241   BOOL ret;
242   DWORD dwNbBytesReadden = 0;
243   LWIP_DEBUGF(SIO_DEBUG, ("sio_read()...\n"));
244   ret = ReadFile((HANDLE)(fd), data, len, &dwNbBytesReadden, NULL);
245   LWIP_DEBUGF(SIO_DEBUG, ("sio_read()=%lu bytes -> %d\n", dwNbBytesReadden, ret));
246   LWIP_UNUSED_ARG(ret);
247   return dwNbBytesReadden;
248 }
249 
250 /**
251  * Tries to read from the serial device. Same as sio_read but returns
252  * immediately if no data is available and never blocks.
253  *
254  * @param fd serial device handle
255  * @param data pointer to data buffer for receiving
256  * @param len maximum length (in bytes) of data to receive
257  * @return number of bytes actually received
258  */
sio_tryread(sio_fd_t fd,u8_t * data,u32_t len)259 u32_t sio_tryread(sio_fd_t fd, u8_t* data, u32_t len)
260 {
261   /* @todo: implement non-blocking read */
262   BOOL ret;
263   DWORD dwNbBytesReadden = 0;
264   LWIP_DEBUGF(SIO_DEBUG, ("sio_read()...\n"));
265   ret = ReadFile((HANDLE)(fd), data, len, &dwNbBytesReadden, NULL);
266   LWIP_DEBUGF(SIO_DEBUG, ("sio_read()=%lu bytes -> %d\n", dwNbBytesReadden, ret));
267   LWIP_UNUSED_ARG(ret);
268   return dwNbBytesReadden;
269 }
270 
271 /**
272  * Writes to the serial device.
273  *
274  * @param fd serial device handle
275  * @param data pointer to data to send
276  * @param len length (in bytes) of data to send
277  * @return number of bytes actually sent
278  *
279  * @note This function will block until all data can be sent.
280  */
sio_write(sio_fd_t fd,const u8_t * data,u32_t len)281 u32_t sio_write(sio_fd_t fd, const u8_t* data, u32_t len)
282 {
283   BOOL ret;
284   DWORD dwNbBytesWritten = 0;
285   LWIP_DEBUGF(SIO_DEBUG, ("sio_write()...\n"));
286   ret = WriteFile((HANDLE)(fd), data, len, &dwNbBytesWritten, NULL);
287   LWIP_DEBUGF(SIO_DEBUG, ("sio_write()=%lu bytes -> %d\n", dwNbBytesWritten, ret));
288   LWIP_UNUSED_ARG(ret);
289   return dwNbBytesWritten;
290 }
291 
292 /**
293  * Aborts a blocking sio_read() call.
294  * @todo: This currently ignores fd and aborts all reads
295  *
296  * @param fd serial device handle
297  */
sio_read_abort(sio_fd_t fd)298 void sio_read_abort(sio_fd_t fd)
299 {
300   LWIP_UNUSED_ARG(fd);
301   LWIP_DEBUGF(SIO_DEBUG, ("sio_read_abort() !!!!!...\n"));
302   sio_abort = 1;
303   return;
304 }
305