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 <string.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, int);
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    rc = tcgetattr (fd[portnum], &t);
143    if (rc < 0)
144    {
145       int tmp;
146       tmp = errno;
147       close(fd[portnum]);
148       errno = tmp;
149       OWERROR(OWERROR_SYSTEM_RESOURCE_INIT_FAILED);
150       return FALSE; // changed (2.00), used to return rc;
151    }
152 
153    cfsetospeed(&t, B9600);
154    cfsetispeed (&t, B9600);
155 
156    // Get terminal parameters. (2.00) removed raw
157    tcgetattr(fd[portnum],&t);
158    // Save original settings.
159    origterm = t;
160 
161    // Set to non-canonical mode, and no RTS/CTS handshaking
162    t.c_iflag &= ~(BRKINT|ICRNL|IGNCR|INLCR|INPCK|ISTRIP|IXON|IXOFF|PARMRK);
163    t.c_iflag |= IGNBRK|IGNPAR;
164    t.c_oflag &= ~(OPOST);
165    t.c_cflag &= ~(CRTSCTS|CSIZE|HUPCL|PARENB);
166    t.c_cflag |= (CLOCAL|CS8|CREAD);
167    t.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ICANON|IEXTEN|ISIG);
168    t.c_cc[VMIN] = 0;
169    t.c_cc[VTIME] = 3;
170 
171    rc = tcsetattr(fd[portnum], TCSAFLUSH, &t);
172    tcflush(fd[portnum],TCIOFLUSH);
173 
174    if (rc < 0)
175    {
176       int tmp;
177       tmp = errno;
178       close(fd[portnum]);
179       errno = tmp;
180       OWERROR(OWERROR_SYSTEM_RESOURCE_INIT_FAILED);
181       return FALSE; // changed (2.00), used to return rc;
182    }
183 
184    return TRUE; // changed (2.00), used to return fd;
185 }
186 
187 
188 //---------------------------------------------------------------------------
189 // Closes the connection to the port.
190 //
191 // 'portnum'  - number 0 to MAX_PORTNUM-1.  This number was provided to
192 //              OpenCOM to indicate the port number.
193 //
CloseCOM(int portnum)194 void CloseCOM(int portnum)
195 {
196    // restore tty settings
197    tcsetattr(fd[portnum], TCSAFLUSH, &origterm);
198    FlushCOM(portnum);
199    close(fd[portnum]);
200 }
201 
202 
203 //--------------------------------------------------------------------------
204 // Write an array of bytes to the COM port, verify that it was
205 // sent out.  Assume that baud rate has been set.
206 //
207 // 'portnum'   - number 0 to MAX_PORTNUM-1.  This number provided will
208 //               be used to indicate the port number desired when calling
209 //               all other functions in this library.
210 // Returns 1 for success and 0 for failure
211 //
WriteCOM(int portnum,int outlen,uchar * outbuf)212 SMALLINT WriteCOM(int portnum, int outlen, uchar *outbuf)
213 {
214    long count = outlen;
215    int i = write(fd[portnum], outbuf, outlen);
216 
217    tcdrain(fd[portnum]);
218    return (i == count);
219 }
220 
221 
222 //--------------------------------------------------------------------------
223 // Read an array of bytes to the COM port, verify that it was
224 // sent out.  Assume that baud rate has been set.
225 //
226 // 'portnum'  - number 0 to MAX_PORTNUM-1.  This number was provided to
227 //              OpenCOM to indicate the port number.
228 // 'outlen'   - number of bytes to write to COM port
229 // 'outbuf'   - pointer ot an array of bytes to write
230 //
231 // Returns:  TRUE(1)  - success
232 //           FALSE(0) - failure
233 //
ReadCOM(int portnum,int inlen,uchar * inbuf)234 int ReadCOM(int portnum, int inlen, uchar *inbuf)
235 {
236    fd_set         filedescr;
237    struct timeval tval;
238    int            cnt;
239 
240    // loop to wait until each byte is available and read it
241    for (cnt = 0; cnt < inlen; cnt++)
242    {
243       // set a descriptor to wait for a character available
244       FD_ZERO(&filedescr);
245       FD_SET(fd[portnum],&filedescr);
246       // set timeout to 10ms
247       tval.tv_sec = 0;
248       tval.tv_usec = 10000;
249 
250       // if byte available read or return bytes read
251       if (select(fd[portnum]+1,&filedescr,NULL,NULL,&tval) != 0)
252       {
253          if (read(fd[portnum],&inbuf[cnt],1) != 1)
254             return cnt;
255       }
256       else
257          return cnt;
258    }
259 
260    // success, so return desired length
261    return inlen;
262 }
263 
264 
265 //---------------------------------------------------------------------------
266 //  Description:
267 //     flush the rx and tx buffers
268 //
269 // 'portnum'  - number 0 to MAX_PORTNUM-1.  This number was provided to
270 //              OpenCOM to indicate the port number.
271 //
FlushCOM(int portnum)272 void FlushCOM(int portnum)
273 {
274    tcflush(fd[portnum], TCIOFLUSH);
275 }
276 
277 
278 //--------------------------------------------------------------------------
279 //  Description:
280 //     Send a break on the com port for at least 2 ms
281 //
282 // 'portnum'  - number 0 to MAX_PORTNUM-1.  This number was provided to
283 //              OpenCOM to indicate the port number.
284 //
BreakCOM(int portnum)285 void BreakCOM(int portnum)
286 {
287    int duration = 0;              // see man termios break may be
288    tcsendbreak(fd[portnum], duration);     // too long
289 }
290 
291 
292 //--------------------------------------------------------------------------
293 // Set the baud rate on the com port.
294 //
295 // 'portnum'   - number 0 to MAX_PORTNUM-1.  This number was provided to
296 //               OpenCOM to indicate the port number.
297 // 'new_baud'  - new baud rate defined as
298 // PARMSET_9600     0x00
299 // PARMSET_19200    0x02
300 // PARMSET_57600    0x04
301 // PARMSET_115200   0x06
302 //
SetBaudCOM(int portnum,int new_baud)303 void SetBaudCOM(int portnum, int new_baud)
304 {
305    struct termios t;
306    int rc;
307    speed_t baud;
308 
309    // read the attribute structure
310    rc = tcgetattr(fd[portnum], &t);
311    if (rc < 0)
312    {
313       close(fd[portnum]);
314       return;
315    }
316 
317    // convert parameter to linux baud rate
318    switch(new_baud)
319    {
320       case PARMSET_9600:
321          baud = B9600;
322          break;
323       case PARMSET_19200:
324          baud = B19200;
325          break;
326       case PARMSET_57600:
327          baud = B57600;
328          break;
329       case PARMSET_115200:
330          baud = B115200;
331          break;
332    }
333 
334    // set baud in structure
335    cfsetospeed(&t, baud);
336    cfsetispeed(&t, baud);
337 
338    // change baud on port
339    rc = tcsetattr(fd[portnum], TCSAFLUSH, &t);
340    if (rc < 0)
341       close(fd[portnum]);
342 }
343 
344 
345 //--------------------------------------------------------------------------
346 // Get the current millisecond tick count.  Does not have to represent
347 // an actual time, it just needs to be an incrementing timer.
348 //
msGettick(void)349 long msGettick(void)
350 {
351    struct timezone tmzone;
352    struct timeval  tmval;
353    long ms;
354 
355    gettimeofday(&tmval,&tmzone);
356    ms = (tmval.tv_sec & 0xFFFF) * 1000 + tmval.tv_usec / 1000;
357    return ms;
358 }
359 
360 
361 //--------------------------------------------------------------------------
362 //  Description:
363 //     Delay for at least 'len' ms
364 //
msDelay(int len)365 void msDelay(int len)
366 {
367    struct timespec s;              // Set aside memory space on the stack
368 
369    s.tv_sec = len / 1000;
370    s.tv_nsec = (len - (s.tv_sec * 1000)) * 1000000;
371    nanosleep(&s, NULL);
372 }
373 
374