Subversion Repositories Projects

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
213 dhylands 1
/****************************************************************************
2
*
3
*   Copyright (c) 2009 Dave Hylands     <dhylands@gmail.com>
4
*
5
*   This program is free software; you can redistribute it and/or modify
6
*   it under the terms of the GNU General Public License version 2 as
7
*   published by the Free Software Foundation.
8
*
9
*   Alternatively, this software may be distributed under the terms of BSD
10
*   license.
11
*
12
*   See README and COPYING for more details.
13
*
14
****************************************************************************/
15
/**
16
*
17
*   @file   SerialPort.cpp
18
*
19
*   @brief  This file implements the SerialPort class using the posix
20
*           API, which is supported by cygwin and linux.
21
*
22
****************************************************************************/
23
 
24
// ---- Include Files -------------------------------------------------------
25
 
26
#include "Log.h"
27
#include "SerialPort.h"
28
#include "Str.h"
29
 
30
#include <stdio.h>
31
#include <stdlib.h>
32
#include <termios.h>
33
#include <errno.h>
34
#include <fcntl.h>
35
#include <sys/unistd.h>
36
#include <string.h>
37
#include <sys/ioctl.h>
38
 
39
// ---- Public Variables ----------------------------------------------------
40
 
41
// ---- Private Constants and Types -----------------------------------------
42
// ---- Private Variables ---------------------------------------------------
43
 
44
static struct
45
{
46
    speed_t     speed;
47
    unsigned    baudRate;
48
} gBaudTable[] =
49
{
50
    { B50,          50 },
51
    { B75,          75 },
52
    { B110,        110 },
53
    { B134,        134 },
54
    { B150,        150 },
55
    { B200,        200 },
56
    { B300,        300 },
57
    { B600,        600 },
58
    { B1200,      1200 },
59
    { B1800,      1800 },
60
    { B2400,      2400 },
61
    { B4800,      4800 },
62
    { B9600,      9600 },
63
    { B19200,    19200 },
64
    { B38400,    38400 },
65
    { B57600,    57600 },
66
    { B115200,  115200 },
67
    { B230400,  230400 },
68
    { B1000000,1000000 }
69
};
70
 
71
#define ARRAY_LEN(x)    ( sizeof( x ) / sizeof( x[ 0 ]))
72
 
73
// ---- Private Function Prototypes -----------------------------------------
74
// ---- Functions -----------------------------------------------------------
75
 
76
/**
77
 * @addtogroup SerialPort
78
 * @{
79
 */
80
 
81
//***************************************************************************
82
/**
83
*   Constructor
84
*/
85
 
86
SerialPort::SerialPort()
87
    : m_fd( -1 )
88
{
89
}
90
 
91
//***************************************************************************
92
/**
93
*   Destructor
94
*/
95
 
96
SerialPort::~SerialPort()
97
{
98
    Close();
99
}
100
 
101
//***************************************************************************
102
/**
103
*   Closes a previously opened serial port
104
*/
105
 
106
void SerialPort::Close()
107
{
108
    if ( m_fd >= 0 )
109
    {
110
        close( m_fd );
111
 
112
        m_fd = -1;
113
    }
114
 
115
} // Close
116
 
117
//***************************************************************************
118
/**
119
*   Opens a serial port.
120
*/
121
 
