156746Sroberto/*
256746Sroberto * Program to control ICOM radios
356746Sroberto *
456746Sroberto * This is a ripoff of the utility routines in the ICOM software
556746Sroberto * distribution. The only function provided is to load the radio
656746Sroberto * frequency. All other parameters must be manually set before use.
756746Sroberto */
8285612Sdelphij#include <config.h>
9289997Sglebius#include <ntp_stdlib.h>
10289997Sglebius#include <ntp_tty.h>
11289997Sglebius#include <l_stdlib.h>
12289997Sglebius#include <icom.h>
13289997Sglebius
1456746Sroberto#include <unistd.h>
1556746Sroberto#include <stdio.h>
1656746Sroberto#include <fcntl.h>
1756746Sroberto#include <errno.h>
1856746Sroberto
1982498Sroberto
20285612Sdelphij#ifdef SYS_WINNT
21285612Sdelphij#undef write	/* ports/winnt/include/config.h: #define write _write */
22285612Sdelphijextern int async_write(int, const void *, unsigned int);
23285612Sdelphij#define write(fd, data, octets)	async_write(fd, data, octets)
24285612Sdelphij#endif
25285612Sdelphij
2656746Sroberto/*
27285612Sdelphij * Packet routines
28285612Sdelphij *
29285612Sdelphij * These routines send a packet and receive the response. If an error
30285612Sdelphij * (collision) occurs on transmit, the packet is resent. If an error
31285612Sdelphij * occurs on receive (timeout), all input to the terminating FI is
32285612Sdelphij * discarded and the packet is resent. If the maximum number of retries
33285612Sdelphij * is not exceeded, the program returns the number of octets in the user
34285612Sdelphij * buffer; otherwise, it returns zero.
35285612Sdelphij *
36285612Sdelphij * ICOM frame format
37285612Sdelphij *
38285612Sdelphij * Frames begin with a two-octet preamble PR-PR followyd by the
39285612Sdelphij * transceiver address RE, controller address TX, control code CN, zero
40285612Sdelphij * or more data octets DA (depending on command), and terminator FI.
41285612Sdelphij * Since the bus is bidirectional, every octet output is echoed on
42285612Sdelphij * input. Every valid frame sent is answered with a frame in the same
43285612Sdelphij * format, but with the RE and TX fields interchanged. The CN field is
44285612Sdelphij * set to NAK if an error has occurred. Otherwise, the data are returned
45285612Sdelphij * in this and following DA octets. If no data are returned, the CN
46285612Sdelphij * octet is set to ACK.
47285612Sdelphij *
48285612Sdelphij *	+------+------+------+------+------+--//--+------+
49285612Sdelphij *	|  PR  |  PR  |  RE  |  TX  |  CN  |  DA  |  FI  |
50285612Sdelphij *	+------+------+------+------+------+--//--+------+
51285612Sdelphij */
52285612Sdelphij/*
5356746Sroberto * Scraps
5456746Sroberto */
5556746Sroberto#define DICOM /dev/icom/	/* ICOM port link */
5656746Sroberto
5756746Sroberto/*
5856746Sroberto * Local function prototypes
5956746Sroberto */
60285612Sdelphijstatic void doublefreq		(double, u_char *, int);
6156746Sroberto
6256746Sroberto
6356746Sroberto/*
6456746Sroberto * icom_freq(fd, ident, freq) - load radio frequency
65289997Sglebius *
66289997Sglebius * returns:
67289997Sglebius *  0 (ok)
68289997Sglebius * -1 (error)
69289997Sglebius *  1 (short write to device)
7056746Sroberto */
7156746Srobertoint
72289997Sglebiusicom_freq(
7356746Sroberto	int fd,			/* file descriptor */
7456746Sroberto	int ident,		/* ICOM radio identifier */
7556746Sroberto	double freq		/* frequency (MHz) */
7656746Sroberto	)
7756746Sroberto{
78285612Sdelphij	u_char cmd[] = {PAD, PR, PR, 0, TX, V_SFREQ, 0, 0, 0, 0, FI,
79285612Sdelphij	    FI};
8056746Sroberto	int temp;
81289997Sglebius	int rc;
82285612Sdelphij
83285612Sdelphij	cmd[3] = (char)ident;
8456746Sroberto	if (ident == IC735)
8556746Sroberto		temp = 4;
8656746Sroberto	else
8756746Sroberto		temp = 5;
88285612Sdelphij	doublefreq(freq * 1e6, &cmd[6], temp);
89289997Sglebius	rc = write(fd, cmd, temp + 7);
90289997Sglebius	if (rc == -1) {
91289997Sglebius		msyslog(LOG_ERR, "icom_freq: write() failed: %m");
92289997Sglebius		return -1;
93289997Sglebius	} else if (rc != temp + 7) {
94289997Sglebius		msyslog(LOG_ERR, "icom_freq: only wrote %d of %d bytes.",
95289997Sglebius			rc, temp+7);
96289997Sglebius		return 1;
97289997Sglebius	}
98285612Sdelphij
99289997Sglebius	return 0;
10056746Sroberto}
10156746Sroberto
10256746Sroberto
10356746Sroberto/*
10456746Sroberto * doublefreq(freq, y, len) - double to ICOM frequency with padding
10556746Sroberto */
10656746Srobertostatic void
10756746Srobertodoublefreq(			/* returns void */
10856746Sroberto	double freq,		/* frequency */
10956746Sroberto	u_char *x,		/* radio frequency */
11056746Sroberto	int len			/* length (octets) */
11156746Sroberto	)
11256746Sroberto{
11356746Sroberto	int i;
114285612Sdelphij	char s1[16];
11556746Sroberto	char *y;
11656746Sroberto
117285612Sdelphij	snprintf(s1, sizeof(s1), " %10.0f", freq);
11856746Sroberto	y = s1 + 10;
11956746Sroberto	i = 0;
12056746Sroberto	while (*y != ' ') {
12156746Sroberto		x[i] = *y-- & 0x0f;
12256746Sroberto		x[i] = x[i] | ((*y-- & 0x0f) << 4);
12356746Sroberto		i++;
12456746Sroberto	}
125285612Sdelphij	for ( ; i < len; i++)
12656746Sroberto		x[i] = 0;
12756746Sroberto	x[i] = FI;
12856746Sroberto}
12956746Sroberto
13056746Sroberto/*
131285612Sdelphij * icom_init() - open and initialize serial interface
13256746Sroberto *
13356746Sroberto * This routine opens the serial interface for raw transmission; that
13456746Sroberto * is, character-at-a-time, no stripping, checking or monkeying with the
13556746Sroberto * bits. For Unix, an input operation ends either with the receipt of a
13656746Sroberto * character or a 0.5-s timeout.
13756746Sroberto */
13856746Srobertoint
13956746Srobertoicom_init(
140285612Sdelphij	const char *device,	/* device name/link */
14156746Sroberto	int speed,		/* line speed */
14256746Sroberto	int trace		/* trace flags */	)
14356746Sroberto{
14482498Sroberto	TTY ttyb;
14556746Sroberto	int fd;
146285612Sdelphij	int rc;
147285612Sdelphij	int saved_errno;
14856746Sroberto
149285612Sdelphij	fd = tty_open(device, O_RDWR, 0777);
15056746Sroberto	if (fd < 0)
151285612Sdelphij		return -1;
152182007Sroberto
153285612Sdelphij	rc = tcgetattr(fd, &ttyb);
154285612Sdelphij	if (rc < 0) {
155285612Sdelphij		saved_errno = errno;
156285612Sdelphij		close(fd);
157285612Sdelphij		errno = saved_errno;
158285612Sdelphij		return -1;
159285612Sdelphij	}
16056746Sroberto	ttyb.c_iflag = 0;	/* input modes */
16156746Sroberto	ttyb.c_oflag = 0;	/* output modes */
162285612Sdelphij	ttyb.c_cflag = IBAUD|CS8|CLOCAL; /* control modes  (no read) */
16356746Sroberto	ttyb.c_lflag = 0;	/* local modes */
16456746Sroberto	ttyb.c_cc[VMIN] = 0;	/* min chars */
16556746Sroberto	ttyb.c_cc[VTIME] = 5;	/* receive timeout */
16656746Sroberto	cfsetispeed(&ttyb, (u_int)speed);
16756746Sroberto	cfsetospeed(&ttyb, (u_int)speed);
168285612Sdelphij	rc = tcsetattr(fd, TCSANOW, &ttyb);
169285612Sdelphij	if (rc < 0) {
170285612Sdelphij		saved_errno = errno;
171285612Sdelphij		close(fd);
172285612Sdelphij		errno = saved_errno;
173285612Sdelphij		return -1;
174285612Sdelphij	}
17556746Sroberto	return (fd);
17656746Sroberto}
17756746Sroberto
17856746Sroberto/* end program */
179