From a1cc888e507e2adffdc56381c6f2b20dcd3201f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Fillod=2C=20F8CFE?= Date: Sun, 1 Oct 2000 14:24:47 +0000 Subject: [PATCH] Moved from ../common git-svn-id: https://hamlib.svn.sourceforge.net/svnroot/hamlib/trunk@175 7ae35d74-ebe9-4afe-98af-79ac388436b8 --- src/serial.c | 407 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/serial.h | 41 ++++++ 2 files changed, 448 insertions(+) create mode 100644 src/serial.c create mode 100644 src/serial.h diff --git a/src/serial.c b/src/serial.c new file mode 100644 index 000000000..a27c72fe6 --- /dev/null +++ b/src/serial.c @@ -0,0 +1,407 @@ +/* + * hamlib - (C) Frank Singleton 2000 (vk3fcs@ix.netcom.com) + * + * serial.c - (C) Frank Singleton 2000 (vk3fcs@ix.netcom.com), + * Stephane Fillod 2000 + * Provides useful routines for read/write serial data for communicating + * via serial interface. + * + * $Id: serial.c,v 1.1 2000-10-01 14:24:47 f4cfe Exp $ + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include +#include /* Standard input/output definitions */ +#include /* String function definitions */ +#include /* UNIX standard function definitions */ +#include /* File control definitions */ +#include /* Error number definitions */ +#include /* POSIX terminal control definitions */ +#include +#include +#include +#include + +#include +#include "serial.h" +#include "misc.h" + + +/* + * Open serial port using rig.state data + * + * + * input: ptr to rig.state structure, with serial port + * populated. (eg: "/dev/ttyS1"). + * + * returns: + * + * 0 if OK or negative value on error. + * + */ + +int serial_open(struct rig_state *rs) { + + int fd; /* File descriptor for the port */ + struct termios options; + speed_t speed; /* serial comm speed */ + + if (!rs) + return -RIG_EINVAL; + + /* + * Open in Non-blocking mode. Watch for EAGAIN errors! + */ + fd = open(rs->rig_path, O_RDWR | O_NOCTTY | O_NDELAY); + + if (fd == -1) { + + /* Could not open the port. */ + + rig_debug(RIG_DEBUG_ERR, "serial_open: Unable to open %s - %s\n", + rs->rig_path, strerror(errno)); + return -RIG_EIO; + } + + /* + * Get the current options for the port... + */ + + tcgetattr(fd, &options); + + /* + * Set the baud rates to requested values + */ + + switch(rs->serial_rate) { + case 300: + speed = B300; /* yikes... */ + break; + case 1200: + speed = B1200; + break; + case 2400: + speed = B2400; + break; + case 4800: + speed = B4800; + break; + case 9600: + speed = B9600; + break; + case 19200: + speed = B19200; + break; + case 38400: + speed = B38400; + break; + case 57600: + speed = B57600; /* cool.. */ + break; + default: + rig_debug(RIG_DEBUG_ERR, "open_serial: unsupported rate specified: %d\n", + rs->serial_rate); + close(fd); + return -RIG_ECONF; + } + cfsetispeed(&options, speed); + cfsetospeed(&options, speed); + + /* + * Enable the receiver and set local mode... + */ + + options.c_cflag |= (CLOCAL | CREAD); + +/* + * Set data to requested values. + * + */ + + switch(rs->serial_data_bits) { + case 7: + options.c_cflag &= ~CSIZE; + options.c_cflag |= CS7; + break; + case 8: + options.c_cflag &= ~CSIZE; + options.c_cflag |= CS8; + break; + default: + rig_debug(RIG_DEBUG_ERR,"open_serial: unsupported serial_data_bits specified: %d\n", + rs->serial_data_bits); + close(fd); + return -RIG_ECONF; + break; + } + +/* + * Set stop bits to requested values. + * + */ + + switch(rs->serial_stop_bits) { + case 1: + options.c_cflag &= ~CSTOPB; + break; + case 2: + options.c_cflag |= CSTOPB; + break; + + default: + rig_debug(RIG_DEBUG_ERR, "open_serial: unsupported serial_stop_bits specified: %d\n", + rs->serial_stop_bits); + close(fd); + return -RIG_ECONF; + break; + } + +/* + * Set parity to requested values. + * + */ + + switch(rs->serial_parity) { + case RIG_PARITY_NONE: + options.c_cflag &= ~PARENB; + break; + case RIG_PARITY_EVEN: + options.c_cflag |= PARENB; + options.c_cflag &= ~PARODD; + break; + case RIG_PARITY_ODD: + options.c_cflag |= PARENB; + options.c_cflag |= PARODD; + break; + default: + rig_debug(RIG_DEBUG_ERR, "open_serial: unsupported serial_parity specified: %d\n", + rs->serial_parity); + close(fd); + return -RIG_ECONF; + break; + } + + +/* + * Set flow control to requested mode + * + */ + + switch(rs->serial_handshake) { + case RIG_HANDSHAKE_NONE: + options.c_cflag &= ~CRTSCTS; + options.c_iflag &= ~IXON; + break; + case RIG_HANDSHAKE_XONXOFF: + options.c_cflag &= ~CRTSCTS; + options.c_iflag |= IXON; /* Enable Xon/Xoff software handshaking */ + break; + case RIG_HANDSHAKE_HARDWARE: + options.c_cflag |= CRTSCTS; /* Enable Hardware handshaking */ + options.c_iflag &= ~IXON; + break; + default: + rig_debug(RIG_DEBUG_ERR, "open_serial: unsupported flow_control specified: %d\n", + rs->serial_handshake); + close(fd); + return -RIG_ECONF; + break; + } + + /* + * Choose raw input, no preprocessing please .. + */ + + options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); + + /* + * Choose raw output, no preprocessing please .. + */ + + options.c_oflag &= ~OPOST; + + /* + * Flush serial port + */ + + tcflush(fd, TCIFLUSH); + + /* + * Finally, set the new options for the port... + */ + + if (tcsetattr(fd, TCSANOW, &options) == -1) { + rig_debug(RIG_DEBUG_ERR, "open_serial: tcsetattr failed: %s\n", + strerror(errno)); + close(fd); + return -RIG_ECONF; /* arg, so close! */ + } + + rs->fd = fd; + + return RIG_OK; +} + + + + +/* + * Read "num" bytes from "fd" and put results into + * an array of unsigned char pointed to by "rxbuffer" + * + * Sleeps read_delay milliseconds until number of bytes to read + * is the amount requested. + * + * It then reads "num" bytes into rxbuffer. + * + * input: + * fd - file descriptor + * rxbuffer - ptr to rx buffer + * num - number of bytes to read + * read_delay - number of msec between read attempts + * + * returns: + * + * n - numbers of bytes read + * + */ + + +int read_sleep(int fd, unsigned char *rxbuffer, int num , int read_delay) { + int bytes = 0; + int n = 0; + + rig_debug(RIG_DEBUG_ERR,"serial:read_sleep called with num = %i \n",num); + + while(1) { + ioctl(fd, FIONREAD, &bytes); /* get bytes in buffer */ + rig_debug(RIG_DEBUG_TRACE,"bytes = %i\n", bytes); + if (bytes == num) + break; + usleep(read_delay*1000); /* sleep read_delay msecs */ + } + + /* this should not block now */ + + n = read(fd,rxbuffer,num); /* grab num bytes from rig */ + + dump_hex(rxbuffer,num); + return n; /* return bytes read */ +} + +/* + * Write a block of count characters to file descriptor, + * with a pause between each character if write_delay is > 0 + * + * The delay is for Yaesu type rigs..require 5 character + * sequence to be sent with 50-200msec between each char. + * + * input: + * + * fd - file descriptor to write to + * txbuffer - pointer to a command sequence array + * count - count of byte to send from the txbuffer + * write_delay - write delay in ms between 2 chars + * + * returns: + * + * 0 = OK + * <0 = NOT OK + * + * Actually, this function has nothing specific to serial comm, + * it could work very well also with any file handle, like a socket. + */ + +int write_block(int fd, const unsigned char *txbuffer, size_t count, int write_delay) +{ + int i; + + if (write_delay > 0) { + for (i=0; i < count; i++) { + if (write(fd, txbuffer+i, 1) < 0) { + rig_debug(RIG_DEBUG_ERR,"write_block() failed - %s\n", strerror(errno)); + return -RIG_EIO; + } + usleep(write_delay*1000); + } + } else { + write(fd, txbuffer, count); + } + rig_debug(RIG_DEBUG_TRACE,"TX %d bytes\n",count); + dump_hex(txbuffer,count); + + return RIG_OK; +} + +/* + * Read "num" bytes from "fd" and put results into + * an array of unsigned char pointed to by "rxbuffer" + * + * Blocks on read until timeout hits. + * + * It then reads "num" bytes into rxbuffer. + * + * Actually, this function has nothing specific to serial comm, + * it could work very well also with any file handle, like a socket. + */ + +int read_block(int fd, unsigned char *rxbuffer, size_t count, int timeout ) +{ + fd_set rfds; + struct timeval tv, tv_timeout; + int rd_count, total_count = 0; + int retval; + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + + /* + * Wait up to timeout ms. + */ + tv_timeout.tv_sec = timeout/1000; + tv_timeout.tv_usec = (timeout%1000)*1000; + + while (count > 0) { + tv = tv_timeout; /* select may have updated it */ + + retval = select(fd+1, &rfds, NULL, NULL, &tv); + if (!retval) { + rig_debug(RIG_DEBUG_ERR,"rig timeout after %d chars or select error - %s!\n", + total_count, strerror(errno)); + return -RIG_ETIMEOUT; + } + + /* + * grab bytes from the rig + * The file descriptor must have been set up non blocking. + */ + rd_count = read(fd, rxbuffer+total_count, count); + if (rd_count < 0) { + rig_debug(RIG_DEBUG_ERR, "read_block: read failed - %s\n", + strerror(errno)); + return -RIG_EIO; + } + total_count += rd_count; + count -= rd_count; + } + + rig_debug(RIG_DEBUG_TRACE,"RX %d bytes\n",total_count); + dump_hex(rxbuffer, total_count); + return total_count; /* return bytes count read */ +} + diff --git a/src/serial.h b/src/serial.h new file mode 100644 index 000000000..af939cafc --- /dev/null +++ b/src/serial.h @@ -0,0 +1,41 @@ +/* + * hamlib - (C) Frank Singleton 2000 (vk3fcs@ix.netcom.com) + * + * serial.h - (C) Frank Singleton 2000 (vk3fcs@ix.netcom.com), + * Stephane Fillod 2000 + * Provides useful routines for read/write serial data for communicating + * via serial interface . + * + * $Id: serial.h,v 1.1 2000-10-01 14:24:47 f4cfe Exp $ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + + +#ifndef _SERIAL_H +#define _SERIAL_H 1 + +#include + + +int serial_open(struct rig_state *rs); + +int read_sleep(int fd, unsigned char *rxbuffer, int num , int read_delay); +int read_block(int fd, unsigned char *rxbuffer, size_t count, int timeout); +int write_block(int fd, const unsigned char *txbuffer, size_t count, int write_delay); + +#endif /* _SERIAL_H */ +