comio_nix.c 11 KB
Newer Older
deuce's avatar
deuce committed
1 2 3 4
/* comio_nix.c */

/* Synchronet Serial Communications I/O Library Functions for *nix */

5
/* $Id: comio_nix.c,v 1.19 2020/06/27 08:23:39 deuce Exp $ */
deuce's avatar
deuce committed
6 7

/****************************************************************************
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
 * @format.tab-size 4       (Plain Text/Source Code File Header)            *
 * @format.use-tabs true    (see http://www.synchro.net/ptsc_hdr.html)      *
 *                                                                          *
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html           *
 *                                                                          *
 * This library is free software; you can redistribute it and/or            *
 * modify it under the terms of the GNU Lesser General Public License       *
 * as published by the Free Software Foundation; either version 2           *
 * of the License, or (at your option) any later version.                   *
 * See the GNU Lesser General Public License for more details: lgpl.txt or  *
 * http://www.fsf.org/copyleft/lesser.html                                  *
 *                                                                          *
 * Anonymous FTP access to the most recent released source is available at  *
 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net  *
 *                                                                          *
 * Anonymous CVS access to the development source and modification history  *
 * is available at cvs.synchro.net:/cvsroot/sbbs, example:                  *
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login            *
 *     (just hit return, no password is necessary)                          *
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src     *
 *                                                                          *
 * For Synchronet coding style and modification guidelines, see             *
 * http://www.synchro.net/source.html                                       *
 *                                                                          *
 * You are encouraged to submit any modifications (preferably in Unix diff  *
 * format) via e-mail to mods@synchro.net                                   *
 *                                                                          *
 * Note: If this box doesn't appear square, then you need to fix your tabs. *
deuce's avatar
deuce committed
36 37
 ****************************************************************************/

deuce's avatar
deuce committed
38
#include <sys/ioctl.h>
deuce's avatar
deuce committed
39
#include <sys/file.h>
40
#include <fcntl.h>      // O_NONBLOCK
deuce's avatar
deuce committed
41 42 43
#include "comio.h"
#include "genwrap.h"

44 45 46 47 48 49 50 51 52 53 54 55 56 57
#if defined(CCTS_OFLOW) && defined(CRTS_IFLOW)
 #define CTSRTS_FLOW_CFLAGS (CCTS_OFLOW | CRTS_IFLOW)
#elif defined(CRTSCTS)
 #define CTSRTS_FLOW_CFLAGS (CRTSCTS)
#else
 #error No way to control CTS/RTS flow control
#endif

#if defined(IXON) && defined (IXOFF)
 #define XONXOFF_FLOW_IFLAGS (IXON | IXOFF)
#else
 #error No way to control XON/XOFF flow control
#endif

58 59 60
#ifdef SPEED_MACROS_ONLY

#define SUPPORTED_SPEED(x) \
61 62
    if (speed <= (x)) \
        return B##x
63 64 65

