kopia lustrzana https://github.com/Hamlib/Hamlib
397 wiersze
9.1 KiB
C
397 wiersze
9.1 KiB
C
/*
|
|
* Hamlib Gemini amplifier backend - low level communication routines
|
|
* Copyright (c) 2019 by Michael Black W9MDB
|
|
*
|
|
*
|
|
* 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
|
|
*
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "misc.h"
|
|
#include "gemini.h"
|
|
|
|
#if 0
|
|
struct fault_list
|
|
{
|
|
int code;
|
|
char *errmsg;
|
|
};
|
|
#endif
|
|
|
|
/*
|
|
* Initialize data structures
|
|
*/
|
|
|
|
int gemini_init(AMP *amp)
|
|
{
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
|
|
|
if (!amp)
|
|
{
|
|
return -RIG_EINVAL;
|
|
}
|
|
|
|
AMPSTATE(amp)->priv = (struct gemini_priv_data *)
|
|
calloc(1, sizeof(struct gemini_priv_data));
|
|
|
|
if (!AMPSTATE(amp)->priv)
|
|
{
|
|
return -RIG_ENOMEM;
|
|
}
|
|
|
|
AMPPORT(amp)->type.rig = RIG_PORT_NETWORK;
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
int gemini_close(AMP *amp)
|
|
{
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
|
|
|
if (AMPSTATE(amp)->priv) { free(AMPSTATE(amp)->priv); }
|
|
|
|
AMPSTATE(amp)->priv = NULL;
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
int gemini_flushbuffer(AMP *amp)
|
|
{
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
|
|
|
return rig_flush(AMPPORT(amp));
|
|
}
|
|
|
|
int gemini_transaction(AMP *amp, const char *cmd, char *response,
|
|
int response_len)
|
|
{
|
|
|
|
hamlib_port_t *ampp = AMPPORT(amp);
|
|
int err;
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called, cmd=%s\n", __func__, cmd);
|
|
|
|
if (!amp) { return -RIG_EINVAL; }
|
|
|
|
gemini_flushbuffer(amp);
|
|
|
|
// Now send our command
|
|
err = write_block(ampp, (unsigned char *) cmd, strlen(cmd));
|
|
|
|
if (err != RIG_OK) { return err; }
|
|
|
|
if (response) // if response expected get it
|
|
{
|
|
response[0] = 0;
|
|
int len = read_string(ampp, (unsigned char *) response, response_len,
|
|
"\n", 1, 0, 1);
|
|
|
|
if (len < 0)
|
|
{
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called, error=%s\n", __func__,
|
|
rigerror(len));
|
|
return len;
|
|
}
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called, response='%s'\n", __func__,
|
|
response);
|
|
}
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
/*
|
|
* Get Info
|
|
* returns the model name string
|
|
*/
|
|
// cppcheck-suppress constParameterPointer
|
|
const char *gemini_get_info(AMP *amp)
|
|
{
|
|
const struct amp_caps *rc;
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
|
|
|
if (!amp) { return (const char *) - RIG_EINVAL; }
|
|
|
|
rc = amp->caps;
|
|
|
|
return rc->model_name;
|
|
}
|
|
|
|
int gemini_status_parse(AMP *amp)
|
|
{
|
|
int retval, n = 0;
|
|
char *p;
|
|
char responsebuf[GEMINIBUFSZ];
|
|
struct gemini_priv_data *priv = AMPSTATE(amp)->priv;
|
|
|
|
retval = gemini_transaction(amp, "S\n", responsebuf, sizeof(responsebuf));
|
|
|
|
if (retval != RIG_OK)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s: error sending command 'S'\n", __func__);
|
|
}
|
|
|
|
p = strtok(responsebuf, ",\n");
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s: responsebuf=%s\n", __func__, responsebuf);
|
|
|
|
while (p)
|
|
{
|
|
char tmp[8];
|
|
double freq;
|
|
n += sscanf(p, "BAND=%lf%7s", &freq, tmp);
|
|
|
|
if (tmp[0] == 'K') { priv->band = freq * 1000; }
|
|
|
|
if (tmp[0] == 'M') { priv->band = freq * 1000000; }
|
|
|
|
n += sscanf(p, "ANTENNA=%c", &priv->antenna);
|
|
n += sscanf(p, "POWER=%dW%d", &priv->power_current, &priv->power_peak);
|
|
n += sscanf(p, "VSWR=%lf", &priv->vswr);
|
|
n += sscanf(p, "CURRENT=%d", &priv->current);
|
|
n += sscanf(p, "TEMPERATURE=%d", &priv->temperature);
|
|
n += sscanf(p, "STATE=%7s", priv->state);
|
|
n += sscanf(p, "PTT=%7s", tmp);
|
|
priv->ptt = tmp[0] == 'T';
|
|
n += sscanf(p, "TRIP=%7s", priv->trip);
|
|
|
|
if (n == 0)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s: unknown status item=%s\n", __func__, p);
|
|
}
|
|
}
|
|
|
|
if (n == 0) { return -RIG_EPROTO; }
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
int gemini_get_freq(AMP *amp, freq_t *freq)
|
|
{
|
|
int retval;
|
|
struct gemini_priv_data *priv;
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
|
|
|
if (!amp) { return -RIG_EINVAL; }
|
|
|
|
priv = AMPSTATE(amp)->priv;
|
|
|
|
retval = gemini_status_parse(amp);
|
|
|
|
if (retval != RIG_OK) { return retval; }
|
|
|
|
*freq = priv->band;
|
|
return RIG_OK;
|
|
}
|
|
|
|
int gemini_set_freq(AMP *amp, freq_t freq)
|
|
{
|
|
int retval;
|
|
char *cmd;
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
|
|
|
if (freq < 1.0) { cmd = "B472KHZ\n"; }
|
|
else if (freq < 2.0) { cmd = "B1.8MHZ\n"; }
|
|
else if (freq < 4.0) { cmd = "B3.5MHZ\n"; }
|
|
else if (freq < 6.0) { cmd = "B50MHZ\n"; }
|
|
else if (freq < 9.0) { cmd = "B70MHZ\n"; }
|
|
else if (freq < 12.0) { cmd = "B10MHZ\n"; }
|
|
else if (freq < 16.0) { cmd = "B14MHZ\n"; }
|
|
else if (freq < 19.0) { cmd = "B18MHZ\n"; }
|
|
else if (freq < 22.0) { cmd = "B21MHZ\n"; }
|
|
else if (freq < 26.0) { cmd = "B24MHZ\n"; }
|
|
else { cmd = "B50MHZ\n"; }
|
|
|
|
retval = gemini_transaction(amp, cmd, NULL, 0);
|
|
|
|
if (retval != RIG_OK) { return retval; }
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
int gemini_get_level(AMP *amp, setting_t level, value_t *val)
|
|
{
|
|
int retval;
|
|
struct gemini_priv_data *priv = AMPSTATE(amp)->priv;
|
|
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
|
|
|
retval = gemini_status_parse(amp);
|
|
|
|
if (retval != RIG_OK) { return retval; }
|
|
|
|
switch (level)
|
|
{
|
|
case AMP_LEVEL_SWR:
|
|
val->f = priv->vswr;
|
|
return RIG_OK;
|
|
|
|
case AMP_LEVEL_PWR_FWD:
|
|
val->i = priv->power_peak;
|
|
return RIG_OK;
|
|
|
|
case AMP_LEVEL_PWR_PEAK:
|
|
val->i = priv->power_peak;
|
|
return RIG_OK;
|
|
|
|
case AMP_LEVEL_FAULT:
|
|
val->s = priv->trip;
|
|
return RIG_OK;
|
|
|
|
default:
|
|
rig_debug(RIG_DEBUG_ERR, "%s unknown level=%s\n", __func__,
|
|
rig_strlevel(level));
|
|
|
|
}
|
|
|
|
return -RIG_EINVAL;
|
|
}
|
|
|
|
int gemini_set_level(AMP *amp, setting_t level, value_t val)
|
|
{
|
|
char *cmd = "?";
|
|
int retval;
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
|
|
|
switch (level)
|
|
{
|
|
case AMP_LEVEL_PWR: // 0-.33 = low, .34-.67 = medium, .68-1.0 = high
|
|
cmd = "PH\n";
|
|
|
|
if (val.f < .33) { cmd = "PL\n"; }
|
|
|
|
if (val.f < .67) { cmd = "PM\n"; }
|
|
|
|
break;
|
|
}
|
|
|
|
retval = gemini_transaction(amp, cmd, NULL, 0);
|
|
|
|
if (retval == RIG_OK) { return retval; }
|
|
|
|
rig_debug(RIG_DEBUG_ERR, "%s: Unknown level=%s\n", __func__,
|
|
rig_strlevel(level));
|
|
return -RIG_EINVAL;
|
|
|
|
}
|
|
|
|
int gemini_get_powerstat(AMP *amp, powerstat_t *status)
|
|
{
|
|
char responsebuf[GEMINIBUFSZ];
|
|
int retval;
|
|
int ampon;
|
|
int nargs;
|
|
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
|
|
|
*status = RIG_POWER_UNKNOWN;
|
|
|
|
if (!amp) { return -RIG_EINVAL; }
|
|
|
|
retval = gemini_transaction(amp, "R\n", responsebuf, sizeof(responsebuf));
|
|
|
|
if (retval != RIG_OK) { return retval; }
|
|
|
|
nargs = sscanf(responsebuf, "%d", &on);
|
|
|
|
if (nargs != 1)
|
|
{
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s Error: ^ON response='%s'\n", __func__,
|
|
responsebuf);
|
|
return -RIG_EPROTO;
|
|
}
|
|
|
|
switch (ampon)
|
|
{
|
|
case 0: *status = RIG_POWER_STANDBY; return RIG_OK;
|
|
|
|
case 1: *status = RIG_POWER_ON; break;
|
|
|
|
default:
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s Error: 'R' unknown response='%s'\n", __func__,
|
|
responsebuf);
|
|
return -RIG_EPROTO;
|
|
}
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
int gemini_set_powerstat(AMP *amp, powerstat_t status)
|
|
{
|
|
int retval;
|
|
char *cmd = NULL;
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
|
|
|
if (!amp) { return -RIG_EINVAL; }
|
|
|
|
switch (status)
|
|
{
|
|
case RIG_POWER_UNKNOWN: break;
|
|
|
|
case RIG_POWER_OFF: cmd = "R0\n"; break;
|
|
|
|
case RIG_POWER_ON: cmd = "LP1\n"; break;
|
|
|
|
case RIG_POWER_OPERATE: cmd = "R1\n"; break;
|
|
|
|
case RIG_POWER_STANDBY: cmd = "R0\n"; break;
|
|
|
|
|
|
default:
|
|
rig_debug(RIG_DEBUG_ERR, "%s invalid status=%d\n", __func__, status);
|
|
|
|
}
|
|
|
|
retval = gemini_transaction(amp, cmd, NULL, 0);
|
|
|
|
if (retval != RIG_OK) { return retval; }
|
|
|
|
return RIG_OK;
|
|
}
|
|
|
|
int gemini_reset(AMP *amp, amp_reset_t reset)
|
|
{
|
|
int retval;
|
|
|
|
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
|
|
|
|
retval = gemini_transaction(amp, "T\n", NULL, 0);
|
|
|
|
if (retval != RIG_OK)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s: error setting RIG_POWER_STANDBY '%s'\n", __func__,
|
|
strerror(retval));
|
|
}
|
|
|
|
// toggling from standby to operate perhaps does a reset
|
|
retval = gemini_set_powerstat(amp, RIG_POWER_STANDBY);
|
|
|
|
if (retval != RIG_OK)
|
|
{
|
|
rig_debug(RIG_DEBUG_ERR, "%s: error setting RIG_POWER_STANDBY '%s'\n", __func__,
|
|
strerror(retval));
|
|
}
|
|
|
|
return gemini_set_powerstat(amp, RIG_POWER_OPERATE);
|
|
}
|