|
| 1 | +// Serial inteface implementation for POSIX-compliant systems |
| 2 | + |
| 3 | +#include "serial.h" |
| 4 | +#include <stdio.h> |
| 5 | +#include <string.h> |
| 6 | +#include <unistd.h> |
| 7 | +#include <fcntl.h> |
| 8 | +#include <errno.h> |
| 9 | +#include <termios.h> |
| 10 | +#include <sys/select.h> |
| 11 | +#include <sys/time.h> |
| 12 | +#include <sys/types.h> |
| 13 | + |
| 14 | +static u32 ser_timeout = SER_INF_TIMEOUT; |
| 15 | + |
| 16 | +// Open the serial port |
| 17 | +ser_handler ser_open( const char* sername ) |
| 18 | +{ |
| 19 | + int fd; |
| 20 | + |
| 21 | + if( ( fd = open( sername, O_RDWR | O_NOCTTY | O_NDELAY ) ) == -1 ) |
| 22 | + perror( "ser_open: unable to open port" ); |
| 23 | + else |
| 24 | + fcntl( fd, F_SETFL, 0 ); |
| 25 | + return ( ser_handler )fd; |
| 26 | +} |
| 27 | + |
| 28 | +// Close the serial port |
| 29 | +void ser_close( ser_handler id ) |
| 30 | +{ |
| 31 | + close( ( int )id ); |
| 32 | +} |
| 33 | + |
| 34 | +// Helper function: get baud ID from actual baud rate |
| 35 | +#define BAUDCASE(x) case x: return B##x |
| 36 | +static u32 ser_baud_to_id( u32 baud ) |
| 37 | +{ |
| 38 | + switch( baud ) |
| 39 | + { |
| 40 | + BAUDCASE( 1200 ); |
| 41 | + BAUDCASE( 1800 ); |
| 42 | + BAUDCASE( 2400 ); |
| 43 | + BAUDCASE( 4800 ); |
| 44 | + BAUDCASE( 9600 ); |
| 45 | + BAUDCASE( 19200 ); |
| 46 | + BAUDCASE( 38400 ); |
| 47 | + BAUDCASE( 57600 ); |
| 48 | + BAUDCASE( 115200 ); |
| 49 | + BAUDCASE( 230400 ); |
| 50 | + } |
| 51 | + return 0; |
| 52 | +} |
| 53 | + |
| 54 | +// Helper function: get number of bits ID from actual number of bits |
| 55 | +#define NBCASE(x) case x: return CS##x |
| 56 | +static int ser_number_of_bits_to_id( int nb ) |
| 57 | +{ |
| 58 | + switch( nb ) |
| 59 | + { |
| 60 | + NBCASE( 5 ); |
| 61 | + NBCASE( 6 ); |
| 62 | + NBCASE( 7 ); |
| 63 | + NBCASE( 8 ); |
| 64 | + } |
| 65 | + return 0; |
| 66 | +} |
| 67 | + |
| 68 | +int ser_setup( ser_handler id, u32 baud, int databits, int parity, int stopbits ) |
| 69 | +{ |
| 70 | + struct termios termdata; |
| 71 | + int hnd = ( int )id; |
| 72 | + |
| 73 | + usleep( 200000 ); |
| 74 | + tcgetattr( hnd, &termdata ); |
| 75 | + |
| 76 | + // Baud rate |
| 77 | + cfsetispeed( &termdata, ser_baud_to_id( baud ) ); |
| 78 | + cfsetospeed( &termdata, ser_baud_to_id( baud ) ); |
| 79 | + |
| 80 | + // Parity / stop bits |
| 81 | + termdata.c_cflag &= ~CSTOPB; |
| 82 | + if( parity == SER_PARITY_NONE ) // no parity |
| 83 | + { |
| 84 | + termdata.c_cflag &= ~PARENB; |
| 85 | + } |
| 86 | + else if( parity == SER_PARITY_EVEN ) // even parity |
| 87 | + { |
| 88 | + termdata.c_cflag |= PARENB; |
| 89 | + termdata.c_cflag &= ~PARODD; |
| 90 | + } |
| 91 | + else if( parity == SER_PARITY_ODD ) // odd parity |
| 92 | + { |
| 93 | + termdata.c_cflag |= PARENB; |
| 94 | + termdata.c_cflag |= PARODD; |
| 95 | + } |
| 96 | + |
| 97 | + // Data bits |
| 98 | + termdata.c_cflag |= ( CLOCAL | CREAD ); |
| 99 | + termdata.c_cflag &= ~CSIZE; |
| 100 | + termdata.c_cflag |= ser_number_of_bits_to_id( databits ); |
| 101 | + |
| 102 | + // Disable HW and SW flow control |
| 103 | + termdata.c_cflag &= ~CRTSCTS; |
| 104 | + termdata.c_iflag &= ~( IXON | IXOFF | IXANY ); |
| 105 | + |
| 106 | + // Raw input |
| 107 | + termdata.c_lflag &= ~( ICANON | ECHO | ECHOE | ISIG ); |
| 108 | + |
| 109 | + // Raw output |
| 110 | + termdata.c_oflag &= ~OPOST; |
| 111 | + |
| 112 | + // Check and strip parity bit |
| 113 | + if( parity == SER_PARITY_NONE ) |
| 114 | + termdata.c_iflag &= ~( INPCK | ISTRIP ); |
| 115 | + else |
| 116 | + termdata.c_iflag |= ( INPCK | ISTRIP ); |
| 117 | + |
| 118 | + // Setup timeouts |
| 119 | + termdata.c_cc[ VMIN ] = 1; |
| 120 | + termdata.c_cc[ VTIME ] = 0; |
| 121 | + |
| 122 | + // Set the attibutes now |
| 123 | + tcsetattr( hnd, TCSANOW, &termdata ); |
| 124 | + |
| 125 | + // Flush everything |
| 126 | + tcflush( hnd, TCIOFLUSH ); |
| 127 | + |
| 128 | + // And set blocking mode by default |
| 129 | + fcntl( id, F_SETFL, 0 ); |
| 130 | +} |
| 131 | + |
| 132 | +// Read up to the specified number of bytes, return bytes actually read |
| 133 | +u32 ser_read( ser_handler id, u8* dest, u32 maxsize ) |
| 134 | +{ |
| 135 | + if( ser_timeout == SER_INF_TIMEOUT ) |
| 136 | + return ( u32 )read( ( int )id, dest, maxsize ); |
| 137 | + else |
| 138 | + { |
| 139 | + fd_set readfs; |
| 140 | + struct timeval tv; |
| 141 | + int retval; |
| 142 | + |
| 143 | + FD_ZERO( &readfs ); |
| 144 | + FD_SET( ( int )id, &readfs ); |
| 145 | + tv.tv_sec = ser_timeout / 1000000; |
| 146 | + tv.tv_usec = ( ser_timeout % 1000000 ) * 1000; |
| 147 | + retval = select( ( int )id + 1, &readfs, NULL, NULL, &tv ); |
| 148 | + if( retval == -1 || retval == 0 ) |
| 149 | + return 0; |
| 150 | + else |
| 151 | + return ( u32 )read( ( int )id, dest, maxsize ); |
| 152 | + } |
| 153 | +} |
| 154 | + |
| 155 | +// Read a single byte and return it (or -1 for error) |
| 156 | +int ser_read_byte( ser_handler id ) |
| 157 | +{ |
| 158 | + u8 data; |
| 159 | + int res = ser_read( id, &data, 1 ); |
| 160 | + |
| 161 | + return res == 1 ? data : -1; |
| 162 | +} |
| 163 | + |
| 164 | +// Write up to the specified number of bytes, return bytes actually written |
| 165 | +u32 ser_write( ser_handler id, const u8 *src, u32 size ) |
| 166 | +{ |
| 167 | + u32 res; |
| 168 | + |
| 169 | + res = ( u32 )write( ( int )id, src, size ); |
| 170 | + return res; |
| 171 | +} |
| 172 | + |
| 173 | +// Write a byte to the serial port |
| 174 | +u32 ser_write_byte( ser_handler id, u8 data ) |
| 175 | +{ |
| 176 | + return ( u32 )write( id, &data, 1 ); |
| 177 | +} |
| 178 | + |
| 179 | +// Set communication timeout |
| 180 | +void ser_set_timeout_ms( ser_handler id, u32 timeout ) |
| 181 | +{ |
| 182 | + ser_timeout = timeout; |
| 183 | +} |
| 184 | + |
0 commit comments