/* * 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 #include #include #include #include #include #include #include #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 { AMP *amp; struct opened_amp_l *next; }; 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) { 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; } static int remove_opened_amp(AMP *amp) { struct opened_amp_l *p, *q; q = NULL; for (p = opened_amp_list; p; p = p->next) { 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; } return -RIG_EINVAL; /* Not found in list ! */ } /** * \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) { struct opened_amp_l *p; amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); for (p = opened_amp_list; p; p = p->next) { if ((*cfunc)(p->amp, data) == 0) { return RIG_OK; } } return RIG_OK; } /** * \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) { AMP *amp; const struct amp_caps *caps; struct amp_state *rs; int retcode; 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 = &->state; rs->comm_state = 0; rs->ampport.type.rig = caps->port_type; /* default from caps */ 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; case RIG_PORT_NETWORK: case RIG_PORT_UDP_NETWORK: strncpy(rs->ampport.pathname, "127.0.0.1:4534", FILPATHLEN - 1); break; default: strncpy(rs->ampport.pathname, "", FILPATHLEN - 1); } rs->ampport.fd = -1; /* * 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. */ if (caps->amp_init != NULL) { retcode = caps->amp_init(amp); if (retcode != RIG_OK) { amp_debug(RIG_DEBUG_VERBOSE, "%s: backend_init failed!\n", __func__); /* cleanup and exit */ free(amp); return NULL; } } return amp; } /** * \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) { const struct amp_caps *caps; struct amp_state *rs; int status; amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); if (!amp || !amp->caps) { return -RIG_EINVAL; } caps = amp->caps; rs = &->state; if (rs->comm_state) { return -RIG_EINVAL; } rs->ampport.fd = -1; switch (rs->ampport.type.rig) { case RIG_PORT_SERIAL: status = serial_open(&rs->ampport); if (status != 0) { return status; } break; case RIG_PORT_PARALLEL: status = par_open(&rs->ampport); if (status < 0) { return status; } break; case RIG_PORT_DEVICE: status = open(rs->ampport.pathname, O_RDWR, 0); if (status < 0) { return -RIG_EIO; } rs->ampport.fd = status; break; case RIG_PORT_USB: status = usb_port_open(&rs->ampport); if (status < 0) { return status; } break; case RIG_PORT_NONE: case RIG_PORT_RPC: break; /* ez :) */ case RIG_PORT_NETWORK: case RIG_PORT_UDP_NETWORK: /* FIXME: default port */ status = network_open(&rs->ampport, 4533); if (status < 0) { return status; } break; default: return -RIG_EINVAL; } add_opened_amp(amp); rs->comm_state = 1; /* * Maybe the backend has something to initialize * In case of failure, just close down and report error code. */ if (caps->amp_open != NULL) { status = caps->amp_open(amp); if (status != RIG_OK) { return status; } } return RIG_OK; } /** * \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) { const struct amp_caps *caps; struct amp_state *rs; amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); if (!amp || !amp->caps) { return -RIG_EINVAL; } caps = amp->caps; rs = &->state; if (!rs->comm_state) { return -RIG_EINVAL; } /* * Let the backend say 73s to the amp. * and ignore the return code. */ if (caps->amp_close) { caps->amp_close(amp); } 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; } remove_opened_amp(amp); rs->comm_state = 0; return RIG_OK; } /** * \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) { 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; } /** * \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) { const struct amp_caps *caps; amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); if (CHECK_AMP_ARG(amp)) { return -RIG_EINVAL; } caps = amp->caps; if (caps->reset == NULL) { return -RIG_ENAVAIL; } return caps->reset(amp, reset); } int HAMLIB_API amp_get_freq(AMP *amp, freq_t *freq) { const struct amp_caps *caps; amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); if (CHECK_AMP_ARG(amp)) { return -RIG_EINVAL; } caps = amp->caps; if (caps->get_freq == NULL) { return -RIG_ENAVAIL; } return caps->get_freq(amp, freq); } int HAMLIB_API amp_set_freq(AMP *amp, freq_t freq) { const struct amp_caps *caps; amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); if (CHECK_AMP_ARG(amp)) { return -RIG_EINVAL; } caps = amp->caps; if (caps->set_freq == NULL) { return -RIG_ENAVAIL; } return caps->set_freq(amp, freq); } /** * \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) { amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); if (CHECK_AMP_ARG(amp)) { return NULL; } if (amp->caps->get_info == NULL) { return NULL; } return amp->caps->get_info(amp); } int HAMLIB_API amp_get_level(AMP *amp, setting_t level, value_t *val) { amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); if (CHECK_AMP_ARG(amp)) { return -RIG_EINVAL; } if (amp->caps->get_level == NULL) { return -RIG_ENIMPL; } return amp->caps->get_level(amp, level, val); } int HAMLIB_API amp_get_ext_level(AMP *amp, token_t level, value_t *val) { amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); if (CHECK_AMP_ARG(amp)) { return -RIG_EINVAL; } if (amp->caps->get_ext_level == NULL) { return -RIG_ENIMPL; } return amp->caps->get_ext_level(amp, level, val); } /** * \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) { amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); if (CHECK_AMP_ARG(amp)) { return -RIG_EINVAL; } if (amp->caps->set_powerstat == NULL) { return -RIG_ENIMPL; } return amp->caps->set_powerstat(amp, status); } int HAMLIB_API amp_get_powerstat(AMP *amp, powerstat_t *status) { amp_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__); if (CHECK_AMP_ARG(amp)) { return -RIG_EINVAL; } if (amp->caps->get_powerstat == NULL) { return -RIG_ENIMPL; } return amp->caps->get_powerstat(amp, status); } /*! @} */