Hamlib/src/amplifier.c

710 wiersze
15 KiB
C
Czysty Zwykły widok Historia

2019-06-12 20:52:35 +00:00
/*
* Hamlib Interface - main file
* Copyright (c) 2000-2012 by Stephane Fillod
* Copyright (c) 2000-2003 by Frank Singleton
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
/**
* \addtogroup amplifier
* @{
*/
/**
* \file src/amplifier.c
* \brief Amplifier interface
* \author Stephane Fillod
* \date 2000-2012
*
* Hamlib interface is a frontend implementing amplifier wrapper functions.
*/
/**
* \page amp Amplifier interface
*
* Amplifier can be any kind of azimuth or azimuth and elevation controlled
* antenna system.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <hamlib/amplifier.h>
#include "serial.h"
#include "parallel.h"
#include "usb_port.h"
#include "network.h"
#include "amp_conf.h"
#include "token.h"
#define CHECK_AMP_ARG(r) (!(r) || !(r)->caps || !(r)->state.comm_state)
/*
* Data structure to track the opened amp (by amp_open)
*/
struct opened_amp_l
{
2019-11-30 16:19:08 +00:00
AMP *amp;
struct opened_amp_l *next;
2019-06-12 20:52:35 +00:00
};
static struct opened_amp_l *opened_amp_list = { NULL };
/*
* track which amp is opened (with amp_open)
* needed at least for transceive mode
*/
static int add_opened_amp(AMP *amp)
{
2019-11-30 16:19:08 +00:00
struct opened_amp_l *p;
p = (struct opened_amp_l *)malloc(sizeof(struct opened_amp_l));
if (!p)
{
return -RIG_ENOMEM;
}
p->amp = amp;
p->next = opened_amp_list;
opened_amp_list = p;
return RIG_OK;
2019-06-12 20:52:35 +00:00
}
static int remove_opened_amp(AMP *amp)
{
2019-11-30 16:19:08 +00:00
struct opened_amp_l *p, *q;
q = NULL;
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
for (p = opened_amp_list; p; p = p->next)
2019-06-12 20:52:35 +00:00
{
2019-11-30 16:19:08 +00:00
if (p->amp == amp)
{
if (q == NULL)
{
opened_amp_list = opened_amp_list->next;
}
else
{
q->next = p->next;
}
free(p);
return RIG_OK;
}
q = p;
2019-06-12 20:52:35 +00:00
}
2019-11-30 16:19:08 +00:00
return -RIG_EINVAL; /* Not found in list ! */
2019-06-12 20:52:35 +00:00
}
2019-12-08 22:27:46 +00:00
#ifdef XXREMOVEDXX
2019-06-12 20:52:35 +00:00
/**
* \brief execs cfunc() on each opened amp
* \param cfunc The function to be executed on each amp
* \param data Data pointer to be passed to cfunc()
*
* Calls cfunc() function for each opened amp. The contents of the opened
* amp table is processed in random order according to a function pointed to
* by \a cfunc, whic is called with two arguments, the first pointing to the
* #AMP handle, the second to a data pointer \a data.
*
* If \a data is not needed, then it can be set to NULL. The processing of
* the opened amp table is stopped when cfunc() returns 0.
* \internal
*
* \return always RIG_OK.
*/
int foreach_opened_amp(int (*cfunc)(AMP *, rig_ptr_t), rig_ptr_t data)
{
2019-11-30 16:19:08 +00:00
struct opened_amp_l *p;
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
for (p = opened_amp_list; p; p = p->next)
2019-06-12 20:52:35 +00:00
{
2019-11-30 16:19:08 +00:00
if ((*cfunc)(p->amp, data) == 0)
{
return RIG_OK;
}
2019-06-12 20:52:35 +00:00
}
2019-11-30 16:19:08 +00:00
return RIG_OK;
2019-06-12 20:52:35 +00:00
}
2019-12-08 22:27:46 +00:00
#endif
2019-06-12 20:52:35 +00:00
/**
* \brief allocate a new #AMP handle
* \param amp_model The amp model for this new handle
*
* Allocates a new #AMP handle and initializes the associated data
* for \a amp_model.
*
* \return a pointer to the #AMP handle otherwise NULL if memory allocation
* failed or \a amp_model is unknown (e.g. backend autoload failed).
*
* \sa amp_cleanup(), amp_open()
*/
AMP *HAMLIB_API amp_init(amp_model_t amp_model)
{
2019-11-30 16:19:08 +00:00
AMP *amp;
const struct amp_caps *caps;
struct amp_state *rs;
amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
amp_check_backend(amp_model);
caps = amp_get_caps(amp_model);
if (!caps)
{
return NULL;
}
/*
* okay, we've found it. Allocate some memory and set it to zeros,
* and especially the initialize the callbacks
*/
amp = calloc(1, sizeof(AMP));
if (amp == NULL)
{
/*
* FIXME: how can the caller know it's a memory shortage,
* and not "amp not found" ?
*/
return NULL;
}
/* caps is const, so we need to tell compiler
that we know what we are doing */
amp->caps = (struct amp_caps *) caps;
/*
* populate the amp->state
* TODO: read the Preferences here!
*/
rs = &amp->state;
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
rs->comm_state = 0;
rs->ampport.type.rig = caps->port_type; /* default from caps */
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
rs->ampport.write_delay = caps->write_delay;
rs->ampport.post_write_delay = caps->post_write_delay;
rs->ampport.timeout = caps->timeout;
rs->ampport.retry = caps->retry;
rs->has_get_level = caps->has_get_level;
switch (caps->port_type)
{
case RIG_PORT_SERIAL:
// Dont' think we need a default port here
//strncpy(rs->ampport.pathname, DEFAULT_SERIAL_PORT, FILPATHLEN - 1);
rs->ampport.parm.serial.rate = caps->serial_rate_max; /* fastest ! */
rs->ampport.parm.serial.data_bits = caps->serial_data_bits;
rs->ampport.parm.serial.stop_bits = caps->serial_stop_bits;
rs->ampport.parm.serial.parity = caps->serial_parity;
rs->ampport.parm.serial.handshake = caps->serial_handshake;
break;
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
case RIG_PORT_NETWORK:
case RIG_PORT_UDP_NETWORK:
strncpy(rs->ampport.pathname, "127.0.0.1:4531", FILPATHLEN - 1);
2019-11-30 16:19:08 +00:00
break;
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
default:
strncpy(rs->ampport.pathname, "", FILPATHLEN - 1);
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
rs->ampport.fd = -1;
2019-06-12 20:52:35 +00:00
/*
2019-11-30 16:19:08 +00:00
* let the backend a chance to setup his private data
* This must be done only once defaults are setup,
* so the backend init can override amp_state.
2019-06-12 20:52:35 +00:00
*/
2019-11-30 16:19:08 +00:00
if (caps->amp_init != NULL)
{
2019-12-08 22:27:46 +00:00
int retcode = caps->amp_init(amp);
2019-11-30 16:19:08 +00:00
if (retcode != RIG_OK)
{
amp_debug(RIG_DEBUG_VERBOSE,
"%s: backend_init failed!\n",
__func__);
/* cleanup and exit */
free(amp);
return NULL;
}
}
return amp;
2019-06-12 20:52:35 +00:00
}
/**
* \brief open the communication to the amp
* \param amp The #AMP handle of the amplifier to be opened
*
* Opens communication to a amplifier which \a AMP handle has been passed
* by argument.
*
* \return RIG_OK if the operation has been sucessful, otherwise
* a negative value if an error occured (in which case, cause is
* set appropriately).
*
* \retval RIG_EINVAL \a amp is NULL or unconsistent.
* \retval RIG_ENIMPL port type communication is not implemented yet.
*
* \sa amp_init(), amp_close()
*/
int HAMLIB_API amp_open(AMP *amp)
{
2019-11-30 16:19:08 +00:00
const struct amp_caps *caps;
struct amp_state *rs;
int status;
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (!amp || !amp->caps)
{
return -RIG_EINVAL;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
caps = amp->caps;
rs = &amp->state;
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (rs->comm_state)
{
return -RIG_EINVAL;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
rs->ampport.fd = -1;
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
switch (rs->ampport.type.rig)
2019-06-12 20:52:35 +00:00
{
2019-11-30 16:19:08 +00:00
case RIG_PORT_SERIAL:
status = serial_open(&rs->ampport);
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (status != 0)
{
return status;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
break;
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
case RIG_PORT_PARALLEL:
status = par_open(&rs->ampport);
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (status < 0)
{
return status;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
break;
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
case RIG_PORT_DEVICE:
status = open(rs->ampport.pathname, O_RDWR, 0);
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (status < 0)
{
return -RIG_EIO;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
rs->ampport.fd = status;
break;
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
case RIG_PORT_USB:
status = usb_port_open(&rs->ampport);
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (status < 0)
{
return status;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
break;
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
case RIG_PORT_NONE:
case RIG_PORT_RPC:
break; /* ez :) */
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
case RIG_PORT_NETWORK:
case RIG_PORT_UDP_NETWORK:
/* FIXME: default port */
status = network_open(&rs->ampport, 4531);
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (status < 0)
{
return status;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
break;
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
default:
return -RIG_EINVAL;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
add_opened_amp(amp);
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
rs->comm_state = 1;
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
/*
* Maybe the backend has something to initialize
* In case of failure, just close down and report error code.
*/
if (caps->amp_open != NULL)
2019-06-12 20:52:35 +00:00
{
2019-11-30 16:19:08 +00:00
status = caps->amp_open(amp);
if (status != RIG_OK)
{
return status;
}
2019-06-12 20:52:35 +00:00
}
2019-11-30 16:19:08 +00:00
return RIG_OK;
2019-06-12 20:52:35 +00:00
}
/**
* \brief close the communication to the amp
* \param amp The #AMP handle of the amplifier to be closed
*
* Closes communication to a amplifier which \a AMP handle has been passed
* by argument that was previously open with amp_open().
*
* \return RIG_OK if the operation has been sucessful, otherwise
* a negative value if an error occured (in which case, cause is
* set appropriately).
*
* \sa amp_cleanup(), amp_open()
*/
int HAMLIB_API amp_close(AMP *amp)
{
2019-11-30 16:19:08 +00:00
const struct amp_caps *caps;
struct amp_state *rs;
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (!amp || !amp->caps)
{
return -RIG_EINVAL;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
caps = amp->caps;
rs = &amp->state;
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (!rs->comm_state)
2019-06-12 20:52:35 +00:00
{
2019-11-30 16:19:08 +00:00
return -RIG_EINVAL;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
/*
* Let the backend say 73s to the amp.
* and ignore the return code.
*/
if (caps->amp_close)
{
caps->amp_close(amp);
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (rs->ampport.fd != -1)
{
switch (rs->ampport.type.rig)
{
case RIG_PORT_SERIAL:
ser_close(&rs->ampport);
break;
case RIG_PORT_PARALLEL:
par_close(&rs->ampport);
break;
case RIG_PORT_USB:
usb_port_close(&rs->ampport);
break;
case RIG_PORT_NETWORK:
case RIG_PORT_UDP_NETWORK:
network_close(&rs->ampport);
break;
default:
close(rs->ampport.fd);
}
rs->ampport.fd = -1;
2019-06-12 20:52:35 +00:00
}
2019-11-30 16:19:08 +00:00
remove_opened_amp(amp);
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
rs->comm_state = 0;
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
return RIG_OK;
2019-06-12 20:52:35 +00:00
}
/**
* \brief release a amp handle and free associated memory
* \param amp The #AMP handle of the radio to be closed
*
* Releases a amp struct which port has eventualy been closed already
* with amp_close().
*
* \return RIG_OK if the operation has been sucessful, otherwise
* a negative value if an error occured (in which case, cause is
* set appropriately).
*
* \sa amp_init(), amp_close()
*/
int HAMLIB_API amp_cleanup(AMP *amp)
{
2019-11-30 16:19:08 +00:00
amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
if (!amp || !amp->caps)
{
return -RIG_EINVAL;
}
/*
* check if they forgot to close the amp
*/
if (amp->state.comm_state)
{
amp_close(amp);
}
/*
* basically free up the priv struct
*/
if (amp->caps->amp_cleanup)
{
amp->caps->amp_cleanup(amp);
}
free(amp);
return RIG_OK;
2019-06-12 20:52:35 +00:00
}
/**
* \brief reset the amplifier
* \param amp The amp handle
* \param reset The reset operation to perform
*
* Resets the amplifier.
*
* \return RIG_OK if the operation has been sucessful, otherwise
* a negative value if an error occured (in which case, cause is
* set appropriately).
*
*/
int HAMLIB_API amp_reset(AMP *amp, amp_reset_t reset)
{
2019-11-30 16:19:08 +00:00
const struct amp_caps *caps;
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (CHECK_AMP_ARG(amp))
{
return -RIG_EINVAL;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
caps = amp->caps;
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (caps->reset == NULL)
{
return -RIG_ENAVAIL;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
return caps->reset(amp, reset);
2019-06-12 20:52:35 +00:00
}
int HAMLIB_API amp_get_freq(AMP *amp, freq_t *freq)
{
2019-11-30 16:19:08 +00:00
const struct amp_caps *caps;
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (CHECK_AMP_ARG(amp))
{
return -RIG_EINVAL;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
caps = amp->caps;
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (caps->get_freq == NULL)
{
return -RIG_ENAVAIL;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
return caps->get_freq(amp, freq);
2019-06-12 20:52:35 +00:00
}
int HAMLIB_API amp_set_freq(AMP *amp, freq_t freq)
{
2019-11-30 16:19:08 +00:00
const struct amp_caps *caps;
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (CHECK_AMP_ARG(amp))
{
return -RIG_EINVAL;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
caps = amp->caps;
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (caps->set_freq == NULL)
{
return -RIG_ENAVAIL;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
return caps->set_freq(amp, freq);
2019-06-12 20:52:35 +00:00
}
/**
* \brief get general information from the amplifier
* \param amp The amp handle
*
* Retrieves some general information from the amplifier.
* This can include firmware revision, exact model name, or just nothing.
*
* \return a pointer to static memory containing the ASCIIZ string
* if the operation has been sucessful, otherwise NULL if an error occured
* or get_info not part of capabilities.
*/
const char *HAMLIB_API amp_get_info(AMP *amp)
{
2019-11-30 16:19:08 +00:00
amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (CHECK_AMP_ARG(amp))
{
return NULL;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (amp->caps->get_info == NULL)
{
return NULL;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
return amp->caps->get_info(amp);
2019-06-12 20:52:35 +00:00
}
int HAMLIB_API amp_get_level(AMP *amp, setting_t level, value_t *val)
{
2019-11-30 16:19:08 +00:00
amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (CHECK_AMP_ARG(amp))
{
return -RIG_EINVAL;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (amp->caps->get_level == NULL)
{
return -RIG_ENIMPL;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
return amp->caps->get_level(amp, level, val);
2019-06-12 20:52:35 +00:00
}
int HAMLIB_API amp_get_ext_level(AMP *amp, token_t level, value_t *val)
{
2019-11-30 16:19:08 +00:00
amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (CHECK_AMP_ARG(amp))
{
return -RIG_EINVAL;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (amp->caps->get_ext_level == NULL)
{
return -RIG_ENIMPL;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
return amp->caps->get_ext_level(amp, level, val);
2019-06-12 20:52:35 +00:00
}
/**
* \brief turn on/off the amplifier or standby/operate toggle
* \param amp The amp handle
* \param status The status to set to
*
* turns on/off the amplifier.
* See #RIG_POWER_ON, #RIG_POWER_OFF and #RIG_POWER_STANDBY #RIG_POWER_OPERATE defines
* for the \a status.
*
* \return RIG_OK if the operation has been sucessful, ortherwise
* a negative value if an error occured (in which case, cause is
* set appropriately).
*
* \sa amp_get_powerstat()
*/
int HAMLIB_API amp_set_powerstat(AMP *amp, powerstat_t status)
{
2019-11-30 16:19:08 +00:00
amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (CHECK_AMP_ARG(amp))
{
return -RIG_EINVAL;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (amp->caps->set_powerstat == NULL)
{
return -RIG_ENIMPL;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
return amp->caps->set_powerstat(amp, status);
2019-06-12 20:52:35 +00:00
}
int HAMLIB_API amp_get_powerstat(AMP *amp, powerstat_t *status)
{
2019-11-30 16:19:08 +00:00
amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (CHECK_AMP_ARG(amp))
{
return -RIG_EINVAL;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
if (amp->caps->get_powerstat == NULL)
{
return -RIG_ENIMPL;
}
2019-06-12 20:52:35 +00:00
2019-11-30 16:19:08 +00:00
return amp->caps->get_powerstat(amp, status);
2019-06-12 20:52:35 +00:00
}
/*! @} */