Home | History | Annotate | Line # | Download | only in libntp
icom.c revision 1.10
      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