]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/ntp/libntp/icom.c
Upgrade NTP to 4.2.8p4.
[FreeBSD/releng/10.2.git] / contrib / ntp / libntp / icom.c
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 */