122
bool SerialPort::Open( const char *inDevName, const char *param )
123
{
124
    char        devName[ 40 ];
125
    unsigned    baudRate;
126
 
127
    devName[ 0 ] = '\0';
128
 
129
#if 1
130
    if ( inDevName[ 0 ] != '/' )
131
    {
132
        StrMaxCpy( devName, "/dev/", sizeof( devName ));
133
    }
134
#endif
135
    StrMaxCat( devName, inDevName, sizeof( devName ));
136
 
137
    // Translate the params, if any
138
 
139
    speed_t speed = B0;
140
    if ( param == NULL )
141
    {
142
        speed = B38400;
143
        baudRate = 38400;
144
    }
145
    else
146
    {
147
        baudRate = atoi( param );
148
 
149
        for ( unsigned i = 0; i < ARRAY_LEN( gBaudTable ); i++ )
150
        {
151
            if ( gBaudTable[ i ].baudRate == baudRate )
152
            {
153
                speed = gBaudTable[ i ].speed;
154
                break;
155
            }
156
        }
157
 
158
        if ( speed == B0 )
159
        {
160
            LogError( "Unrecognized baud rate: '%s'\n", param );
161
            return false;
162
        }
163
    }
164
 
165
    LogVerbose( "Port: '%s' Baud: %d\n", devName, baudRate );
166
 
167
    if (( m_fd = open( devName, O_RDWR | O_EXCL )) < 0 )
168
    {
169
        LogError( "Unable to open serial port '%s': %s\n", devName, strerror( errno ));
170
        return false;
171
    }
172
 
173
    // Setup the serial port
174
 
175
    struct termios  attr;
176
 
177
    if ( tcgetattr( m_fd, &attr ) < 0 )
178
    {
179
        LogError( "A: Call to tcgetattr failed: %s\n", strerror( errno ));
180
        return false;
181
    }
182
 
183
    attr.c_iflag = 0;
184
    attr.c_oflag = 0;
185
    attr.c_cflag = CLOCAL | CREAD | CS8;
186
    attr.c_lflag = 0;
187
    attr.c_cc[ VTIME ] = 0;   // timeout in tenths of a second
188
    attr.c_cc[ VMIN ] = 1;
189
 
190
    cfsetispeed( &attr, speed );
191
    cfsetospeed( &attr, speed );
192
 
193
    if ( tcsetattr( m_fd, TCSAFLUSH, &attr ) < 0 )
194
    {
195
        LogError( "Call to tcsetattr failed: %s\n", strerror( errno ));
196
        return false;
197
    }
198
 
199
    return true;
200
 
201
} // Open
202
 
203
//***************************************************************************
204
/**
205
*   Reads data from the serial port.
206
*/
207
 
208
size_t SerialPort::Read( void *buf, size_t bufSize )
209
{
210
    int  bytesRead;
211
 
212
    if ( m_fd < 0 )
213
    {
214
        return 0;
215
    }
216
 
217
    bytesRead = read( m_fd, buf, bufSize );
218
    if ( bytesRead < 0 )
219
    {
220
        if ( errno != EBADF )
221
        {
222
            // We get EBADF returned if the serial port is closed on
223
            // us.
224
 
225
            LogError( "read failed: %d\n", errno );
226
        }
227
        return 0;
228
    }
229
 
230
    return bytesRead;
231
 
232
} // Read
233
 
234
//***************************************************************************
235
/**
236
*   Sets the timeout to use when waiting for data. 0 = infinite
237
*   The timeout is specified in 1/10ths of a second.
238
*/
239
bool SerialPort::SetTimeout( uint8_t timeout )
240
{
241
    struct termios  attr;
242
 
243
    if ( tcgetattr( m_fd, &attr ) < 0 )
244
    {
245
        LogError( "B: Call to tcgetattr failed: %s\n", strerror( errno ));
246
        return false;
247
    }
248
 
249
    if ( timeout == 0 )
250
    {
251
        attr.c_cc[ VTIME ] = 0;
252
        attr.c_cc[ VMIN ]  = 1;
253
    }
254
    else
255
    {
256
        attr.c_cc[ VTIME ] = timeout;   // timeout in tenths of a second
257
        attr.c_cc[ VMIN ]  = 0;
258
    }
259
 
260
    if ( tcsetattr( m_fd, TCSAFLUSH, &attr ) < 0 )
261
    {
262
        LogError( "Call to tcsetattr failed: %s\n", strerror( errno ));
263
        return false;
264
    }
265
 
266
    return true;
267
 
268
} // SetTimeout
269
 
270
//***************************************************************************
271
/**
272
*   Writes data to the serial port.
273
*/
274
 
275
size_t SerialPort::Write( const void *buf, size_t bytesToWrite )
276
{
277
    int  bytesWritten;
278
 
279
    bytesWritten = write( m_fd, buf, bytesToWrite );
280
    if ( bytesWritten < 0 )
281
    {
282
        LogError( "write failed: %d\n", errno );
283
        bytesWritten = 0;
284
    }
285
 
286
    return bytesWritten;
287
 
288
} // Write
289
 
290
//***************************************************************************
291
/**
292
*   Resets the target
293
*/
294
 
295
void SerialPort::StrobeRTS( int strobeWidthInMsec )
296
{
297
    int bits = TIOCM_RTS;
298
 
299
    // On my computer downstairs, settinging the RTS line makes it low.
300
 
301
    ioctl( m_fd, TIOCMBIS, &bits );
302
 
303
    // Sleep for 10 msec to allow the reset to take effect.
304
 
305
    usleep( strobeWidthInMsec * 1000 );
306
 
307
    // On my computer downstairs, clearing the RTS line makes it high.
308
 
309
    ioctl( m_fd, TIOCMBIC, &bits );
310
 
311
} // StrobeRTS
312
 
313
/** @} */
314