xref: /netbsd-src/external/bsd/ntp/dist/libntp/icom.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /*	$NetBSD: icom.c,v 1.4 2013/10/20 02:47:38 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 "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 rc;
133 	int saved_errno;
134 
135 	fd = tty_open(device, O_RDWR, 0777);
136 	if (fd < 0)
137 		return -1;
138 
139 	rc = tcgetattr(fd, &ttyb);
140 	if (rc < 0) {
141 		saved_errno = errno;
142 		close(fd);
143 		errno = saved_errno;
144 		return -1;
145 	}
146 	ttyb.c_iflag = 0;	/* input modes */
147 	ttyb.c_oflag = 0;	/* output modes */
148 	ttyb.c_cflag = IBAUD|CS8|CLOCAL; /* control modes  (no read) */
149 	ttyb.c_lflag = 0;	/* local modes */
150 	ttyb.c_cc[VMIN] = 0;	/* min chars */
151 	ttyb.c_cc[VTIME] = 5;	/* receive timeout */
152 	cfsetispeed(&ttyb, (u_int)speed);
153 	cfsetospeed(&ttyb, (u_int)speed);
154 	rc = tcsetattr(fd, TCSANOW, &ttyb);
155 	if (rc < 0) {
156 		saved_errno = errno;
157 		close(fd);
158 		errno = saved_errno;
159 		return -1;
160 	}
161 	return (fd);
162 }
163 
164 /* end program */
165