Hamlib/src/microham.c

967 wiersze
26 KiB
C
Czysty Zwykły widok Historia

//
// This file contains the support for microHam devices
//
// On WIN32, this behaves as if no microHam device is connected
// to the computer since (at least my version of MinGW) does not
// support socketpair().
//
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <time.h>
#include <limits.h>
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
//#define FRAME(s, ...) printf(s, ##__VA_ARGS__)
//#define DEBUG(s, ...) printf(s, ##__VA_ARGS__)
//#define TRACE(s, ...) printf(s, ##__VA_ARGS__)
//#define MYERROR(s, ...) printf(s, ##__VA_ARGS__)
#ifndef FRAME
#define FRAME(s, ...)
#endif
#ifndef DEBUG
#define DEBUG(s, ...)
#endif
#ifndef TRACE
#define TRACE(s, ...)
#endif
#ifndef MYERROR
#define MYERROR(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) || !defined(HAVE_GLOB_H)
/*
* 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.
*
* 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.
*
*
* For those who want to implement the WIN32 case here properly:
*
* 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 with correct serial speed etc. 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.
*
* Note: StationMaster uses a different protocol, and
* the protocol of StationMaster DeLuxe is not
* even disclosed.
*
* We are using the glob() function to obtain a list
* of candidates.
*/
#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>
#include <sys/stat.h>
#include <glob.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.
MYERROR("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) {
MYERROR("Cannot open serial port %s\n",uh_device_path);
perror("Open:");
continue;
}
tcflush(fd, TCIFLUSH);
if (tcgetattr( fd, &TTY)) {
MYERROR("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)) {
MYERROR("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) {
MYERROR("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: // Flag byte
DEBUG("%10d:RCV: Flags=%02x\n", TIME, byte);
// No reason to pass the flags to clients
break;
case 1: // part of control string
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.
// Note that we can get a lot of unsolicited control messages
// here (squelch, voltage change, etc.)
break;
}
// in the middle of a control string
controlstring[numcontrolbytes++]=byte;
break;
case 2: // message from WinKey chip
DEBUG("%10d:RCV: WinKey=%02x\n", TIME, byte);
if (write(uh_wkey_pair[0], &byte, 1) != 1) {
MYERROR("Write Winkey socket\n");
}
break;
case 3: // Key pressed on PS2 keyboard connected to microHam device
DEBUG("%10d:RCV: PS2=%02x\n", TIME,byte);
break;
}
}
}
//
// Send radio bytes to microHam device
//
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) {
MYERROR("WriteRadio failed with %d\n", ret);
if (ret < 0) {
perror("WriteRadioError:");
}
}
}
freelock();
}
//
// send statusbyte to microHam device
//
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) {
MYERROR("WriteFlags failed with %d\n", ret);
if (ret < 0) {
perror("WriteFlagsError:");
}
}
freelock();
}
//
// Send bytes to the WinKeyer within microHam device
//
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) {
MYERROR("WriteWINKEY failed with %d\n", ret);
if (ret < 0) {
perror("WriteWinkeyError:");
}
}
}
freelock();
}
//
// Write a control string to the microHam device
//
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) {
MYERROR("WriteControl failed, ret=%d\n", ret);
if (ret < 0) {
perror("WriteControlError:");
}
}
}
freelock();
}
//
// send a heartbeat and record time
// The "last heartbeat" time is recorded in a global variable
// such that the service thread can decice whether a new
// heartbeat is due.
//
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)
{
#if defined(HAVE_SELECT)
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) {
MYERROR("FrameSyncStartError\n");
framepos=0;
}
if ((buf[0] & 0x80) && framepos == 0) {
MYERROR("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);
}
}
}
#endif
return NULL;
}
/*
* 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.
*
* If we do not have socketpair(), the same thing applies.
*
* If we do not have select(), then the read thread cannot work so we
* do not spawn it.
*/
static void start_thread()
{
#if defined(HAVE_PTHREAD) && defined(HAVE_SOCKETPAIR) && defined(HAVE_SELECT)
/*
* 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) {
MYERROR("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) {
MYERROR("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) {
MYERROR("%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()
{
// Possibly we can do better, but we just reflect
// what we have done via uh_set_ptt.
if (statusbyte & 0x04) {
return 1;
} else {
return 0;
}
}