156746Sroberto/* 256746Sroberto * Program to control ICOM radios 356746Sroberto * 456746Sroberto * This is a ripoff of the utility routines in the ICOM software 556746Sroberto * distribution. The only function provided is to load the radio 656746Sroberto * frequency. All other parameters must be manually set before use. 756746Sroberto */ 8285612Sdelphij#include <config.h> 9289997Sglebius#include <ntp_stdlib.h> 10289997Sglebius#include <ntp_tty.h> 11289997Sglebius#include <l_stdlib.h> 12289997Sglebius#include <icom.h> 13289997Sglebius 1456746Sroberto#include <unistd.h> 1556746Sroberto#include <stdio.h> 1656746Sroberto#include <fcntl.h> 1756746Sroberto#include <errno.h> 1856746Sroberto 1982498Sroberto 20285612Sdelphij#ifdef SYS_WINNT 21285612Sdelphij#undef write /* ports/winnt/include/config.h: #define write _write */ 22285612Sdelphijextern int async_write(int, const void *, unsigned int); 23285612Sdelphij#define write(fd, data, octets) async_write(fd, data, octets) 24285612Sdelphij#endif 25285612Sdelphij 2656746Sroberto/* 27285612Sdelphij * Packet routines 28285612Sdelphij * 29285612Sdelphij * These routines send a packet and receive the response. If an error 30285612Sdelphij * (collision) occurs on transmit, the packet is resent. If an error 31285612Sdelphij * occurs on receive (timeout), all input to the terminating FI is 32285612Sdelphij * discarded and the packet is resent. If the maximum number of retries 33285612Sdelphij * is not exceeded, the program returns the number of octets in the user 34285612Sdelphij * buffer; otherwise, it returns zero. 35285612Sdelphij * 36285612Sdelphij * ICOM frame format 37285612Sdelphij * 38285612Sdelphij * Frames begin with a two-octet preamble PR-PR followyd by the 39285612Sdelphij * transceiver address RE, controller address TX, control code CN, zero 40285612Sdelphij * or more data octets DA (depending on command), and terminator FI. 41285612Sdelphij * Since the bus is bidirectional, every octet output is echoed on 42285612Sdelphij * input. Every valid frame sent is answered with a frame in the same 43285612Sdelphij * format, but with the RE and TX fields interchanged. The CN field is 44285612Sdelphij * set to NAK if an error has occurred. Otherwise, the data are returned 45285612Sdelphij * in this and following DA octets. If no data are returned, the CN 46285612Sdelphij * octet is set to ACK. 47285612Sdelphij * 48285612Sdelphij * +------+------+------+------+------+--//--+------+ 49285612Sdelphij * | PR | PR | RE | TX | CN | DA | FI | 50285612Sdelphij * +------+------+------+------+------+--//--+------+ 51285612Sdelphij */ 52285612Sdelphij/* 5356746Sroberto * Scraps 5456746Sroberto */ 5556746Sroberto#define DICOM /dev/icom/ /* ICOM port link */ 5656746Sroberto 5756746Sroberto/* 5856746Sroberto * Local function prototypes 5956746Sroberto */ 60285612Sdelphijstatic void doublefreq (double, u_char *, int); 6156746Sroberto 6256746Sroberto 6356746Sroberto/* 6456746Sroberto * icom_freq(fd, ident, freq) - load radio frequency 65289997Sglebius * 66289997Sglebius * returns: 67289997Sglebius * 0 (ok) 68289997Sglebius * -1 (error) 69289997Sglebius * 1 (short write to device) 7056746Sroberto */ 7156746Srobertoint 72289997Sglebiusicom_freq( 7356746Sroberto int fd, /* file descriptor */ 7456746Sroberto int ident, /* ICOM radio identifier */ 7556746Sroberto double freq /* frequency (MHz) */ 7656746Sroberto ) 7756746Sroberto{ 78285612Sdelphij u_char cmd[] = {PAD, PR, PR, 0, TX, V_SFREQ, 0, 0, 0, 0, FI, 79285612Sdelphij FI}; 8056746Sroberto int temp; 81289997Sglebius int rc; 82285612Sdelphij 83285612Sdelphij cmd[3] = (char)ident; 8456746Sroberto if (ident == IC735) 8556746Sroberto temp = 4; 8656746Sroberto else 8756746Sroberto temp = 5; 88285612Sdelphij doublefreq(freq * 1e6, &cmd[6], temp); 89289997Sglebius rc = write(fd, cmd, temp + 7); 90289997Sglebius if (rc == -1) { 91289997Sglebius msyslog(LOG_ERR, "icom_freq: write() failed: %m"); 92289997Sglebius return -1; 93289997Sglebius } else if (rc != temp + 7) { 94289997Sglebius msyslog(LOG_ERR, "icom_freq: only wrote %d of %d bytes.", 95289997Sglebius rc, temp+7); 96289997Sglebius return 1; 97289997Sglebius } 98285612Sdelphij 99289997Sglebius return 0; 10056746Sroberto} 10156746Sroberto 10256746Sroberto 10356746Sroberto/* 10456746Sroberto * doublefreq(freq, y, len) - double to ICOM frequency with padding 10556746Sroberto */ 10656746Srobertostatic void 10756746Srobertodoublefreq( /* returns void */ 10856746Sroberto double freq, /* frequency */ 10956746Sroberto u_char *x, /* radio frequency */ 11056746Sroberto int len /* length (octets) */ 11156746Sroberto ) 11256746Sroberto{ 11356746Sroberto int i; 114285612Sdelphij char s1[16]; 11556746Sroberto char *y; 11656746Sroberto 117285612Sdelphij snprintf(s1, sizeof(s1), " %10.0f", freq); 11856746Sroberto y = s1 + 10; 11956746Sroberto i = 0; 12056746Sroberto while (*y != ' ') { 12156746Sroberto x[i] = *y-- & 0x0f; 12256746Sroberto x[i] = x[i] | ((*y-- & 0x0f) << 4); 12356746Sroberto i++; 12456746Sroberto } 125285612Sdelphij for ( ; i < len; i++) 12656746Sroberto x[i] = 0; 12756746Sroberto x[i] = FI; 12856746Sroberto} 12956746Sroberto 13056746Sroberto/* 131285612Sdelphij * icom_init() - open and initialize serial interface 13256746Sroberto * 13356746Sroberto * This routine opens the serial interface for raw transmission; that 13456746Sroberto * is, character-at-a-time, no stripping, checking or monkeying with the 13556746Sroberto * bits. For Unix, an input operation ends either with the receipt of a 13656746Sroberto * character or a 0.5-s timeout. 13756746Sroberto */ 13856746Srobertoint 13956746Srobertoicom_init( 140285612Sdelphij const char *device, /* device name/link */ 14156746Sroberto int speed, /* line speed */ 14256746Sroberto int trace /* trace flags */ ) 14356746Sroberto{ 14482498Sroberto TTY ttyb; 14556746Sroberto int fd; 146285612Sdelphij int rc; 147285612Sdelphij int saved_errno; 14856746Sroberto 149285612Sdelphij fd = tty_open(device, O_RDWR, 0777); 15056746Sroberto if (fd < 0) 151285612Sdelphij return -1; 152182007Sroberto 153285612Sdelphij rc = tcgetattr(fd, &ttyb); 154285612Sdelphij if (rc < 0) { 155285612Sdelphij saved_errno = errno; 156285612Sdelphij close(fd); 157285612Sdelphij errno = saved_errno; 158285612Sdelphij return -1; 159285612Sdelphij } 16056746Sroberto ttyb.c_iflag = 0; /* input modes */ 16156746Sroberto ttyb.c_oflag = 0; /* output modes */ 162285612Sdelphij ttyb.c_cflag = IBAUD|CS8|CLOCAL; /* control modes (no read) */ 16356746Sroberto ttyb.c_lflag = 0; /* local modes */ 16456746Sroberto ttyb.c_cc[VMIN] = 0; /* min chars */ 16556746Sroberto ttyb.c_cc[VTIME] = 5; /* receive timeout */ 16656746Sroberto cfsetispeed(&ttyb, (u_int)speed); 16756746Sroberto cfsetospeed(&ttyb, (u_int)speed); 168285612Sdelphij rc = tcsetattr(fd, TCSANOW, &ttyb); 169285612Sdelphij if (rc < 0) { 170285612Sdelphij saved_errno = errno; 171285612Sdelphij close(fd); 172285612Sdelphij errno = saved_errno; 173285612Sdelphij return -1; 174285612Sdelphij } 17556746Sroberto return (fd); 17656746Sroberto} 17756746Sroberto 17856746Sroberto/* end program */ 179