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