xref: /netbsd-src/external/bsd/ntp/dist/libntp/icom.c (revision b757af438b42b93f8c6571f026d8b8ef3eaf5fc9)
1 /*	$NetBSD: icom.c,v 1.3 2012/02/01 07:46:22 kardel 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 "icom.h"
12 #include <unistd.h>
13 #include <stdio.h>
14 #include <fcntl.h>
15 #include <errno.h>
16 
17 #include "ntp_tty.h"
18 #include "l_stdlib.h"
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 int
67 icom_freq(			/* returns 0 (ok), EIO (error) */
68 	int fd,			/* file descriptor */
69 	int ident,		/* ICOM radio identifier */
70 	double freq		/* frequency (MHz) */
71 	)
72 {
73 	u_char cmd[] = {PAD, PR, PR, 0, TX, V_SFREQ, 0, 0, 0, 0, FI,
74 	    FI};
75 	int temp;
76 
77 	cmd[3] = (char)ident;
78 	if (ident == IC735)
79 		temp = 4;
80 	else
81 		temp = 5;
82 	doublefreq(freq * 1e6, &cmd[6], temp);
83 	temp = write(fd, cmd, temp + 7);
84 
85 	return (0);
86 }
87 
88 
89 /*
90  * doublefreq(freq, y, len) - double to ICOM frequency with padding
91  */
92 static void
93 doublefreq(			/* returns void */
94 	double freq,		/* frequency */
95 	u_char *x,		/* radio frequency */
96 	int len			/* length (octets) */
97 	)
98 {
99 	int i;
100 	char s1[16];
101 	char *y;
102 
103 	snprintf(s1, sizeof(s1), " %10.0f", freq);
104 	y = s1 + 10;
105 	i = 0;
106 	while (*y != ' ') {
107 		x[i] = *y-- & 0x0f;
108 		x[i] = x[i] | ((*y-- & 0x0f) << 4);
109 		i++;
110 	}
111 	for ( ; i < len; i++)
112 		x[i] = 0;
113 	x[i] = FI;
114 }
115 
116 /*
117  * icom_init() - open and initialize serial interface
118  *
119  * This routine opens the serial interface for raw transmission; that
120  * is, character-at-a-time, no stripping, checking or monkeying with the
121  * bits. For Unix, an input operation ends either with the receipt of a
122  * character or a 0.5-s timeout.
123  */
124 int
125 icom_init(
126 	const char *device,	/* device name/link */
127 	int speed,		/* line speed */
128 	int trace		/* trace flags */	)
129 {
130 	TTY ttyb;
131 	int fd;
132 	int flags;
133 	int rc;
134 	int saved_errno;
135 
136 	flags = trace;
137 	fd = tty_open(device, O_RDWR, 0777);
138 	if (fd < 0)
139 		return -1;
140 
141 	rc = tcgetattr(fd, &ttyb);
142 	if (rc < 0) {
143 		saved_errno = errno;
144 		close(fd);
145 		errno = saved_errno;
146 		return -1;
147 	}
148 	ttyb.c_iflag = 0;	/* input modes */
149 	ttyb.c_oflag = 0;	/* output modes */
150 	ttyb.c_cflag = IBAUD|CS8|CLOCAL; /* control modes  (no read) */
151 	ttyb.c_lflag = 0;	/* local modes */
152 	ttyb.c_cc[VMIN] = 0;	/* min chars */
153 	ttyb.c_cc[VTIME] = 5;	/* receive timeout */
154 	cfsetispeed(&ttyb, (u_int)speed);
155 	cfsetospeed(&ttyb, (u_int)speed);
156 	rc = tcsetattr(fd, TCSANOW, &ttyb);
157 	if (rc < 0) {
158 		saved_errno = errno;
159 		close(fd);
160 		errno = saved_errno;
161 		return -1;
162 	}
163 	return (fd);
164 }
165 
166 /* end program */
167