kopia lustrzana https://github.com/Hamlib/Hamlib
Microham support. Use "uh-rig" for rig_pathname to talk to the
microHam device for CAT. If you want hardware PTT via the microham device, use DTR method and ptt_pathname "uh-ptt".pull/1/head
rodzic
3709fcb982
commit
d008ca6e5d
1
NEWS
1
NEWS
|
@ -12,6 +12,7 @@ Version 3.2
|
|||
* New model, FT-891. Mike, W9MDB
|
||||
* Build instructions and test script for Python3
|
||||
* Rename autogen.sh to bootsrap and don't call configure
|
||||
* micro-ham support. Christoph, DL1YCF
|
||||
|
||||
Version 3.1
|
||||
2016-12-31
|
||||
|
|
|
@ -249,7 +249,9 @@ model 2 for NET rigctl (@command{rigctld}).
|
|||
Use @var{device} as the file name of the port the radio is connected.
|
||||
Often a serial port, but could be a USB to serial adapter. Typically
|
||||
@file{/dev/ttyS0} , @file{/dev/ttyS1} , @file{/dev/ttyUSB0} , etc.@:
|
||||
on Linux or @file{COM1} , @file{COM2} , etc.@: on MS Windows.
|
||||
on Linux or @file{COM1} , @file{COM2} , etc.@: on MS Windows. The
|
||||
special string @kbd{uh-rig} may be given to enable micro-ham device
|
||||
support.
|
||||
@ifhtml
|
||||
@*
|
||||
@end ifhtml
|
||||
|
@ -1308,11 +1310,13 @@ Select rotator model number. See model list (use @kbd{rotctl -l}).
|
|||
rotor model 2 for NET rotctl (@command{rotctld}).
|
||||
|
||||
@item -r
|
||||
@itemx --rig-file=@var{device}
|
||||
@itemx --rot-file=@var{device}
|
||||
Use @var{device} as the file name of the port the rotor is connected.
|
||||
Often a serial port, but could be a USB to serial adapter. Typically
|
||||
@file{/dev/ttyS0} , @file{/dev/ttyS1} , @file{/dev/ttyUSB0} , etc.@:
|
||||
on Linux or @file{COM1} , @file{COM2} , etc.@: on MS Windows.
|
||||
on Linux or @file{COM1} , @file{COM2} , etc.@: on MS Windows. The
|
||||
special string @kbd{uh-rig} may be given to enable micro-ham device
|
||||
support.
|
||||
@ifhtml
|
||||
@*
|
||||
@end ifhtml
|
||||
|
@ -1776,7 +1780,9 @@ Select radio model number. See model list (use @kbd{rigctld -l}).
|
|||
Use @var{device} as the file name of the port the radio is connected.
|
||||
Often a serial port, but could be a USB to serial adapter. Typically
|
||||
@file{/dev/ttyS0} , @file{/dev/ttyS1} , @file{/dev/ttyUSB0} , etc.@:
|
||||
on Linux or @file{COM1} , @file{COM2} , etc.@: on MS Windows.
|
||||
on Linux or @file{COM1} , @file{COM2} , etc.@: on MS Windows. The
|
||||
special string @kbd{uh-rig} may be given to enable micro-ham device
|
||||
support.
|
||||
@ifhtml
|
||||
@*
|
||||
@end ifhtml
|
||||
|
@ -2861,11 +2867,13 @@ Select rotator model number. See model list (use @kbd{rotctl -l}).
|
|||
rotor model 2 for NET rotctl (@command{rotctld}).
|
||||
|
||||
@item -r
|
||||
@itemx --rig-file=@var{device}
|
||||
@itemx --rot-file=@var{device}
|
||||
Use @var{device} as the file name of the port the rotor is connected.
|
||||
Often a serial port, but could be a USB to serial adapter. Typically
|
||||
@file{/dev/ttyS0} , @file{/dev/ttyS1} , @file{/dev/ttyUSB0} , etc.@:
|
||||
on Linux or @file{COM1} , @file{COM2} , etc.@: on MS Windows.
|
||||
on Linux or @file{COM1} , @file{COM2} , etc.@: on MS Windows. The
|
||||
special string @kbd{uh-rig} may be given to enable micro-ham device
|
||||
support.
|
||||
@ifhtml
|
||||
@*
|
||||
@end ifhtml
|
||||
|
|
|
@ -4,7 +4,7 @@ RIGSRC = rig.c serial.c serial.h misc.c misc.h register.c register.h event.c \
|
|||
event.h cal.c cal.h conf.c tones.c tones.h rotator.c locator.c rot_reg.c \
|
||||
rot_conf.c rot_conf.h iofunc.c iofunc.h ext.c mem.c settings.c \
|
||||
parallel.c parallel.h usb_port.c usb_port.h debug.c network.c network.h \
|
||||
cm108.c cm108.h gpio.c gpio.h idx_builtin.h token.h par_nt.h
|
||||
cm108.c cm108.h gpio.c gpio.h idx_builtin.h token.h par_nt.h microham.c microham.h
|
||||
|
||||
lib_LTLIBRARIES = libhamlib.la
|
||||
libhamlib_la_SOURCES = $(RIGSRC)
|
||||
|
|
36
src/iofunc.c
36
src/iofunc.c
|
@ -223,6 +223,12 @@ int HAMLIB_API port_close(hamlib_port_t *p, rig_port_t port_type)
|
|||
#if defined(WIN32) && !defined(HAVE_TERMIOS_H)
|
||||
#include "win32termios.h"
|
||||
|
||||
/*
|
||||
* We need uh_radio_fd to determine wether to use win32_serial_read() etc.
|
||||
* or (simply) read().
|
||||
*/
|
||||
#include "microham.h"
|
||||
|
||||
|
||||
/* On MinGW32/MSVC/.. the appropriate accessor must be used
|
||||
* depending on the port type, sigh.
|
||||
|
@ -232,6 +238,16 @@ static ssize_t port_read(hamlib_port_t *p, void *buf, size_t count)
|
|||
int i;
|
||||
ssize_t ret;
|
||||
|
||||
/*
|
||||
* Since WIN32 does its special serial read, we have
|
||||
* to catch the microHam case to do just "read".
|
||||
* Note that we always have RIG_PORT_SERIAL in the
|
||||
* microHam case.
|
||||
*/
|
||||
if (p->fd == uh_radio_fd) {
|
||||
return read(p->fd, buf, count);
|
||||
}
|
||||
|
||||
if (p->type.rig == RIG_PORT_SERIAL) {
|
||||
ret = win32_serial_read(p->fd, buf, count);
|
||||
|
||||
|
@ -255,6 +271,16 @@ static ssize_t port_read(hamlib_port_t *p, void *buf, size_t count)
|
|||
|
||||
static ssize_t port_write(hamlib_port_t *p, const void *buf, size_t count)
|
||||
{
|
||||
/*
|
||||
* Since WIN32 does its special serial write, we have
|
||||
* to catch the microHam case to do just "write".
|
||||
* Note that we always have RIG_PORT_SERIAL in the
|
||||
* microHam case.
|
||||
*/
|
||||
if (p->fd == uh_radio_fd) {
|
||||
return write(p->fd, buf, count);
|
||||
}
|
||||
|
||||
if (p->type.rig == RIG_PORT_SERIAL) {
|
||||
return win32_serial_write(p->fd, buf, count);
|
||||
} else if (p->type.rig == RIG_PORT_NETWORK
|
||||
|
@ -287,6 +313,16 @@ static int port_select(hamlib_port_t *p, int n, fd_set *readfds,
|
|||
exceptfds = NULL;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Since WIN32 does its special serial select, we have
|
||||
* to catch the microHam case to do just "select".
|
||||
* Note that we always have RIG_PORT_SERIAL in the
|
||||
* microHam case.
|
||||
*/
|
||||
if (p->fd == uh_radio_fd) {
|
||||
return select(n, readfds, writefds, exceptfds, timeout);
|
||||
}
|
||||
|
||||
if (p->type.rig == RIG_PORT_SERIAL) {
|
||||
return win32_serial_select(n, readfds, writefds, exceptfds, timeout);
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,942 @@
|
|||
//
|
||||
// This file contains the support for microHam devices
|
||||
// if this system does not have pthreads, there is no microHam support, but it compiles
|
||||
// on WIN32, this file compiles but no microHam device will be found and openend
|
||||
//
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <glob.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/select.h>
|
||||
#include <time.h>
|
||||
#include <sys/errno.h>
|
||||
#include <limits.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
|
||||
//#define FRAME(s, ...) printf(s, ##__VA_ARGS__)
|
||||
//#define DEBUG(s, ...) printf(s, ##__VA_ARGS__)
|
||||
//#define TRACE(s, ...) printf(s, ##__VA_ARGS__)
|
||||
//#define ERROR(s, ...) printf(s, ##__VA_ARGS__)
|
||||
|
||||
#ifndef FRAME
|
||||
#define FRAME(s, ...)
|
||||
#endif
|
||||
#ifndef DEBUG
|
||||
#define DEBUG(s, ...)
|
||||
#endif
|
||||
#ifndef TRACE
|
||||
#define TRACE(s, ...)
|
||||
#endif
|
||||
#ifndef ERROR
|
||||
#define ERROR(s, ...)
|
||||
#endif
|
||||
|
||||
#ifndef PATH_MAX
|
||||
// should not happen, should be defined in limits.h
|
||||
// but better paranoia than a code that does not work
|
||||
#define PATH_MAX 256
|
||||
#endif
|
||||
|
||||
static char uh_device_path[PATH_MAX]; // use PATH_MAX since udev names can be VERY long!
|
||||
static int uh_device_fd=-1;
|
||||
static int uh_is_initialized=0;
|
||||
|
||||
static int uh_radio_pair[2] = {-1, -1};
|
||||
static int uh_ptt_pair[2] = {-1, -1};
|
||||
static int uh_wkey_pair[2] = {-1, -1};
|
||||
|
||||
static int uh_radio_in_use;
|
||||
static int uh_ptt_in_use;
|
||||
static int uh_wkey_in_use;
|
||||
|
||||
static int statusbyte=0;
|
||||
|
||||
#ifdef HAVE_PTHREAD
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
static pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_t readthread;
|
||||
#define getlock() if (pthread_mutex_lock(&mutex)) perror("GETLOCK:")
|
||||
#define freelock() if (pthread_mutex_unlock(&mutex)) perror("FREELOCK:")
|
||||
#else
|
||||
#define getlock()
|
||||
#define freelock()
|
||||
#endif
|
||||
|
||||
//
|
||||
// time of last heartbeat. Updated by heartbeat()
|
||||
//
|
||||
static time_t lastbeat=0;
|
||||
static time_t starttime;
|
||||
|
||||
#define TIME ((int) (time(NULL) - starttime))
|
||||
|
||||
//
|
||||
// close all sockets and mark them free
|
||||
//
|
||||
static void close_all_files()
|
||||
{
|
||||
if (uh_radio_pair[0] >= 0) {
|
||||
close(uh_radio_pair[0]);
|
||||
}
|
||||
if (uh_radio_pair[1] >= 0) {
|
||||
close(uh_radio_pair[1]);
|
||||
}
|
||||
if (uh_ptt_pair[0] >= 0) {
|
||||
close(uh_ptt_pair[0]);
|
||||
}
|
||||
if (uh_ptt_pair[1] >= 0) {
|
||||
close(uh_ptt_pair[1]);
|
||||
}
|
||||
if (uh_wkey_pair[0] >= 0) {
|
||||
close(uh_wkey_pair[0]);
|
||||
}
|
||||
if (uh_wkey_pair[1] >= 0) {
|
||||
close(uh_wkey_pair[1]);
|
||||
}
|
||||
uh_radio_pair[0]=-1;
|
||||
uh_radio_pair[1]=-1;
|
||||
uh_ptt_pair[0]=-1;
|
||||
uh_ptt_pair[1]=-1;
|
||||
uh_wkey_pair[0]=-1;
|
||||
uh_wkey_pair[1]=-1;
|
||||
uh_radio_in_use=0;
|
||||
uh_ptt_in_use=0;
|
||||
uh_wkey_in_use=0;
|
||||
// finally, close connection to microHam device
|
||||
if (uh_device_fd >= 0) {
|
||||
close(uh_device_fd);
|
||||
}
|
||||
}
|
||||
|
||||
static void close_microham()
|
||||
{
|
||||
if (!uh_is_initialized) {
|
||||
return;
|
||||
}
|
||||
TRACE("%10d:Closing MicroHam device\n",TIME);
|
||||
uh_is_initialized=0;
|
||||
#ifdef HAVE_PTHREAD
|
||||
// wait for read_device thread to finish
|
||||
pthread_join(readthread, NULL);
|
||||
#endif
|
||||
close_all_files();
|
||||
}
|
||||
|
||||
#if defined(WIN32)
|
||||
/*
|
||||
* On Windows, this is not really needed since we have uhrouter.exe
|
||||
* creating virtual COM ports
|
||||
*
|
||||
* I do now know how to "find" a microham device under Windows,
|
||||
* and serial I/O may also be Windows-specific.
|
||||
*
|
||||
* Therefore, a dummy version of finddevices() is included such that it compiles
|
||||
* well on WIN32. Since the dummy version does not find anything, no reading thread
|
||||
* and no sockets are created.
|
||||
*
|
||||
* What finddevices() must do:
|
||||
* Scan all USB-serial ports with an FTDI chip, and look
|
||||
* for its serial number, take the first port you can find where the serial
|
||||
* number begins with MK, M2, CK, DK, D2, 2R, 2P or UR. Then, open the serial
|
||||
* line and put a valid fd into uh_device_fd.
|
||||
*/
|
||||
static void finddevices()
|
||||
{
|
||||
}
|
||||
#else
|
||||
|
||||
/*
|
||||
* POSIX (including APPLE)
|
||||
*
|
||||
* Finding microHam devices can be a mess.
|
||||
* On Apple, the FTDI chips inside the microHam device show up as
|
||||
* /dev/tty.usbserial-<SERIAL> where <SERIAL> is the serial number
|
||||
* of the chip. So we can easily look for MK, MK-II, DK etc.
|
||||
* devices.
|
||||
*
|
||||
* On LINUX, these show up as /dev/ttyUSBx where x=0,1,2...
|
||||
* depending on when the device has been recognized. Fortunately
|
||||
* today all LINUX boxes have udev, and there is a symlink
|
||||
* in /dev/serial/by-id containing the serial number pointing
|
||||
* to the relevant special file in /dev.
|
||||
*
|
||||
* This technique is used such that we do not need to open
|
||||
* ALL serial ports in the system looking which one corresponds
|
||||
* to microHam. Note we could use libusb directly, but this
|
||||
* probably requires root privileges.
|
||||
*
|
||||
* Below is support for MacOS and LINUX, but I do not know
|
||||
* how to "find" a microHam device under Windows. Perhaps
|
||||
* someone knows, but for Windows there is uhrouter.exe that
|
||||
* creates virtual COM-ports such that microHam support is
|
||||
* not really needed.
|
||||
*
|
||||
* Note: StationMaster used a different protocol, and
|
||||
* the protocol of StationMaster DeLuxe is not
|
||||
* even disclosed.
|
||||
*/
|
||||
|
||||
#define NUMUHTYPES 8
|
||||
static struct uhtypes {
|
||||
const char *name;
|
||||
const char *device;
|
||||
} uhtypes[NUMUHTYPES] = {
|
||||
|
||||
#ifdef __APPLE__
|
||||
{ "microKeyer", "/dev/tty.usbserial-MK*"},
|
||||
{ "microKeyer-II", "/dev/tty.usbserial-M2*"},
|
||||
{ "CW Keyer", "/dev/tty.usbserial-CK*"},
|
||||
{ "digiKeyer", "/dev/tty.usbserial-DK*"},
|
||||
{ "digiKeyer-II", "/dev/tty.usbserial-D2*"},
|
||||
{ "micorKeyer-IIR", "/dev/tty.usbserial-2R*"},
|
||||
{ "microKeyer-IIR+", "/dev/tty.usbserial-2P*"},
|
||||
{ "microKeyer-U2R", "/dev/tty.usbserial-UR*"},
|
||||
#else
|
||||
{ "microKeyer", "/dev/serial/by-id/*microHAM*_MK*"},
|
||||
{ "microKeyer-II", "/dev/serial/by-id/*microHAM*_M2*"},
|
||||
{ "CW Keyer", "/dev/serial/by-id/*microHAM*_CK*"},
|
||||
{ "digiKeyer", "/dev/serial/by-id/*microHAM*_DK*"},
|
||||
{ "digiKeyer-II", "/dev/serial/by-id/*microHAM*_D2*"},
|
||||
{ "micorKeyer-IIR", "/dev/serial/by-id/*microHAM*_2R*"},
|
||||
{ "microKeyer-IIR+", "/dev/serial/by-id/*microHAM*_2P*"},
|
||||
{ "microKeyer-U2R", "/dev/serial/by-id/*microHAM*_UR*"},
|
||||
#endif
|
||||
};
|
||||
|
||||
//
|
||||
// Find a microHamDevice. Here we assume that the device special
|
||||
// file has a name from which we can tell this is a microHam device
|
||||
// This is the case for MacOS and LINUX (for LINUX: use udev)
|
||||
//
|
||||
#include <termios.h>
|
||||
static void finddevices()
|
||||
{
|
||||
struct stat st;
|
||||
glob_t gbuf;
|
||||
int i,j;
|
||||
struct termios TTY;
|
||||
int fd;
|
||||
|
||||
uh_device_fd= -1; // indicates "no device is found"
|
||||
|
||||
//
|
||||
// Check ALL device special files that might be relevant,
|
||||
//
|
||||
for (i=0; i<NUMUHTYPES; i++) {
|
||||
DEBUG("Checking for %s device\n", uhtypes[i].device);
|
||||
glob(uhtypes[i].device, 0, NULL, &gbuf);
|
||||
for (j=0; j < gbuf.gl_pathc; j++) {
|
||||
DEBUG("Found file: %s\n",gbuf.gl_pathv[j]);
|
||||
if (!stat(gbuf.gl_pathv[j], &st)) {
|
||||
if (S_ISCHR(st.st_mode)) {
|
||||
// found a character special device with correct name
|
||||
if (strlen(gbuf.gl_pathv[j]) >= PATH_MAX) {
|
||||
// I do not know if this can happen, but if it happens, we just skip the device.
|
||||
ERROR("Name too long: %s\n",gbuf.gl_pathv[j]);
|
||||
continue;
|
||||
}
|
||||
DEBUG("%s is a character special file\n", gbuf.gl_pathv[j]);
|
||||
strcpy(uh_device_path, gbuf.gl_pathv[j]);
|
||||
TRACE("Found a %s, Device=%s\n",uhtypes[i].name,uh_device_path);
|
||||
|
||||
fd = open(uh_device_path, O_RDWR | O_NONBLOCK | O_NOCTTY);
|
||||
if (fd < 0) {
|
||||
ERROR("Cannot open serial port %s\n",uh_device_path);
|
||||
perror("Open:");
|
||||
continue;
|
||||
}
|
||||
tcflush(fd, TCIFLUSH);
|
||||
if (tcgetattr( fd, &TTY)) {
|
||||
ERROR("Cannot get comm params\n");
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
// microHam devices always use 230400 baud, 8N1, only TxD/RxD is used (no h/w handshake)
|
||||
// 8 data bits
|
||||
TTY.c_cflag &= ~CSIZE;
|
||||
TTY.c_cflag |= CS8;
|
||||
// enable receiver, set local mode
|
||||
TTY.c_cflag |= (CLOCAL | CREAD);
|
||||
// no parity
|
||||
TTY.c_cflag &= ~PARENB;
|
||||
// 1 stop bit
|
||||
TTY.c_cflag &= ~CSTOPB;
|
||||
|
||||
cfsetispeed(&TTY, B230400);
|
||||
cfsetospeed(&TTY, B230400);
|
||||
|
||||
// NO h/w handshake
|
||||
// TTY.c_cflag &= ~CRTSCTS;
|
||||
// raw input
|
||||
TTY.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
|
||||
// raw output
|
||||
TTY.c_oflag &= ~OPOST;
|
||||
// software flow control disabled
|
||||
// TTY.c_iflag &= ~IXON;
|
||||
// do not translate CR to NL
|
||||
// TTY.c_iflag &= ~ICRNL;
|
||||
|
||||
// timeouts
|
||||
TTY.c_cc[VMIN]=0;
|
||||
TTY.c_cc[VTIME]=255;
|
||||
|
||||
if (tcsetattr(fd, TCSANOW, &TTY)) {
|
||||
ERROR("Can't set device communication parameters");
|
||||
close (fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
TRACE("SerialPort opened: %s fd=%d\n",uh_device_path,fd);
|
||||
uh_device_fd=fd;
|
||||
// The first time we were successfull, we skip all what might come
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// parse a frame received from the keyer
|
||||
// This is called from the "device reading" thread
|
||||
// once a complete frame has been received
|
||||
// Send Radio and Winkey bytes received to the client sockets.
|
||||
//
|
||||
static int frameseq=0;
|
||||
static int incontrol=0;
|
||||
static unsigned char controlstring[256];
|
||||
static int numcontrolbytes=0;
|
||||
|
||||
static void parseFrame(unsigned char *frame)
|
||||
{
|
||||
int i;
|
||||
unsigned char byte;
|
||||
FRAME("RCV frame %02x %02x %02x %02x\n",frame[0],frame[1],frame[2],frame[3]);
|
||||
|
||||
// frames come in sequences. The first frame of a sequence has bit6 cleared in the headerbyte.
|
||||
if ((frame[0] & 0x40) == 0) {
|
||||
frameseq=0;
|
||||
} else {
|
||||
frameseq++;
|
||||
}
|
||||
|
||||
// A frame is of the form header-byte1-byte2-byte3
|
||||
// byte 1 is always RADIO, byte 2 is always RADIO2/AUX (if validity bit set)
|
||||
// byte 3 has different meaning, depending on the sequence number of the frame:
|
||||
// seq=0 -> Flags
|
||||
// seq=1 -> control
|
||||
// seq=2 -> WinKey
|
||||
// seq=3 -> PS2
|
||||
|
||||
// if RADIO byte is valid, send it to client
|
||||
if ((frame[0] & 0x20) != 0) {
|
||||
byte=frame[1] & 0x7F;
|
||||
if ((frame[0] & 0x04) != 0) {
|
||||
byte |= 0x80;
|
||||
}
|
||||
DEBUG("%10d:FromRadio: %02x\n", TIME, byte);
|
||||
if (write(uh_radio_pair[0], &byte, 1) != 1) {
|
||||
ERROR("Write Radio Socket\n");
|
||||
}
|
||||
}
|
||||
|
||||
// ignore AUX/RADIO2 for the time being
|
||||
|
||||
// check the shared channel for validity, if it is the CONTROL channel it is always valid
|
||||
if ((frame[0] & 0x08) || (frameseq == 1)) {
|
||||
byte=frame[3] & 0x7F;
|
||||
if (frame[0] & 0x01) {
|
||||
byte |= 0x80;
|
||||
}
|
||||
|
||||
switch (frameseq) {
|
||||
case 0:
|
||||
DEBUG("%10d:RCV: Flags=%02x\n", TIME, byte);
|
||||
// No reason to pass the flags to clients
|
||||
break;
|
||||
case 1:
|
||||
if ((frame[0] & 0x08) == 0 && !incontrol) {
|
||||
// start or end of a control sequence
|
||||
numcontrolbytes=1;
|
||||
controlstring[0]=byte;
|
||||
incontrol=1;
|
||||
break;
|
||||
}
|
||||
if ((frame[0] & 0x08) == 0 && incontrol) {
|
||||
// end of a control sequence
|
||||
controlstring[numcontrolbytes++]=byte;
|
||||
DEBUG("%10d:FromControl:",TIME);
|
||||
for (i=0; i<numcontrolbytes; i++) DEBUG(" %02x",controlstring[i]);
|
||||
DEBUG(".\n");
|
||||
incontrol=0;
|
||||
// printing control messages is only used for debugging.
|
||||
break;
|
||||
}
|
||||
// in the middle of a control string
|
||||
controlstring[numcontrolbytes++]=byte;
|
||||
break;
|
||||
case 2:
|
||||
DEBUG("%10d:RCV: WinKey=%02x\n", TIME, byte);
|
||||
if (write(uh_wkey_pair[0], &byte, 1) != 1) {
|
||||
ERROR("Write Winkey socket\n");
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
DEBUG("%10d:RCV: PS2=%02x\n", TIME,byte);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Send radio bytes to keyer
|
||||
//
|
||||
static void writeRadio(unsigned char *bytes, int len)
|
||||
{
|
||||
unsigned char seq[4];
|
||||
int i,ret;
|
||||
|
||||
DEBUG("%10d:Send radio data: ",TIME);
|
||||
for (i=0; i<len; i++) DEBUG(" %02x",(int) bytes[i]);
|
||||
DEBUG(".\n");
|
||||
|
||||
getlock();
|
||||
for (i=0; i<len; i++) {
|
||||
seq[0]=0x28;
|
||||
seq[1]=0x80 | bytes[i];
|
||||
seq[2]=0x80;
|
||||
seq[3]=0X80 | statusbyte;
|
||||
if (statusbyte & 0x80) {
|
||||
seq[0] |= 0x01;
|
||||
}
|
||||
if (bytes[i] & 0x80) {
|
||||
seq[0] |= 0x04;
|
||||
}
|
||||
if ((ret=write(uh_device_fd, seq, 4)) < 4) {
|
||||
ERROR("WriteRadio failed with %d\n", ret);
|
||||
if (ret < 0) {
|
||||
perror("WriteRadioError:");
|
||||
}
|
||||
}
|
||||
}
|
||||
freelock();
|
||||
}
|
||||
|
||||
//
|
||||
// send statusbyte to keyer
|
||||
//
|
||||
static void writeFlags()
|
||||
{
|
||||
unsigned char seq[4];
|
||||
int ret;
|
||||
|
||||
DEBUG("%10d:Sending FlagByte: %02x\n", TIME, statusbyte);
|
||||
getlock();
|
||||
seq[0]=0x08;
|
||||
if (statusbyte & 0x80) {
|
||||
seq[0] = 0x09;
|
||||
}
|
||||
seq[1]=0x80;
|
||||
seq[2]=0x80;
|
||||
seq[3]=0x80 | statusbyte;
|
||||
if ((ret=write (uh_device_fd, seq, 4)) < 4) {
|
||||
ERROR("WriteFlags failed with %d\n", ret);
|
||||
if (ret < 0) {
|
||||
perror("WriteFlagsError:");
|
||||
}
|
||||
}
|
||||
freelock();
|
||||
}
|
||||
//
|
||||
// Send bytes to the WinKeyer
|
||||
//
|
||||
static void writeWkey(unsigned char *bytes, int len)
|
||||
{
|
||||
unsigned char seq[12];
|
||||
int i,ret;
|
||||
DEBUG("%10d:Send WinKey data: ",TIME);
|
||||
for (i=0; i<len; i++) DEBUG(" %02x",(int) bytes[i]);
|
||||
DEBUG(".\n");
|
||||
// Winkey data is in the third frame of a sequence,
|
||||
// So send two no-ops first. Include statusbyte in first frame
|
||||
getlock();
|
||||
for (i=0; i<len; i++) {
|
||||
seq[ 0]=0x08;
|
||||
seq[ 1]=0x80;
|
||||
seq[ 2]=0x80;
|
||||
seq[ 3]=0X80 | statusbyte;
|
||||
seq[ 4]=0x40;
|
||||
seq[ 5]=0x80;
|
||||
seq[ 6]=0x80;
|
||||
seq[ 7]=0x80;
|
||||
seq[ 8]=0x48;
|
||||
seq[ 9]=0x80;
|
||||
seq[10]=0x80;
|
||||
seq[11]=0x80 | bytes[i];
|
||||
if (statusbyte & 0x80) {
|
||||
seq[ 0] |= 0x01;
|
||||
}
|
||||
if (bytes[i] & 0x80) {
|
||||
seq[ 8] |= 0x01;
|
||||
}
|
||||
if ((ret=write(uh_device_fd, seq, 12)) < 12) {
|
||||
ERROR("WriteWINKEY failed with %d\n", ret);
|
||||
if (ret < 0) {
|
||||
perror("WriteWinkeyError:");
|
||||
}
|
||||
}
|
||||
}
|
||||
freelock();
|
||||
}
|
||||
//
|
||||
// Write a string to the control channel
|
||||
//
|
||||
static void writeControl(unsigned char *data, int len)
|
||||
{
|
||||
int i, ret;
|
||||
unsigned char seq[8];
|
||||
|
||||
DEBUG("%10d:WriteControl:",TIME);
|
||||
for (i=0; i<len; i++) DEBUG(" %02x", data[i]);
|
||||
DEBUG(".\n");
|
||||
// Control data is in the second frame of a sequence,
|
||||
// So send a no-op first. Include statusbyte in first frame.
|
||||
// First and last byte of the control message is NOT marked "valid"
|
||||
getlock();
|
||||
for (i=0; i<len; i++) {
|
||||
// encode statusbyte in first frame
|
||||
seq[0]=0x08;
|
||||
seq[1]=0x80;
|
||||
seq[2]=0x80;
|
||||
seq[3]=0x80 | statusbyte;
|
||||
seq[4]=0x48; // marked valid
|
||||
seq[5]=0x80;
|
||||
seq[6]=0x80;
|
||||
seq[7]=0x80 | data[i];
|
||||
if (statusbyte & 0x80) {
|
||||
seq[0] |= 1;
|
||||
}
|
||||
if (i==0 || i==len-1) {
|
||||
seq[4]=0x40; // un-mark valid
|
||||
}
|
||||
if (data[i] & 0x80) {
|
||||
seq[4] |= 0x01;
|
||||
}
|
||||
if ((ret=write (uh_device_fd, seq, 8)) < 8) {
|
||||
ERROR("WriteControl failed, ret=%d\n", ret);
|
||||
if (ret < 0) {
|
||||
perror("WriteControlError:");
|
||||
}
|
||||
}
|
||||
}
|
||||
freelock();
|
||||
}
|
||||
//
|
||||
// send a heartbeat and record time.
|
||||
//
|
||||
static void heartbeat()
|
||||
{
|
||||
unsigned char seq[2];
|
||||
|
||||
seq[0] = 0x7e;
|
||||
seq[1] = 0xfe;
|
||||
writeControl(seq, 2);
|
||||
lastbeat=time(NULL);
|
||||
}
|
||||
//
|
||||
// This thread reads from the microHam device and puts data on the sockets
|
||||
// it also issues periodic heartbeat messages
|
||||
// it also reads the sockets if data is available
|
||||
//
|
||||
static void* read_device(void *p)
|
||||
{
|
||||
unsigned char frame[4];
|
||||
int framepos=0;
|
||||
int ret;
|
||||
unsigned char buf[2];
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
int maxdev;
|
||||
|
||||
|
||||
// the bytes from the microHam decive come in "frames"
|
||||
// a frame is a four-byte sequence. The first byte has the MSB unset,
|
||||
// then come three bytes with the MSB set
|
||||
// What comes here is an "infinite" loop. However this thread
|
||||
// terminates if the device is closed.
|
||||
for (;;) {
|
||||
//
|
||||
// setting uh_is_initialized to zero in the main thread
|
||||
// tells this one that it is all over now
|
||||
//
|
||||
if (!uh_is_initialized) {
|
||||
return NULL;
|
||||
}
|
||||
//
|
||||
// This is the right place to ensure that a heartbeat is sent
|
||||
// to the microham device regularly (15 sec delay is the maximum
|
||||
// allowed, let us use 5 secs to be on the safe side).
|
||||
//
|
||||
if ((time(NULL)-lastbeat) > 5) {
|
||||
heartbeat();
|
||||
}
|
||||
//
|
||||
// Wait for something to arrive, either from the microham device
|
||||
// or from the sockets used for I/O from hamlib.
|
||||
// If nothing arrives within 100 msec, restart the "infinite loop".
|
||||
//
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(uh_device_fd, &fds);
|
||||
FD_SET(uh_radio_pair[0], &fds);
|
||||
FD_SET(uh_ptt_pair[0], &fds);
|
||||
FD_SET(uh_wkey_pair[0], &fds);
|
||||
|
||||
// determine max of these fd's for use in select()
|
||||
maxdev=uh_device_fd;
|
||||
if (uh_radio_pair[0] > maxdev) {
|
||||
maxdev=uh_radio_pair[0];
|
||||
}
|
||||
if (uh_ptt_pair[0] > maxdev) {
|
||||
maxdev=uh_ptt_pair[0];
|
||||
}
|
||||
if (uh_wkey_pair[0] > maxdev) {
|
||||
maxdev=uh_wkey_pair[0];
|
||||
}
|
||||
|
||||
tv.tv_usec=100000;
|
||||
tv.tv_sec=0;
|
||||
ret=select(maxdev+1, &fds, NULL, NULL, &tv);
|
||||
//
|
||||
// select returned error, or nothing has arrived:
|
||||
// continue "infinite" loop.
|
||||
//
|
||||
if (ret <=0) {
|
||||
continue;
|
||||
}
|
||||
//
|
||||
// Take care of the incoming data (microham device, sockets)
|
||||
//
|
||||
if (FD_ISSET(uh_device_fd, &fds)) {
|
||||
// compose frame, if it is complete, all parseFrame
|
||||
while(read(uh_device_fd, buf, 1) > 0) {
|
||||
if (!(buf[0] & 0x80) && framepos != 0) {
|
||||
ERROR("FrameSyncStartError\n");
|
||||
framepos=0;
|
||||
}
|
||||
if ((buf[0] & 0x80) && framepos == 0) {
|
||||
ERROR("FrameSyncStartError\n");
|
||||
framepos=0;
|
||||
continue;
|
||||
}
|
||||
frame[framepos++]=buf[0];
|
||||
if (framepos >= 4) {
|
||||
framepos=0;
|
||||
parseFrame(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (FD_ISSET(uh_ptt_pair[0], &fds)) {
|
||||
// we do not expect any data here, but drain the socket
|
||||
while(read(uh_ptt_pair[0], buf, 1) >0) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
if (FD_ISSET(uh_radio_pair[0], &fds)) {
|
||||
// read everything that is there, and send it to the radio
|
||||
while(read(uh_radio_pair[0], buf, 1) >0) {
|
||||
writeRadio(buf, 1);
|
||||
}
|
||||
}
|
||||
if (FD_ISSET(uh_wkey_pair[0], &fds)) {
|
||||
// read everything that is there, and send it to the WinKey chip
|
||||
while(read(uh_wkey_pair[0], buf, 1) >0) {
|
||||
writeWkey(buf, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we do not have pthreads, we cannot use the microham device.
|
||||
* This is so because we have to digest unsolicited messages
|
||||
* (e.g. voltage change) and since we have to send periodic
|
||||
* heartbeats.
|
||||
* Nevertheless, the program should compile well even we we do not
|
||||
* have pthreads, in this case start_thread is a dummy since uh_is_initialized
|
||||
* is never set.
|
||||
*/
|
||||
static void start_thread()
|
||||
{
|
||||
#ifdef HAVE_PTHREAD
|
||||
/*
|
||||
* Find a microHam device and open serial port to it.
|
||||
* If successful, create sockets for doing I/O from within hamlib
|
||||
* and start a thread to listen to the "other ends" of the sockets
|
||||
*/
|
||||
int ret, fail;
|
||||
unsigned char buf[4];
|
||||
pthread_attr_t attr;
|
||||
|
||||
if (uh_is_initialized) {
|
||||
return; // PARANOIA: this should not happen
|
||||
}
|
||||
finddevices();
|
||||
if (uh_device_fd < 0) {
|
||||
ERROR("Could not open any microHam device.\n");
|
||||
return;
|
||||
}
|
||||
// Create socket pairs
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, uh_radio_pair) < 0) {
|
||||
perror("RadioPair:");
|
||||
return;
|
||||
}
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, uh_ptt_pair) < 0) {
|
||||
perror("PTTPair:");
|
||||
return;
|
||||
}
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, uh_wkey_pair) < 0) {
|
||||
perror("WkeyPair:");
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG("RADIO sockets: server=%d client=%d\n", uh_radio_pair[0], uh_radio_pair[1]);
|
||||
DEBUG("PTT sockets: server=%d client=%d\n", uh_ptt_pair[0], uh_ptt_pair[1]);
|
||||
DEBUG("WinKey sockets: server=%d client=%d\n", uh_wkey_pair[0], uh_wkey_pair[1]);
|
||||
|
||||
//
|
||||
// Make the sockets nonblocking
|
||||
// First try if we can set flags, then do set the flags
|
||||
//
|
||||
|
||||
fail=0;
|
||||
|
||||
ret=fcntl(uh_radio_pair[0], F_GETFL, 0);
|
||||
if (ret != -1) {
|
||||
ret=fcntl(uh_radio_pair[0], F_SETFL, ret | O_NONBLOCK);
|
||||
}
|
||||
if (ret == -1) {
|
||||
fail=1;
|
||||
}
|
||||
ret=fcntl(uh_ptt_pair[0], F_GETFL, 0);
|
||||
if (ret != -1) {
|
||||
ret=fcntl(uh_ptt_pair[0], F_SETFL, ret | O_NONBLOCK);
|
||||
}
|
||||
if (ret == -1) {
|
||||
fail=1;
|
||||
}
|
||||
ret=fcntl(uh_wkey_pair[0], F_GETFL, 0);
|
||||
if (ret != -1) {
|
||||
ret=fcntl(uh_wkey_pair[0], F_SETFL, ret | O_NONBLOCK);
|
||||
}
|
||||
if (ret == -1) {
|
||||
fail=1;
|
||||
}
|
||||
ret=fcntl(uh_radio_pair[1], F_GETFL, 0);
|
||||
if (ret != -1) {
|
||||
ret=fcntl(uh_radio_pair[1], F_SETFL, ret | O_NONBLOCK);
|
||||
}
|
||||
if (ret == -1) {
|
||||
fail=1;
|
||||
}
|
||||
ret=fcntl(uh_ptt_pair[1], F_GETFL, 0);
|
||||
if (ret != -1) {
|
||||
ret=fcntl(uh_ptt_pair[1], F_SETFL, ret | O_NONBLOCK);
|
||||
}
|
||||
if (ret == -1) {
|
||||
fail=1;
|
||||
}
|
||||
ret=fcntl(uh_wkey_pair[1], F_GETFL, 0);
|
||||
if (ret != -1) {
|
||||
ret=fcntl(uh_wkey_pair[1], F_SETFL, ret | O_NONBLOCK);
|
||||
}
|
||||
if (ret == -1) {
|
||||
fail=1;
|
||||
}
|
||||
|
||||
//
|
||||
// If something went wrong, close everything and return
|
||||
//
|
||||
if (fail) {
|
||||
close_all_files();
|
||||
return;
|
||||
}
|
||||
|
||||
// drain input from microHam device
|
||||
while(read(uh_device_fd, buf, 1) >0) {
|
||||
// do_nothing
|
||||
}
|
||||
|
||||
uh_is_initialized=1;
|
||||
starttime=time(NULL);
|
||||
|
||||
// Do some heartbeats to sync-in
|
||||
heartbeat();
|
||||
heartbeat();
|
||||
heartbeat();
|
||||
|
||||
// Set keyer mode to DIGITAL
|
||||
buf[0]=0x0A; buf[1]=0x03; buf[2]=0x8a; writeControl(buf,3);
|
||||
|
||||
// Start background thread reading the microham device and the sockets
|
||||
pthread_attr_init(&attr);
|
||||
ret=pthread_create(&readthread, &attr, read_device, NULL);
|
||||
if (ret != 0) {
|
||||
ERROR("Could not start read_device thread\n");
|
||||
close_all_files();
|
||||
uh_is_initialized=0;
|
||||
return;
|
||||
}
|
||||
TRACE("Started daemonized thread reading microHam\n");
|
||||
#endif
|
||||
// if we do not have pthreads, this function does nothing.
|
||||
}
|
||||
|
||||
/*
|
||||
* What comes now are "public" functions that can be called from outside
|
||||
*
|
||||
void uh_close_XXX() XXX= ptt, radio, wkey
|
||||
void uh_open_XXX() XXX= ptt, wkey
|
||||
void uh_open_radio(int baud, int databits, int stopbits, int rtscts)
|
||||
void uh_set_ptt(int ptt)
|
||||
int uh_get_ptt()
|
||||
|
||||
* Note that it is not intended that any I/O is done via the PTT sockets
|
||||
* but hamlib needs a valid file descriptor!
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Close routines:
|
||||
* Mark the channel as closed, but close the connection
|
||||
* to the microHam device only if ALL channels are closed
|
||||
*
|
||||
* NOTE: hamlib repeatedly opens/closes the PTT port while keeping the
|
||||
* the radio port open.
|
||||
*/
|
||||
void uh_close_ptt()
|
||||
{
|
||||
uh_ptt_in_use=0;
|
||||
if (!uh_radio_in_use && ! uh_wkey_in_use) {
|
||||
close_microham();
|
||||
}
|
||||
}
|
||||
|
||||
void uh_close_radio()
|
||||
{
|
||||
uh_radio_in_use=0;
|
||||
if (!uh_ptt_in_use && ! uh_wkey_in_use) {
|
||||
close_microham();
|
||||
}
|
||||
}
|
||||
|
||||
void uh_close_wkey()
|
||||
{
|
||||
uh_wkey_in_use=0;
|
||||
if (!uh_ptt_in_use && ! uh_radio_in_use) {
|
||||
close_microham();
|
||||
}
|
||||
}
|
||||
|
||||
int uh_open_ptt()
|
||||
{
|
||||
if (!uh_is_initialized) {
|
||||
start_thread();
|
||||
}
|
||||
if (!uh_is_initialized) {
|
||||
return -1;
|
||||
}
|
||||
uh_ptt_in_use=1;
|
||||
return uh_ptt_pair[1];
|
||||
}
|
||||
|
||||
int uh_open_wkey()
|
||||
{
|
||||
if (!uh_is_initialized) {
|
||||
start_thread();
|
||||
}
|
||||
if (!uh_is_initialized) {
|
||||
return -1;
|
||||
}
|
||||
uh_wkey_in_use=1;
|
||||
return uh_wkey_pair[1];
|
||||
}
|
||||
|
||||
//
|
||||
// Number of stop bits must be 1 or 2.
|
||||
// Number of data bits can be 5,6,7,8
|
||||
// Hardware handshake (rtscts) can be on of off.
|
||||
// microHam devices ALWAY use "no parity".
|
||||
//
|
||||
int uh_open_radio(int baud, int databits, int stopbits, int rtscts)
|
||||
{
|
||||
unsigned char string[5];
|
||||
int baudrateConst;
|
||||
|
||||
if (!uh_is_initialized) {
|
||||
start_thread();
|
||||
}
|
||||
if (!uh_is_initialized) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
baudrateConst = 11059200/baud ;
|
||||
string[0] = 0x01;
|
||||
string[1] = baudrateConst & 0xff ;
|
||||
string[2] = baudrateConst/256 ;
|
||||
switch (stopbits) {
|
||||
case 1: string[3]=0x00; break;
|
||||
case 2: string[3]=0x40; break;
|
||||
default: return -1;
|
||||
}
|
||||
if (rtscts) {
|
||||
string[3] |= 0x10;
|
||||
}
|
||||
switch (databits) {
|
||||
case 5: break;
|
||||
case 6: string[3] |= 0x20; break;
|
||||
case 7: string[3] |= 0x40; break;
|
||||
case 8: string[3] |= 0x60; break;
|
||||
default: return -1;
|
||||
}
|
||||
string[4] = 0x81;
|
||||
writeControl(string, 5);
|
||||
|
||||
uh_radio_in_use=1;
|
||||
return uh_radio_pair[1];
|
||||
}
|
||||
|
||||
void uh_set_ptt(int ptt)
|
||||
{
|
||||
if (!uh_ptt_in_use) {
|
||||
ERROR("%10d:SetPTT but not open\n", TIME);
|
||||
return;
|
||||
}
|
||||
DEBUG("%10d:SET PTT = %d\n", TIME, ptt);
|
||||
if (ptt) {
|
||||
statusbyte |= 0x04;
|
||||
} else {
|
||||
statusbyte &= ~0x04;
|
||||
}
|
||||
writeFlags();
|
||||
}
|
||||
|
||||
int uh_get_ptt()
|
||||
{
|
||||
if (statusbyte & 0x04) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
//
|
||||
// Support for microHam
|
||||
//
|
||||
// Store the fd's of the sockets here. Then we can tell later on
|
||||
// whether we are working on a "real" serial interface or on a socket
|
||||
//
|
||||
|
||||
int uh_ptt_fd = -1; // PUBLIC! must be visible in iofunc.c in WIN32 case
|
||||
int uh_radio_fd = -1; // PUBLIC! must be visible in iofunc.c in WIN32 case
|
||||
|
||||
extern int uh_open_radio(int baud, int databits, int stopbits, int rtscts);
|
||||
extern int uh_open_ptt();
|
||||
extern void uh_set_ptt(int ptt);
|
||||
extern int uh_get_ptt();
|
||||
extern void uh_close_radio();
|
||||
extern void uh_close_ptt();
|
||||
|
157
src/serial.c
157
src/serial.c
|
@ -82,6 +82,7 @@
|
|||
#include <sys/ioccom.h>
|
||||
#endif
|
||||
|
||||
#include "microham.h"
|
||||
|
||||
/**
|
||||
* \brief Open serial port using rig.state data
|
||||
|
@ -100,6 +101,48 @@ int HAMLIB_API serial_open(hamlib_port_t *rp)
|
|||
return -RIG_EINVAL;
|
||||
}
|
||||
|
||||
if (!strncmp(rp->pathname,"uh-rig",6)) {
|
||||
/*
|
||||
* If the pathname is EXACTLY "uh-rig", try to use a microHam device
|
||||
* rather than a conventional serial port.
|
||||
* The microHam devices ALWAYS use "no parity", and can either use no handshake
|
||||
* or hardware handshake. Return with error if something else is requested.
|
||||
*/
|
||||
if (rp->parm.serial.parity != RIG_PARITY_NONE) {
|
||||
return -RIG_EIO;
|
||||
}
|
||||
if ((rp->parm.serial.handshake != RIG_HANDSHAKE_HARDWARE) &&
|
||||
(rp->parm.serial.handshake != RIG_HANDSHAKE_NONE)) {
|
||||
return -RIG_EIO;
|
||||
}
|
||||
/*
|
||||
* Note that serial setup is also don in uh_open_radio.
|
||||
* So we need to dig into serial_setup().
|
||||
*/
|
||||
fd=uh_open_radio( rp->parm.serial.rate, // baud
|
||||
rp->parm.serial.data_bits, // databits
|
||||
rp->parm.serial.stop_bits, // stopbits
|
||||
(rp->parm.serial.handshake == RIG_HANDSHAKE_HARDWARE)); // rtscts
|
||||
if (fd == -1) {
|
||||
return -RIG_EIO;
|
||||
}
|
||||
rp->fd=fd;
|
||||
/*
|
||||
* Remember the fd in a global variable. We can do read(), write() and select()
|
||||
* on fd but whenever it is tried to do an ioctl(), we have to catch it
|
||||
* (e.g. setting DTR or tcflush on this fd does not work)
|
||||
* While this may look dirty, it is certainly easier and more efficient than
|
||||
* to check whether fd corresponds to a serial line or a socket everywhere.
|
||||
*
|
||||
* CAVEAT: for WIN32, it might be necessary to use win_serial_read() instead
|
||||
* of read() for serial lines in iofunc.c. Therefore, we have to
|
||||
* export uh_radio_fd to iofunc.c because in the case of sockets,
|
||||
* read() must be used also in the WIN32 case.
|
||||
* This is why uh_radio_fd is declared globally in microham.h.
|
||||
*/
|
||||
uh_radio_fd=fd;
|
||||
return RIG_OK;
|
||||
}
|
||||
/*
|
||||
* Open in Non-blocking mode. Watch for EAGAIN errors!
|
||||
*/
|
||||
|
@ -449,8 +492,19 @@ int HAMLIB_API serial_flush(hamlib_port_t *p)
|
|||
{
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
||||
|
||||
if (p->fd == uh_ptt_fd || p->fd == uh_radio_fd) {
|
||||
char buf[32];
|
||||
/*
|
||||
* Catch microHam case:
|
||||
* if fd corresponds to a microHam device drain the line
|
||||
* (which is a socket) by reading until it is empty.
|
||||
*/
|
||||
while (read(p->fd, buf, 32) > 0) {
|
||||
/* do nothing */
|
||||
}
|
||||
return RIG_OK;
|
||||
}
|
||||
tcflush(p->fd, TCIFLUSH);
|
||||
|
||||
return RIG_OK;
|
||||
}
|
||||
|
||||
|
@ -462,9 +516,37 @@ int HAMLIB_API serial_flush(hamlib_port_t *p)
|
|||
*/
|
||||
int ser_open(hamlib_port_t *p)
|
||||
{
|
||||
int ret;
|
||||
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
||||
|
||||
return (p->fd = OPEN(p->pathname, O_RDWR | O_NOCTTY | O_NDELAY));
|
||||
if (!strncmp(p->pathname,"uh-rig",6)) {
|
||||
/*
|
||||
* This should not happen: ser_open is only used for
|
||||
* DTR-only serial ports (ptt_pathname != rig_pathname).
|
||||
*/
|
||||
ret=-1;
|
||||
} else {
|
||||
if (!strncmp(p->pathname,"uh-ptt",6)) {
|
||||
/*
|
||||
* Use microHam device for doing PTT. Although a valid file
|
||||
* descriptor is returned, it is not used for anything
|
||||
* but must be remembered in a global variable:
|
||||
* If it is tried later to set/unset DTR on this fd, we know
|
||||
* that we cannot use ioctl and must rather call our
|
||||
* PTT set/unset service routine.
|
||||
*/
|
||||
ret=uh_open_ptt();
|
||||
uh_ptt_fd=ret;
|
||||
} else {
|
||||
/*
|
||||
* pathname is not uh_rig or uh_ptt: simply open()
|
||||
*/
|
||||
ret=OPEN(p->pathname, O_RDWR | O_NOCTTY | O_NDELAY);
|
||||
}
|
||||
}
|
||||
p->fd=ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -475,9 +557,30 @@ int ser_open(hamlib_port_t *p)
|
|||
*/
|
||||
int ser_close(hamlib_port_t *p)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
||||
|
||||
int rc = CLOSE(p->fd);
|
||||
/*
|
||||
* For microHam devices, do not close the
|
||||
* socket via close but call a service routine
|
||||
* (which might decide to keep the socket open).
|
||||
* However, unset p->fd and uh_ptt_fd/uh_radio_fd.
|
||||
*/
|
||||
if (p->fd == uh_ptt_fd) {
|
||||
uh_close_ptt();
|
||||
uh_ptt_fd=-1;
|
||||
p->fd = -1;
|
||||
return 0;
|
||||
}
|
||||
if (p->fd == uh_radio_fd) {
|
||||
uh_close_radio();
|
||||
uh_radio_fd=-1;
|
||||
p->fd = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = CLOSE(p->fd);
|
||||
p->fd = -1;
|
||||
return rc;
|
||||
}
|
||||
|
@ -498,6 +601,11 @@ int HAMLIB_API ser_set_rts(hamlib_port_t *p, int state)
|
|||
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s: RTS=%d\n", __func__, state);
|
||||
|
||||
// ignore this for microHam ports
|
||||
if (p->fd == uh_ptt_fd || p->fd == uh_radio_fd) {
|
||||
return RIG_OK;
|
||||
}
|
||||
|
||||
#if defined(TIOCMBIS) && defined(TIOCMBIC)
|
||||
rc = IOCTL(p->fd, state ? TIOCMBIS : TIOCMBIC, &y);
|
||||
#else
|
||||
|
@ -539,6 +647,11 @@ int HAMLIB_API ser_get_rts(hamlib_port_t *p, int *state)
|
|||
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
||||
|
||||
// cannot do this for microHam ports
|
||||
if (p->fd == uh_ptt_fd || p->fd == uh_radio_fd) {
|
||||
return -RIG_ENIMPL;
|
||||
}
|
||||
|
||||
retcode = IOCTL(p->fd, TIOCMGET, &y);
|
||||
*state = (y & TIOCM_RTS) == TIOCM_RTS;
|
||||
|
||||
|
@ -561,6 +674,16 @@ int HAMLIB_API ser_set_dtr(hamlib_port_t *p, int state)
|
|||
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s: DTR=%d\n", __func__, state);
|
||||
|
||||
// silently ignore on microHam RADIO channel,
|
||||
// but (un)set ptt on microHam PTT channel.
|
||||
if (p->fd == uh_radio_fd) {
|
||||
return RIG_OK;
|
||||
}
|
||||
if (p->fd == uh_ptt_fd) {
|
||||
uh_set_ptt(state);
|
||||
return RIG_OK;
|
||||
}
|
||||
|
||||
#if defined(TIOCMBIS) && defined(TIOCMBIC)
|
||||
rc = IOCTL(p->fd, state ? TIOCMBIS : TIOCMBIC, &y);
|
||||
#else
|
||||
|
@ -602,6 +725,15 @@ int HAMLIB_API ser_get_dtr(hamlib_port_t *p, int *state)
|
|||
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
||||
|
||||
// cannot do this for the RADIO port, return PTT state for the PTT port
|
||||
if (p->fd == uh_ptt_fd) {
|
||||
*state=uh_get_ptt();
|
||||
return RIG_OK;
|
||||
}
|
||||
if (p->fd == uh_radio_fd) {
|
||||
return -RIG_ENIMPL;
|
||||
}
|
||||
|
||||
retcode = IOCTL(p->fd, TIOCMGET, &y);
|
||||
*state = (y & TIOCM_DTR) == TIOCM_DTR;
|
||||
|
||||
|
@ -619,6 +751,11 @@ int HAMLIB_API ser_set_brk(hamlib_port_t *p, int state)
|
|||
{
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
||||
|
||||
// ignore this for microHam ports
|
||||
if (p->fd == uh_ptt_fd || p->fd == uh_radio_fd) {
|
||||
return RIG_OK;
|
||||
}
|
||||
|
||||
#if defined(TIOCSBRK) && defined(TIOCCBRK)
|
||||
return IOCTL(p->fd, state ? TIOCSBRK : TIOCCBRK, 0) < 0 ?
|
||||
-RIG_EIO : RIG_OK;
|
||||
|
@ -640,6 +777,11 @@ int HAMLIB_API ser_get_car(hamlib_port_t *p, int *state)
|
|||
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
||||
|
||||
// cannot do this for microHam ports
|
||||
if (p->fd == uh_ptt_fd || p->fd == uh_radio_fd) {
|
||||
return -RIG_ENIMPL;
|
||||
}
|
||||
|
||||
retcode = IOCTL(p->fd, TIOCMGET, &y);
|
||||
*state = (y & TIOCM_CAR) == TIOCM_CAR;
|
||||
|
||||
|
@ -659,6 +801,11 @@ int HAMLIB_API ser_get_cts(hamlib_port_t *p, int *state)
|
|||
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
||||
|
||||
// cannot do this for microHam ports
|
||||
if (p->fd == uh_ptt_fd || p->fd == uh_radio_fd) {
|
||||
return -RIG_ENIMPL;
|
||||
}
|
||||
|
||||
retcode = IOCTL(p->fd, TIOCMGET, &y);
|
||||
*state = (y & TIOCM_CTS) == TIOCM_CTS;
|
||||
|
||||
|
@ -678,6 +825,10 @@ int HAMLIB_API ser_get_dsr(hamlib_port_t *p, int *state)
|
|||
|
||||
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
||||
|
||||
// cannot do this for microHam ports
|
||||
if (p->fd == uh_ptt_fd || p->fd == uh_radio_fd) {
|
||||
return -RIG_ENIMPL;
|
||||
}
|
||||
retcode = IOCTL(p->fd, TIOCMGET, &y);
|
||||
*state = (y & TIOCM_DSR) == TIOCM_DSR;
|
||||
|
||||
|
|
|
@ -52,7 +52,8 @@ for NET rigctl (rigctld).
|
|||
Use \fIdevice\fP as the file name of the port the radio is connected.
|
||||
Often a serial port, but could be a USB to serial adapter. Typically
|
||||
/dev/ttyS0, /dev/ttyS1, /dev/ttyUSB0, etc. on Linux or COM1, COM2, etc.
|
||||
on Win32.
|
||||
on Win32. The special string 'uh\-rig' may be given to enable micro-ham
|
||||
device support.
|
||||
.TP
|
||||
.B \-p, --ptt-file=device
|
||||
Use \fIdevice\fP as the file name of the Push-To-Talk device using a
|
||||
|
|
|
@ -69,7 +69,8 @@ Select radio model number. See the -l, --list option below.
|
|||
Use \fIdevice\fP as the file name of the port the radio is connected.
|
||||
Often a serial port, but could be a USB to serial adapter or USB port device.
|
||||
Typically /dev/ttyS0, /dev/ttyS1, /dev/ttyUSB0, etc. on Linux or COM1, COM2,
|
||||
etc. on Win32.
|
||||
etc. on Win32. The special string 'uh\-rig' may be given to enable micro-ham
|
||||
device support.
|
||||
.TP
|
||||
.B \-p, --ptt-file=device
|
||||
Use \fIdevice\fP as the file name of the Push-To-Talk device using a
|
||||
|
|
|
@ -52,7 +52,8 @@ for NET rotctl (rotctld).
|
|||
Use \fIdevice\fP as the file name of the port the rotator is connected.
|
||||
Often a serial port, but could be a USB to serial adapter or USB port device.
|
||||
Typically /dev/ttyS0, /dev/ttyS1, /dev/ttyUSB0, etc. on Linux or COM1, COM2,
|
||||
etc. on Win32.
|
||||
etc. on Win32. The special string 'uh\-rig' may be given to enable micro-ham
|
||||
device support.
|
||||
.TP
|
||||
.B \-s, --serial-speed=baud
|
||||
Set serial speed to \fIbaud\fP rate. Uses maximum serial speed from rotator
|
||||
|
|
|
@ -70,7 +70,8 @@ Select rotator model number. See -l, "list" option below.
|
|||
Use \fIdevice\fP as the file name of the port the rotator is connected.
|
||||
Often a serial port, but could be a USB to serial adapter or USB port device.
|
||||
Typically /dev/ttyS0, /dev/ttyS1, /dev/ttyUSB0, etc. on Linux or COM1, COM2,
|
||||
etc. on Win32.
|
||||
etc. on Win32. The special string 'uh\-rig' may be given to enable micro-ham
|
||||
device support.
|
||||
.TP
|
||||
.B \-s, --serial-speed=baud
|
||||
Set serial speed to \fIbaud\fP rate. Uses maximum serial speed from rotor
|
||||
|
|
Ładowanie…
Reference in New Issue