xref: /freebsd/contrib/ntp/libntp/icom.c (revision 61e21613)
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