1 //---------------------------------------------------------------------------
2 // Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a
5 // copy of this software and associated documentation files (the "Software"),
6 // to deal in the Software without restriction, including without limitation
7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 // and/or sell copies of the Software, and to permit persons to whom the
9 // Software is furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 // IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES
18 // OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 // OTHER DEALINGS IN THE SOFTWARE.
21 //
22 // Except as contained in this notice, the name of Dallas Semiconductor
23 // shall not be used except as stated in the Dallas Semiconductor
24 // Branding Policy.
25 //---------------------------------------------------------------------------
26 //
27 // linuxlnk.C - COM functions required by MLANLL.C, MLANTRNU, MLANNETU.C and
28 // MLanFile.C for MLANU to communicate with the DS2480 based
29 // Universal Serial Adapter 'U'. Fill in the platform specific code.
30 //
31 // Version: 1.02
32 //
33 // History: 1.00 -> 1.01 Added function msDelay.
34 //
35 // 1.01 -> 1.02 Changed to generic OpenCOM/CloseCOM for easier
36 // use with other platforms.
37 //
38
39 //--------------------------------------------------------------------------
40 // Copyright (C) 1998 Andrea Chambers and University of Newcastle upon Tyne,
41 // All Rights Reserved.
42 //--------------------------------------------------------------------------
43 //
44 // Permission is hereby granted, free of charge, to any person obtaining a
45 // copy of this software and associated documentation files (the "Software"),
46 // to deal in the Software without restriction, including without limitation
47 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
48 // and/or sell copies of the Software, and to permit persons to whom the
49 // Software is furnished to do so, subject to the following conditions:
50 //
51 // The above copyright notice and this permission notice shall be included
52 // in all copies or substantial portions of the Software.
53 //
54 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
55 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
56 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
57 // IN NO EVENT SHALL THE UNIVERSITY OF NEWCASTLE UPON TYNE OR ANDREA CHAMBERS
58 // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
59 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
60 // THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
61 //---------------------------------------------------------------------------
62 //
63 // LinuxLNK.C - COM functions required by MLANLLU.C, MLANTRNU.C, MLANNETU.C
64 // and MLanFile.C for MLANU to communicate with the DS2480 based
65 // Universal Serial Adapter 'U'. Platform specific code.
66 //
67 // Version: 2.01
68 // History: 1.02 -> 1.03 modifications by David Smiczek
69 // Changed to use generic OpenCOM/CloseCOM
70 // Pass port name to OpenCOM instead of hard coded
71 // Changed msDelay to handle long delays
72 // Reformatted to look like 'TODO.C'
73 // Added #include "ds2480.h" to use constants.
74 // Added function SetBaudCOM()
75 // Added function msGettick()
76 // Removed delay from WriteCOM(), used tcdrain()
77 // Added wait for byte available with timeout using
78 // select() in ReadCOM()
79 //
80 // 1.03 -> 2.00 Support for multiple ports. Include "ownet.h". Use
81 // 'uchar'. Reorder functions. Provide correct
82 // return values to OpenCOM. Replace 'makeraw' call.
83 // Should now be POSIX.
84 // 2.00 -> 2.01 Added support for owError library.
85 //
86
87 #include <unistd.h>
88 #include <sys/types.h>
89 #include <sys/stat.h>
90 #include <fcntl.h>
91 #include <sys/ioctl.h>
92 #include <time.h>
93 #include <termios.h>
94 #include <errno.h>
95 #include <sys/time.h>
96 #include <sys/file.h>
97
98 #include "ds2480.h"
99 #include "ownet.h"
100
101 /* exportable functions */
102 SMALLINT OpenCOM(int, char*);
103 SMALLINT WriteCOM(int, int, uchar*);
104 void CloseCOM(int);
105 void FlushCOM(int);
106 int ReadCOM(int, int, uchar*);
107 void BreakCOM(int);
108 void SetBaudCOM(int, uchar);
109 void msDelay(int);
110 long msGettick(void);
111
112 // LinuxLNK global
113 int fd[MAX_PORTNUM];
114 struct termios origterm;
115
116 //---------------------------------------------------------------------------
117 // Attempt to open a com port.
118 // Set the starting baud rate to 9600.
119 //
120 // 'portnum' - number 0 to MAX_PORTNUM-1. This number provided will
121 // be used to indicate the port number desired when calling
122 // all other functions in this library.
123 //
124 // 'port_zstr' - zero terminate port name. For this platform
125 // use format COMX where X is the port number.
126 //
127 //
128 // Returns: TRUE(1) - success, COM port opened
129 // FALSE(0) - failure, could not open specified port
130 //
OpenCOM(int portnum,char * port_zstr)131 SMALLINT OpenCOM(int portnum, char *port_zstr)
132 {
133 struct termios t; // see man termios - declared as above
134 int rc;
135
136 fd[portnum] = open(port_zstr, O_RDWR|O_NONBLOCK);
137 if (fd[portnum]<0)
138 {
139 OWERROR(OWERROR_GET_SYSTEM_RESOURCE_FAILED);
140 return FALSE; // changed (2.00), used to return fd;
141 }
142
143 /* Lock the device */
144 if(flock(fd[portnum], LOCK_EX|LOCK_NB))
145 {
146 OWERROR(OWERROR_GET_SYSTEM_RESOURCE_FAILED);
147 return FALSE;
148 }
149
150 rc = tcgetattr (fd[portnum], &t);
151 if (rc < 0)
152 {
153 int tmp;
154 tmp = errno;
155 close(fd[portnum]);
156 errno = tmp;
157 OWERROR(OWERROR_SYSTEM_RESOURCE_INIT_FAILED);
158 return FALSE; // changed (2.00), used to return rc;
159 }
160
161 cfsetospeed(&t, B9600);
162 cfsetispeed (&t, B9600);
163
164 // Get terminal parameters. (2.00) removed raw
165 tcgetattr(fd[portnum],&t);
166 // Save original settings.
167 origterm = t;
168
169 // Set to non-canonical mode, and no RTS/CTS handshaking
170 t.c_iflag &= ~(BRKINT|ICRNL|IGNCR|INLCR|INPCK|ISTRIP|IXON|IXOFF|PARMRK);
171 t.c_iflag |= IGNBRK|IGNPAR;
172 t.c_oflag &= ~(OPOST);
173 t.c_cflag &= ~(CRTSCTS|CSIZE|HUPCL|PARENB);
174 t.c_cflag |= (CLOCAL|CS8|CREAD);
175 t.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ICANON|IEXTEN|ISIG);
176 t.c_cc[VMIN] = 0;
177 t.c_cc[VTIME] = 3;
178
179 rc = tcsetattr(fd[portnum], TCSAFLUSH, &t);
180 tcflush(fd[portnum],TCIOFLUSH);
181
182 if (rc < 0)
183 {
184 int tmp;
185 tmp = errno;
186 close(fd[portnum]);
187 errno = tmp;
188 OWERROR(OWERROR_SYSTEM_RESOURCE_INIT_FAILED);
189 return FALSE; // changed (2.00), used to return rc;
190 }
191
192 return TRUE; // changed (2.00), used to return fd;
193 }
194
195
196 //---------------------------------------------------------------------------
197 // Closes the connection to the port.
198 //
199 // 'portnum' - number 0 to MAX_PORTNUM-1. This number was provided to
200 // OpenCOM to indicate the port number.
201 //
CloseCOM(int portnum)202 void CloseCOM(int portnum)
203 {
204 // restore tty settings
205 tcsetattr(fd[portnum], TCSAFLUSH, &origterm);
206 FlushCOM(portnum);
207 close(fd[portnum]);
208 }
209
210
211 //--------------------------------------------------------------------------
212 // Write an array of bytes to the COM port, verify that it was
213 // sent out. Assume that baud rate has been set.
214 //
215 // 'portnum' - number 0 to MAX_PORTNUM-1. This number provided will
216 // be used to indicate the port number desired when calling
217 // all other functions in this library.
218 // Returns 1 for success and 0 for failure
219 //
WriteCOM(int portnum,int outlen,uchar * outbuf)220 SMALLINT WriteCOM(int portnum, int outlen, uchar *outbuf)
221 {
222 long count = outlen;
223 int i = write(fd[portnum], outbuf, outlen);
224
225 tcdrain(fd[portnum]);
226 return (i == count);
227 }
228
229
230 //--------------------------------------------------------------------------
231 // Read an array of bytes to the COM port, verify that it was
232 // sent out. Assume that baud rate has been set.
233 //
234 // 'portnum' - number 0 to MAX_PORTNUM-1. This number was provided to
235 // OpenCOM to indicate the port number.
236 // 'outlen' - number of bytes to write to COM port
237 // 'outbuf' - pointer ot an array of bytes to write
238 //
239 // Returns: Number of bytes actually read
240 //
ReadCOM(int portnum,int inlen,uchar * inbuf)241 int ReadCOM(int portnum, int inlen, uchar *inbuf)
242 {
243 fd_set filedescr;
244 struct timeval tval;
245 int cnt;
246 int sel;
247 int msec = 0;
248 extern int global_msec,
249 global_msec_max;
250
251
252 // loop to wait until each byte is available and read it
253 for (cnt = 0; cnt < inlen; cnt++)
254 {
255 if( msec < global_msec )
256 msec = global_msec;
257
258 // set a descriptor to wait for a character available
259 FD_ZERO(&filedescr);
260 FD_SET(fd[portnum],&filedescr);
261 // set initial timeout to global_msec ms
262 tval.tv_sec = 1;
263 tval.tv_usec = 1000 * msec;
264
265 // if byte available read or return bytes read
266 sel = select(fd[portnum]+1,&filedescr,NULL,NULL,&tval);
267 if ( sel > 0 )
268 {
269 if (read(fd[portnum],&inbuf[cnt],1) != 1)
270 {
271 /* Received something, return it */
272 return cnt;
273 }
274 } else if( sel == 0 ) {
275 /* We timed out waiting for a character, so increase the limit */
276 global_msec++;
277 cnt = -1;
278
279 #ifdef DEBUG_USERIAL
280 fprintf(stderr, "Increasing delay to %ld\n", global_msec * 1000 );
281 #endif /* DEBUG_USERIAL */
282
283 /* don't go too high, just return an error (0) */
284 if( global_msec > global_msec_max )
285 return 0;
286 } else {
287 return cnt;
288 } /* select if */
289 } /* count loop */
290
291 // success, so return desired length
292 return inlen;
293 }
294
295
296 //---------------------------------------------------------------------------
297 // Description:
298 // flush the rx and tx buffers
299 //
300 // 'portnum' - number 0 to MAX_PORTNUM-1. This number was provided to
301 // OpenCOM to indicate the port number.
302 //
FlushCOM(int portnum)303 void FlushCOM(int portnum)
304 {
305 tcflush(fd[portnum], TCIOFLUSH);
306 }
307
308
309 //--------------------------------------------------------------------------
310 // Description:
311 // Send a break on the com port for at least 2 ms
312 //
313 // 'portnum' - number 0 to MAX_PORTNUM-1. This number was provided to
314 // OpenCOM to indicate the port number.
315 //
BreakCOM(int portnum)316 void BreakCOM(int portnum)
317 {
318 int duration = 0; // see man termios break may be
319 tcsendbreak(fd[portnum], duration); // too long
320 }
321
322
323 //--------------------------------------------------------------------------
324 // Set the baud rate on the com port.
325 //
326 // 'portnum' - number 0 to MAX_PORTNUM-1. This number was provided to
327 // OpenCOM to indicate the port number.
328 // 'new_baud' - new baud rate defined as
329 // PARMSET_9600 0x00
330 // PARMSET_19200 0x02
331 // PARMSET_57600 0x04
332 // PARMSET_115200 0x06
333 //
SetBaudCOM(int portnum,uchar new_baud)334 void SetBaudCOM(int portnum, uchar new_baud)
335 {
336 struct termios t;
337 int rc;
338 speed_t baud=B9600;
339
340 // read the attribute structure
341 rc = tcgetattr(fd[portnum], &t);
342 if (rc < 0)
343 {
344 close(fd[portnum]);
345 return;
346 }
347
348 // convert parameter to linux baud rate
349 switch(new_baud)
350 {
351 case PARMSET_9600:
352 baud = B9600;
353 break;
354 case PARMSET_19200:
355 baud = B19200;
356 break;
357 case PARMSET_57600:
358 baud = B57600;
359 break;
360 case PARMSET_115200:
361 baud = B115200;
362 break;
363 }
364
365 // set baud in structure
366 cfsetospeed(&t, baud);
367 cfsetispeed(&t, baud);
368
369 // change baud on port
370 rc = tcsetattr(fd[portnum], TCSAFLUSH, &t);
371 if (rc < 0)
372 close(fd[portnum]);
373 }
374
375
376 //--------------------------------------------------------------------------
377 // Get the current millisecond tick count. Does not have to represent
378 // an actual time, it just needs to be an incrementing timer.
379 //
msGettick(void)380 long msGettick(void)
381 {
382 struct timezone tmzone;
383 struct timeval tmval;
384 long ms;
385
386 gettimeofday(&tmval,&tmzone);
387 ms = (tmval.tv_sec & 0xFFFF) * 1000 + tmval.tv_usec / 1000;
388 return ms;
389 }
390
391
392 //--------------------------------------------------------------------------
393 // Description:
394 // Delay for at least 'len' ms
395 //
msDelay(int len)396 void msDelay(int len)
397 {
398 struct timespec s; // Set aside memory space on the stack
399
400 s.tv_sec = len / 1000;
401 s.tv_nsec = (len - (s.tv_sec * 1000)) * 1000000;
402 nanosleep(&s, NULL);
403 }
404
405