speed_t rate_to_macro(unsigned long speed)
{
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
    // Standard values
    SUPPORTED_SPEED(0);
    SUPPORTED_SPEED(50);
    SUPPORTED_SPEED(75);
    SUPPORTED_SPEED(110);
    SUPPORTED_SPEED(134);
    SUPPORTED_SPEED(150);
    SUPPORTED_SPEED(200);
    SUPPORTED_SPEED(300);
    SUPPORTED_SPEED(600);
    SUPPORTED_SPEED(1200);
    SUPPORTED_SPEED(1800);
    SUPPORTED_SPEED(2400);
    SUPPORTED_SPEED(4800);
    SUPPORTED_SPEED(9600);
    SUPPORTED_SPEED(19200);
    SUPPORTED_SPEED(38400);

    // Non-POSIX
85
#ifdef B57600
86
    SUPPORTED_SPEED(57600);
87 88
#endif
#ifdef B115200
89
    SUPPORTED_SPEED(115200);
90 91
#endif
#ifdef B230400
92
    SUPPORTED_SPEED(230400);
93 94
#endif
#ifdef B460800
95
    SUPPORTED_SPEED(460800);
96 97
#endif
#ifdef B500000
98
    SUPPORTED_SPEED(500000);
99 100
#endif
#ifdef B576000
101
    SUPPORTED_SPEED(576000);
102 103
#endif
#ifdef B921600
104
    SUPPORTED_SPEED(921600);
105 106
#endif
#ifdef B1000000
107
    SUPPORTED_SPEED(1000000);
108 109
#endif
#ifdef B1152000
110
    SUPPORTED_SPEED(1152000);
111 112
#endif
#ifdef B1500000
113
    SUPPORTED_SPEED(1500000);
114 115
#endif
#ifdef B2000000
116
    SUPPORTED_SPEED(2000000);
117 118
#endif
#ifdef B2500000
119
    SUPPORTED_SPEED(2500000);
120 121
#endif
#ifdef B3000000
122
    SUPPORTED_SPEED(3000000);
123 124
#endif
#ifdef B3500000
125
    SUPPORTED_SPEED(3500000);
126 127
#endif
#ifdef B4000000
128
    SUPPORTED_SPEED(4000000);
129
#endif
130
    return B0;
131 132 133
}
#undef SUPPORTED_SPEED
#define SUPPORTED_SPEED(x) \
134 135
    if (speed == B##x) \
        return x;
136 137 138

unsigned long macro_to_rate(speed_t speed)
{
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
    // Standard values
    SUPPORTED_SPEED(0);
    SUPPORTED_SPEED(50);
    SUPPORTED_SPEED(75);
    SUPPORTED_SPEED(110);
    SUPPORTED_SPEED(134);
    SUPPORTED_SPEED(150);
    SUPPORTED_SPEED(200);
    SUPPORTED_SPEED(300);
    SUPPORTED_SPEED(600);
    SUPPORTED_SPEED(1200);
    SUPPORTED_SPEED(1800);
    SUPPORTED_SPEED(2400);
    SUPPORTED_SPEED(4800);
    SUPPORTED_SPEED(9600);
    SUPPORTED_SPEED(19200);
    SUPPORTED_SPEED(38400);

    // Non-POSIX
158
#ifdef B57600
159
    SUPPORTED_SPEED(57600);
160 161
#endif
#ifdef B115200
162
    SUPPORTED_SPEED(115200);
163 164
#endif
#ifdef B230400
165
    SUPPORTED_SPEED(230400);
166 167
#endif
#ifdef B460800
168
    SUPPORTED_SPEED(460800);
169 170
#endif
#ifdef B500000
171
    SUPPORTED_SPEED(500000);
172 173
#endif
#ifdef B576000
174
    SUPPORTED_SPEED(576000);
175 176
#endif
#ifdef B921600
177
    SUPPORTED_SPEED(921600);
178 179
#endif
#ifdef B1000000
180
    SUPPORTED_SPEED(1000000);
181 182
#endif
#ifdef B1152000
183
    SUPPORTED_SPEED(1152000);
184 185
#endif
#ifdef B1500000
186
    SUPPORTED_SPEED(1500000);
187 188
#endif
#ifdef B2000000
189
    SUPPORTED_SPEED(2000000);
190 191
#endif
#ifdef B2500000
192
    SUPPORTED_SPEED(2500000);
193 194
#endif
#ifdef B3000000
195
    SUPPORTED_SPEED(3000000);
196 197
#endif
#ifdef B3500000
198
    SUPPORTED_SPEED(3500000);
199 200
#endif
#ifdef B4000000
201
    SUPPORTED_SPEED(4000000);
202
#endif
203
    return 0;
204 205 206 207
}
#undef SUPPORTED_SPEED

#else
208 209
#define rate_to_macro(x)    (x)
#define macro_to_rate(x)    (x)
210 211
#endif

deuce's avatar
deuce committed
212
char* comVersion(char* str, size_t len)
deuce's avatar
deuce committed
213
{
214
    char revision[16];
deuce's avatar
deuce committed
215

216
    sscanf("$Revision: 1.19 $", "%*s %s", revision);
deuce's avatar
deuce committed
217

218 219
    safe_snprintf(str,len,"Synchronet Communications I/O Library for "PLATFORM_DESC" v%s", revision);
    return str;
deuce's avatar
deuce committed
220 221
}

deuce's avatar
deuce committed
222
COM_HANDLE comOpen(const char* device)
deuce's avatar
deuce committed
223
{
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
    COM_HANDLE handle;
    struct termios t;

    if((handle=open(device, O_NONBLOCK|O_RDWR))==COM_HANDLE_INVALID)
        return COM_HANDLE_INVALID;

    if(tcgetattr(handle, &t)==-1) {
        close(handle);
        return COM_HANDLE_INVALID;
    }

    t.c_iflag = (
                  IGNBRK   /* ignore BREAK condition */
                | IGNPAR   /* ignore (discard) parity errors */
                );
    t.c_oflag = 0;  /* No output processing */
    t.c_cflag = (
                  CS8         /* 8 bits */
                | CREAD       /* enable receiver */
deuce's avatar
deuce committed
243 244 245 246 247 248 249 250
/*
Fun snippet from the FreeBSD manpage:

     If CREAD is set, the receiver is enabled.  Otherwise, no character is
     received.  Not all hardware supports this bit.  In fact, this flag is
     pretty silly and if it were not part of the termios specification it
     would be omitted.
*/
251 252 253 254 255 256 257 258 259 260 261
                | HUPCL       /* hang up on last close */
                | CLOCAL      /* ignore modem status lines */
                | CTSRTS_FLOW_CFLAGS
                );
    t.c_lflag = 0;  /* No local modes */
    if(tcsetattr(handle, TCSANOW, &t)==-1) {
        close(handle);
        return COM_HANDLE_INVALID;
    }

    return handle;
deuce's avatar
deuce committed
262 263
}

deuce's avatar
deuce committed
264
BOOL comClose(COM_HANDLE handle)
deuce's avatar
deuce committed
265
{
266
    return (!close(handle));
deuce's avatar
deuce committed
267 268
}

deuce's avatar
deuce committed
269
long comGetBaudRate(COM_HANDLE handle)
deuce's avatar
deuce committed
270
{
271 272 273 274 275 276 277 278 279 280 281 282 283 284
    struct termios t;
    speed_t in;
    speed_t out;

    if(tcgetattr(handle, &t))
        return COM_ERROR;

    /*
     * We actually have TWO speeds available...
     * return the biggest one
     */
    in = macro_to_rate(cfgetispeed(&t));
    out = macro_to_rate(cfgetospeed(&t));
    return ((long)(in>out?in:out));
deuce's avatar
deuce committed
285 286
}

deuce's avatar
deuce committed
287
BOOL comSetBaudRate(COM_HANDLE handle, unsigned long rate)
deuce's avatar
deuce committed
288
{
289
    struct termios t;
deuce's avatar
deuce committed
290

291 292
    if(tcgetattr(handle, &t))
        return FALSE;
deuce's avatar
deuce committed
293

294 295 296 297
    cfsetispeed(&t, rate_to_macro(rate));
    cfsetospeed(&t, rate_to_macro(rate));
    if(tcsetattr(handle, TCSANOW, &t)==-1)
        return FALSE;
deuce's avatar
deuce committed
298

299
    return TRUE;
deuce's avatar
deuce committed
300 301
}

302
int comGetFlowControl(COM_HANDLE handle)
303
{
304 305
    int ret = 0;
    struct termios t;
306

307 308
    if(tcgetattr(handle, &t)==-1)
        return FALSE;
309

310 311 312 313
    if ((t.c_cflag & CTSRTS_FLOW_CFLAGS) == CTSRTS_FLOW_CFLAGS)
        ret |= COM_FLOW_CONTROL_RTS_CTS;
    if ((t.c_iflag & XONXOFF_FLOW_IFLAGS) == XONXOFF_FLOW_IFLAGS)
        ret |= COM_FLOW_CONTROL_XON_OFF;
314

315
    return ret;
316 317
}

318
BOOL comSetFlowControl(COM_HANDLE handle, int modes)
319
{
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
    struct termios t;

    if(tcgetattr(handle, &t)==-1)
        return FALSE;

    if (modes & COM_FLOW_CONTROL_RTS_CTS)
        t.c_cflag |= CTSRTS_FLOW_CFLAGS;
    else
        t.c_cflag &= ~CTSRTS_FLOW_CFLAGS;

    if (modes & COM_FLOW_CONTROL_XON_OFF)
        t.c_iflag |= XONXOFF_FLOW_IFLAGS;
    else
        t.c_iflag &= ~XONXOFF_FLOW_IFLAGS;

    if(tcsetattr(handle, TCSANOW, &t)==-1)
        return FALSE;

    return TRUE;
339 340
}

341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
BOOL comSetParity(COM_HANDLE handle, BOOL enable, BOOL odd)
{
    struct termios t;

    if(tcgetattr(handle, &t)==-1)
        return FALSE;

    if (enable) {
        t.c_cflag |= PARENB;
		if (odd)
			t.c_cflag |= PARODD;
		else
			t.c_cflag &= ~PARODD;
	} else
        t.c_cflag &= ~(PARENB | PARODD);

    if(tcsetattr(handle, TCSANOW, &t)==-1)
        return FALSE;

    return TRUE;
}

363 364 365 366 367
BOOL comSetBits(COM_HANDLE handle, size_t byteSize, size_t stopBits)
{
    struct termios t;

    if(tcgetattr(handle, &t)==-1)
368
		return FALSE;
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395

	t.c_cflag &= ~CSIZE;
	switch(byteSize) {
		case 5:
			t.c_cflag |= CS5;
			break;
		case 6:
			t.c_cflag |= CS6;
			break;
		case 7:
			t.c_cflag |= CS7;
			break;
		default:
			t.c_cflag |= CS8;
			break;
	}
	if(stopBits == 2)
		t.c_cflag |= CSTOPB;
	else
		t.c_cflag &= ~CSTOPB;

    if(tcsetattr(handle, TCSANOW, &t)==-1)
        return FALSE;

    return TRUE;
}

deuce's avatar
deuce committed
396
int comGetModemStatus(COM_HANDLE handle)
deuce's avatar
deuce committed
397
{
398
    int status;
deuce's avatar
deuce committed
399

400 401
    if(ioctl(handle, TIOCMGET, &status)==-1)
        return COM_ERROR;
deuce's avatar
deuce committed
402

403
    return status;
deuce's avatar
deuce committed
404 405
}

deuce's avatar
deuce committed
406 407
static BOOL comSetFlags(COM_HANDLE handle, int flags, BOOL set)
{
408
    int cmd = set ? TIOCMBIS : TIOCMBIC;
deuce's avatar
deuce committed
409

410
    return (ioctl(handle, cmd, &flags) == 0);
deuce's avatar
deuce committed
411 412
}

deuce's avatar
deuce committed
413
BOOL comRaiseDTR(COM_HANDLE handle)
deuce's avatar
deuce committed
414
{
415
    return comSetFlags(handle, TIOCM_DTR, TRUE);
deuce's avatar
deuce committed
416 417
}

deuce's avatar
deuce committed
418
BOOL comLowerDTR(COM_HANDLE handle)
deuce's avatar
deuce committed
419
{
420
    return comSetFlags(handle, TIOCM_DTR, FALSE);
deuce's avatar
deuce committed
421 422
}

deuce's avatar
deuce committed
423
BOOL comRaiseRTS(COM_HANDLE handle)
deuce's avatar
deuce committed
424
{
425
    return comSetFlags(handle, TIOCM_RTS, TRUE);
deuce's avatar
deuce committed
426 427
}

deuce's avatar
deuce committed
428
BOOL comLowerRTS(COM_HANDLE handle)
deuce's avatar
deuce committed
429
{
430
    return comSetFlags(handle, TIOCM_RTS, FALSE);
deuce's avatar
deuce committed
431
}
deuce's avatar
deuce committed
432
BOOL comWriteByte(COM_HANDLE handle, BYTE ch)
deuce's avatar
deuce committed
433
{
434
    return(write(handle, &ch, 1)==1);
deuce's avatar
deuce committed
435 436
}

deuce's avatar
deuce committed
437
int comWriteBuf(COM_HANDLE handle, const BYTE* buf, size_t buflen)
deuce's avatar
deuce committed
438
{
439
    return write(handle, buf, buflen);
deuce's avatar
deuce committed
440 441 442 443 444
}

/*
 * TODO: This seem kinda dangerous for short writes...
 */
deuce's avatar
deuce committed
445
int comWriteString(COM_HANDLE handle, const char* str)
deuce's avatar
deuce committed
446
{
447
    return comWriteBuf(handle, (BYTE*)str, strlen(str));
deuce's avatar
deuce committed
448 449
}

deuce's avatar
deuce committed
450
BOOL comReadByte(COM_HANDLE handle, BYTE* ch)
deuce's avatar
deuce committed
451
{
452
    return(read(handle, ch, 1)==1);
deuce's avatar
deuce committed
453 454
}

deuce's avatar
deuce committed
455
BOOL comPurgeInput(COM_HANDLE handle)
deuce's avatar
deuce committed
456
{
457
    return(tcflush(handle, TCIFLUSH)==0);
deuce's avatar
deuce committed
458 459
}

deuce's avatar
deuce committed
460
BOOL comPurgeOutput(COM_HANDLE handle)
deuce's avatar
deuce committed
461
{
462
    return(tcflush(handle, TCOFLUSH)==0);
deuce's avatar
deuce committed
463 464
}

deuce's avatar
deuce committed
465
BOOL comDrainOutput(COM_HANDLE handle)
466
{
467
    return(tcdrain(handle)==0);
468
}