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