Home | History | Annotate | Line # | Download | only in libntp
icom.c revision 1.1.1.7
      1 /*
      2  * Program to control ICOM radios
      3  *
      4  * This is a ripoff of the utility routines in the ICOM software
      5  * distribution. The only function provided is to load the radio
      6  * frequency. All other parameters must be manually set before use.
      7  */
      8 #include <config.h>
      9 #include <ntp_stdlib.h>
     10 #include <ntp_tty.h>
     11 #include <l_stdlib.h>
     12 #include <icom.h>
     13 
     14 #include <unistd.h>
     15 #include <stdio.h>
     16 #include <fcntl.h>
     17 #include <errno.h>
     18 
     19 
     20 #ifdef SYS_WINNT
     21 #undef write	/* ports/winnt/include/config.h: #define write _write */
     22 extern int async_write(int, const void *, unsigned int);
     23 #define write(fd, data, octets)	async_write(fd, data, octets)
     24 #endif
     25 
     26 /*
     27  * Packet routines
     28  *
     29  * These routines send a packet and receive the response. If an error
     30  * (collision) occurs on transmit, the packet is resent. If an error
     31  * occurs on receive (timeout), all input to the terminating FI is
     32  * discarded and the packet is resent. If the maximum number of retries
     33  * is not exceeded, the program returns the number of octets in the user
     34  * buffer; otherwise, it returns zero.
     35  *
     36  * ICOM frame format
     37  *
     38  * Frames begin with a two-octet preamble PR-PR followyd by the
     39  * transceiver address RE, controller address TX, control code CN, zero
     40  * or more data octets DA (depending on command), and terminator FI.
     41  * Since the bus is bidirectional, every octet output is echoed on
     42  * input. Every valid frame sent is answered with a frame in the same
     43  * format, but with the RE and TX fields interchanged. The CN field is
     44  * set to NAK if an error has occurred. Otherwise, the data are returned
     45  * in this and following DA octets. If no data are returned, the CN
     46  * octet is set to ACK.
     47  *
     48  *	+------+------+------+------+------+--//--+------+
     49  *	|  PR  |  PR  |  RE  |  TX  |  CN  |  DA  |  FI  |
     50  *	+------+------+------+------+------+--//--+------+
     51  */
     52 /*
     53  * Scraps
     54  */
     55 #define DICOM /dev/icom/	/* ICOM port link */
     56 
     57 /*
     58  * Local function prototypes
     59  */
     60 static void doublefreq		(double, u_char *, int);
     61 
     62 
     63 /*
     64  * icom_freq(fd, ident, freq) - load radio frequency
     65  *
     66  * returns:
     67  *  0 (ok)
     68  * -1 (error)
     69  *  1 (short write to device)
     70  */
     71 int
     72 icom_freq(
     73 	int fd,			/* file descriptor */
     74 	int ident,		/* ICOM radio identifier */
     75 	double freq		/* frequency (MHz) */
     76 	)
     77 {
     78 	u_char cmd[] = {PAD, PR, PR, 0, TX, V_SFREQ, 0, 0, 0, 0, FI,
     79 	    FI};
     80 	int temp;
     81 	int rc;
     82 
     83 	cmd[3] = (char)ident;
     84 	if (ident == IC735)
     85 		temp = 4;
     86 	else
     87 		temp = 5;
     88 	doublefreq(freq * 1e6, &cmd[6], temp);
     89 	rc = write(fd, cmd, temp + 7);
     90 	if (rc == -1) {
     91 		msyslog(LOG_ERR, "icom_freq: write() failed: %m");
     92 		return -1;
     93 	} else if (rc != temp + 7) {
     94 		msyslog(LOG_ERR, "icom_freq: only wrote %d of %d bytes.",
     95 			rc, temp+7);
     96 		return 1;
     97 	}
     98 
     99 	return 0;
    100 }
    101 
    102 
    103 /*
    104  * doublefreq(freq, y, len) - double to ICOM frequency with padding
    105  */
    106 static void
    107 doublefreq(			/* returns void */
    108 	double freq,		/* frequency */
    109 	u_char *x,		/* radio frequency */
    110 	int len			/* length (octets) */
    111 	)
    112 {
    113 	int i;
    114 	char s1[16];
    115 	char *y;
    116 
    117 	snprintf(s1, sizeof(s1), " %10.0f", freq);
    118 	y = s1 + 10;
    119 	i = 0;
    120 	while (*y != ' ') {
    121 		x[i] = *y-- & 0x0f;
    122 		x[i] = x[i] | ((*y-- & 0x0f) << 4);
    123 		i++;
    124 	}
    125 	for ( ; i < len; i++)
    126 		x[i] = 0;
    127 	x[i] = FI;
    128 }
    129 
    130 /*
    131  * icom_init() - open and initialize serial interface
    132  *
    133  * This routine opens the serial interface for raw transmission; that
    134  * is, character-at-a-time, no stripping, checking or monkeying with the
    135  * bits. For Unix, an input operation ends either with the receipt of a
    136  * character or a 0.5-s timeout.
    137  */
    138 int
    139 icom_init(
    140 	const char *device,	/* device name/link */
    141 	int speed,		/* line speed */
    142 	int trace		/* trace flags */	)
    143 {
    144 	TTY ttyb;
    145 	int fd;
    146 	int rc;
    147 	int saved_errno;
    148 
    149 	fd = tty_open(device, O_RDWR, 0777);
    150 	if (fd < 0)
    151 		return -1;
    152 
    153 	rc = tcgetattr(fd, &ttyb);
    154 	if (rc < 0) {
    155 		saved_errno = errno;
    156 		close(fd);
    157 		errno = saved_errno;
    158 		return -1;
    159 	}
    160 	ttyb.c_iflag = 0;	/* input modes */
    161 	ttyb.c_oflag = 0;	/* output modes */
    162 	ttyb.c_cflag = IBAUD|CS8|CLOCAL; /* control modes  (no read) */
    163 	ttyb.c_lflag = 0;	/* local modes */
    164 	ttyb.c_cc[VMIN] = 0;	/* min chars */
    165 	ttyb.c_cc[VTIME] = 5;	/* receive timeout */
    166 	cfsetispeed(&ttyb, (u_int)speed);
    167 	cfsetospeed(&ttyb, (u_int)speed);
    168 	rc = tcsetattr(fd, TCSANOW, &ttyb);
    169 	if (rc < 0) {
    170 		saved_errno = errno;
    171 		close(fd);
    172 		errno = saved_errno;
    173 		return -1;
    174 	}
    175 	return (fd);
    176 }
    177 
    178 /* end program */
    179