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