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