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
c vw 2017-08-16 09:09:10 +02:00 zatwierdzone przez Nate Bargmann
rodzic 3709fcb982
commit d008ca6e5d
11 zmienionych plików z 1184 dodań i 25 usunięć

1
NEWS
Wyświetl plik

@ -12,6 +12,7 @@ Version 3.2
* New model, FT-891. Mike, W9MDB * New model, FT-891. Mike, W9MDB
* Build instructions and test script for Python3 * Build instructions and test script for Python3
* Rename autogen.sh to bootsrap and don't call configure * Rename autogen.sh to bootsrap and don't call configure
* micro-ham support. Christoph, DL1YCF
Version 3.1 Version 3.1
2016-12-31 2016-12-31

Wyświetl plik

@ -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. 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 Often a serial port, but could be a USB to serial adapter. Typically
@file{/dev/ttyS0} , @file{/dev/ttyS1} , @file{/dev/ttyUSB0} , etc.@: @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 @ifhtml
@* @*
@end 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}). rotor model 2 for NET rotctl (@command{rotctld}).
@item -r @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. 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 Often a serial port, but could be a USB to serial adapter. Typically
@file{/dev/ttyS0} , @file{/dev/ttyS1} , @file{/dev/ttyUSB0} , etc.@: @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 @ifhtml
@* @*
@end 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. 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 Often a serial port, but could be a USB to serial adapter. Typically
@file{/dev/ttyS0} , @file{/dev/ttyS1} , @file{/dev/ttyUSB0} , etc.@: @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 @ifhtml
@* @*
@end 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}). rotor model 2 for NET rotctl (@command{rotctld}).
@item -r @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. 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 Often a serial port, but could be a USB to serial adapter. Typically
@file{/dev/ttyS0} , @file{/dev/ttyS1} , @file{/dev/ttyUSB0} , etc.@: @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 @ifhtml
@* @*
@end ifhtml @end ifhtml

Wyświetl plik

@ -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 \ 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 \ 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 \ 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 lib_LTLIBRARIES = libhamlib.la
libhamlib_la_SOURCES = $(RIGSRC) libhamlib_la_SOURCES = $(RIGSRC)

Wyświetl plik

@ -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) #if defined(WIN32) && !defined(HAVE_TERMIOS_H)
#include "win32termios.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 /* On MinGW32/MSVC/.. the appropriate accessor must be used
* depending on the port type, sigh. * 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; int i;
ssize_t ret; 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) { if (p->type.rig == RIG_PORT_SERIAL) {
ret = win32_serial_read(p->fd, buf, count); 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) 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) { if (p->type.rig == RIG_PORT_SERIAL) {
return win32_serial_write(p->fd, buf, count); return win32_serial_write(p->fd, buf, count);
} else if (p->type.rig == RIG_PORT_NETWORK } 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; exceptfds = NULL;
#endif #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) { if (p->type.rig == RIG_PORT_SERIAL) {
return win32_serial_select(n, readfds, writefds, exceptfds, timeout); return win32_serial_select(n, readfds, writefds, exceptfds, timeout);
} else { } else {

942
src/microham.c 100644
Wyświetl plik

@ -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;
}
}

17
src/microham.h 100644
Wyświetl plik

@ -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();

Wyświetl plik

@ -82,6 +82,7 @@
#include <sys/ioccom.h> #include <sys/ioccom.h>
#endif #endif
#include "microham.h"
/** /**
* \brief Open serial port using rig.state data * \brief Open serial port using rig.state data
@ -100,6 +101,48 @@ int HAMLIB_API serial_open(hamlib_port_t *rp)
return -RIG_EINVAL; 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! * 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__); 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); tcflush(p->fd, TCIFLUSH);
return RIG_OK; return RIG_OK;
} }
@ -462,9 +516,37 @@ int HAMLIB_API serial_flush(hamlib_port_t *p)
*/ */
int ser_open(hamlib_port_t *p) int ser_open(hamlib_port_t *p)
{ {
int ret;
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); 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 ser_close(hamlib_port_t *p)
{ {
int rc;
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); 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; p->fd = -1;
return rc; 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); 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) #if defined(TIOCMBIS) && defined(TIOCMBIC)
rc = IOCTL(p->fd, state ? TIOCMBIS : TIOCMBIC, &y); rc = IOCTL(p->fd, state ? TIOCMBIS : TIOCMBIC, &y);
#else #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__); 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); retcode = IOCTL(p->fd, TIOCMGET, &y);
*state = (y & TIOCM_RTS) == TIOCM_RTS; *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); 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) #if defined(TIOCMBIS) && defined(TIOCMBIC)
rc = IOCTL(p->fd, state ? TIOCMBIS : TIOCMBIC, &y); rc = IOCTL(p->fd, state ? TIOCMBIS : TIOCMBIC, &y);
#else #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__); 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); retcode = IOCTL(p->fd, TIOCMGET, &y);
*state = (y & TIOCM_DTR) == TIOCM_DTR; *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__); 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) #if defined(TIOCSBRK) && defined(TIOCCBRK)
return IOCTL(p->fd, state ? TIOCSBRK : TIOCCBRK, 0) < 0 ? return IOCTL(p->fd, state ? TIOCSBRK : TIOCCBRK, 0) < 0 ?
-RIG_EIO : RIG_OK; -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__); 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); retcode = IOCTL(p->fd, TIOCMGET, &y);
*state = (y & TIOCM_CAR) == TIOCM_CAR; *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__); 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); retcode = IOCTL(p->fd, TIOCMGET, &y);
*state = (y & TIOCM_CTS) == TIOCM_CTS; *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__); 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); retcode = IOCTL(p->fd, TIOCMGET, &y);
*state = (y & TIOCM_DSR) == TIOCM_DSR; *state = (y & TIOCM_DSR) == TIOCM_DSR;

Wyświetl plik

@ -52,7 +52,8 @@ for NET rigctl (rigctld).
Use \fIdevice\fP as the file name of the port the radio is connected. 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 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. /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 .TP
.B \-p, --ptt-file=device .B \-p, --ptt-file=device
Use \fIdevice\fP as the file name of the Push-To-Talk device using a Use \fIdevice\fP as the file name of the Push-To-Talk device using a

Wyświetl plik

@ -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. 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. 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, 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 .TP
.B \-p, --ptt-file=device .B \-p, --ptt-file=device
Use \fIdevice\fP as the file name of the Push-To-Talk device using a Use \fIdevice\fP as the file name of the Push-To-Talk device using a

Wyświetl plik

@ -52,7 +52,8 @@ for NET rotctl (rotctld).
Use \fIdevice\fP as the file name of the port the rotator is connected. 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. 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, 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 .TP
.B \-s, --serial-speed=baud .B \-s, --serial-speed=baud
Set serial speed to \fIbaud\fP rate. Uses maximum serial speed from rotator Set serial speed to \fIbaud\fP rate. Uses maximum serial speed from rotator

Wyświetl plik

@ -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. 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. 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, 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 .TP
.B \-s, --serial-speed=baud .B \-s, --serial-speed=baud
Set serial speed to \fIbaud\fP rate. Uses maximum serial speed from rotor Set serial speed to \fIbaud\fP rate. Uses maximum serial speed from rotor