Add Gemini DX-1200 HF-1K amplifier

pull/1091/head
Mike Black W9MDB 2022-07-10 17:05:44 -05:00
rodzic 7b49921468
commit 363219e60a
13 zmienionych plików z 667 dodań i 3 usunięć

1
NEWS
Wyświetl plik

@ -16,6 +16,7 @@ Version 4.6
Version 4.5
* 2022-05-XX
* Add Gemini DX-1200 HF-1K Amplifiers
* Kenwood rigs should now support AI command packets
* Add FT-990UNI for older 990 ROMs 1.2 and earlier
* Add FT-650

Wyświetl plik

@ -0,0 +1,12 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := gemini
LOCAL_MODULE := gemini
LOCAL_CFLAGS :=
LOCAL_C_INCLUDES := android include src
LOCAL_LDLIBS := -lhamlib
include $(BUILD_STATIC_LIBRARY)

Wyświetl plik

@ -0,0 +1,8 @@
SRC = gemini.c
GEMINISRC = dx1200.c gemini.h
noinst_LTLIBRARIES = libhamlib-gemini.la
libhamlib_gemini_la_SOURCES = $(SRC) $(GEMINISRC)
EXTRA_DIST = README.gemini Android.mk

Wyświetl plik

@ -0,0 +1,4 @@
Back end for Gemini DX1200 and HF-1K
https://github.com/Hamlib/Hamlib/files/9063647/NetworkConnectionProtocol_3.pdf
Initial prototype 20220710

Wyświetl plik

@ -0,0 +1,143 @@
/*
* Hamlib backend library for the Gemini DX1200 and HF-1K command set.
*
* dx1200.c - (C) Michael Black W9MDB 2022
*
* This shared library provides an API for communicating
* to Gemini amplifiers.
*
* 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 <hamlib/config.h>
#include <stdio.h>
#include <stdlib.h> /* Standard library definitions */
#include <string.h> /* String function definitions */
#include "register.h"
#include "gemini.h"
struct gemini_priv_data *gemini_priv;
/*
* API local implementation
*
*/
/*
* Private helper function prototypes
*/
//static int gemini_send_priv_cmd(AMP *amp, const char *cmd);
//static int gemini_flush_buffer(AMP *amp);
/* *************************************
*
* Separate model capabilities
*
* *************************************
*/
/*
* Gemini
*/
const struct amp_caps gemini_amp_caps =
{
AMP_MODEL(AMP_MODEL_GEMINI_DX1200),
.model_name = "DX1200/HF-1K",
.mfg_name = "Gemini",
.version = "20220710.0",
.copyright = "LGPL",
.status = RIG_STATUS_ALPHA,
.amp_type = AMP_TYPE_OTHER,
.port_type = RIG_PORT_NETWORK,
.write_delay = 0,
.post_write_delay = 0,
.timeout = 2000,
.retry = 2,
.has_get_level = AMP_LEVEL_SWR | AMP_LEVEL_PWR_FWD | AMP_LEVEL_PWR_PEAK | AMP_LEVEL_FAULT | AMP_LEVEL_PWR,
.has_set_level = AMP_LEVEL_PWR,
.amp_open = NULL,
.amp_init = gemini_init,
.amp_close = gemini_close,
.reset = gemini_reset,
.get_info = gemini_get_info,
.get_powerstat = gemini_get_powerstat,
.set_powerstat = gemini_set_powerstat,
.get_freq = gemini_get_freq,
.set_freq = gemini_set_freq,
.get_level = gemini_get_level,
.set_level = gemini_set_level,
};
/* ************************************
*
* API functions
*
* ************************************
*/
/*
*
*/
#if 0 // not implemented yet
/*
* Send command string to amplifier
*/
static int gemini_send_priv_cmd(AMP *amp, const char *cmdstr)
{
struct amp_state *rs;
int err;
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
if (!amp)
{
return -RIG_EINVAL;
}
rs = &amp->state;
err = write_block(&rs->ampport, cmdstr, strlen(cmdstr));
if (err != RIG_OK)
{
return err;
}
return RIG_OK;
}
#endif
/*
* Initialize backend
*/
DECLARE_INITAMP_BACKEND(gemini)
{
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
amp_register(&gemini_amp_caps);
return RIG_OK;
}

Wyświetl plik

@ -0,0 +1,397 @@
/*
* 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"
struct fault_list
{
int code;
char *errmsg;
};
/*
* Initialize data structures
*/
int gemini_init(AMP *amp)
{
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
if (!amp)
{
return -RIG_EINVAL;
}
amp->state.priv = (struct gemini_priv_data *)
malloc(sizeof(struct gemini_priv_data));
if (!amp->state.priv)
{
return -RIG_ENOMEM;
}
amp->state.ampport.type.rig = RIG_PORT_NETWORK;
return RIG_OK;
}
int gemini_close(AMP *amp)
{
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
if (amp->state.priv) { free(amp->state.priv); }
amp->state.priv = NULL;
return RIG_OK;
}
int gemini_flushbuffer(AMP *amp)
{
struct amp_state *rs;
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
rs = &amp->state;
return rig_flush(&rs->ampport);
}
int gemini_transaction(AMP *amp, const char *cmd, char *response,
int response_len)
{
struct amp_state *rs;
int err;
int len = 0;
rig_debug(RIG_DEBUG_VERBOSE, "%s called, cmd=%s\n", __func__, cmd);
if (!amp) { return -RIG_EINVAL; }
gemini_flushbuffer(amp);
rs = &amp->state;
// Now send our command
err = write_block(&rs->ampport, (unsigned char *) cmd, strlen(cmd));
if (err != RIG_OK) { return err; }
if (response) // if response expected get it
{
response[0] = 0;
len = read_string(&rs->ampport, (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
*/
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;
char *p;
char responsebuf[GEMINIBUFSZ];
struct gemini_priv_data *priv = amp->state.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 = 0;
n += sscanf(p, "BAND=%lf%s", &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=%s", priv->state);
n += sscanf(p, "PTT=%s", tmp);
priv->ptt = tmp[0] == 'T';
n += sscanf(p, "TRIP=%s", 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 = amp->state.priv;
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
if (!amp) { return -RIG_EINVAL; }
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 = amp->state.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"; }
return RIG_OK;
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", &ampon);
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);
}

Wyświetl plik

@ -0,0 +1,72 @@
/*
* Hamlib backend library for the Gemini amplifier set.
*
* gemini.h - (C) Michael Black W9MDB 2022
*
* This shared library provides an API for communicating
* via serial interface to Gemini amplifiers.
*
*
* 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
*
*/
#ifndef _AMP_GEMINI_H
#define _AMP_GEMINI_H 1
#include <hamlib/amplifier.h>
#include <iofunc.h>
#include <serial.h>
// Is this big enough?
#define GEMINIBUFSZ 1024
extern const struct amp_caps gemini_amp_caps;
/*
* Private data structure
*/
struct gemini_priv_data
{
long band; // Hz
char antenna;
int power_current; // Watts
int power_peak; // Watts
double vswr;
int current; // Amps
int temperature; // Centigrade
char state[5];
int ptt;
char trip[256];
};
int gemini_init(AMP *amp);
int gemini_close(AMP *amp);
int gemini_reset(AMP *amp, amp_reset_t reset);
int gemini_flush_buffer(AMP *amp);
int gemini_transaction(AMP *amp, const char *cmd, char *response,
int response_len);
const char *gemini_get_info(AMP *amp);
int gemini_get_freq(AMP *amp, freq_t *freq);
int gemini_set_freq(AMP *amp, freq_t freq);
int gemini_get_level(AMP *amp, setting_t level, value_t *val);
int gemini_set_level(AMP *amp, setting_t level, value_t val);
int gemini_get_powerstat(AMP *amp, powerstat_t *status);
int gemini_set_powerstat(AMP *amp, powerstat_t status);
#endif /* _AMP_GEMINI_H */

Wyświetl plik

@ -50,7 +50,7 @@ dnl here but will be added later, e.g. "winradio".
RIG_BACKEND_LIST="rigs/adat rigs/alinco rigs/aor rigs/barrett rigs/codan rigs/dorji rigs/drake rigs/dummy rigs/elad rigs/flexradio rigs/icom rigs/icmarine rigs/jrc rigs/kachina rigs/kenwood rigs/kit rigs/lowe rigs/pcr rigs/prm80 rigs/racal rigs/rft rigs/rs rigs/skanti rigs/tapr rigs/tentec rigs/tuner rigs/uniden rigs/winradio rigs/wj rigs/yaesu rigs/gomspace"
ROT_BACKEND_LIST="rotators/amsat rotators/ars rotators/celestron rotators/cnctrk rotators/grbltrk rotators/easycomm rotators/ether6 rotators/fodtrack rotators/gs232a rotators/heathkit rotators/m2 rotators/meade rotators/rotorez rotators/sartek rotators/spid rotators/ts7400 rotators/prosistel rotators/ioptron rotators/satel rotators/radant"
# Amplifiers are all in the amplifiers directory
AMP_BACKEND_LIST="amplifiers/elecraft"
AMP_BACKEND_LIST="amplifiers/elecraft amplifiers/gemini"
dnl See README.release on setting these values
# Values given to -version-info when linking. See libtool documentation.
@ -883,6 +883,7 @@ tests/Makefile
scripts/Makefile
android/Makefile
amplifiers/elecraft/Makefile
amplifiers/gemini/Makefile
simulators/Makefile
hamlib.pc
])

Wyświetl plik

@ -458,6 +458,24 @@ as in
.B set_powerstat
above.
.
.TP
.BR Y ", " set_ant " \(aq" \fIAntenna\fP "\(aq \(aq" \fIOption\fP \(aq
Set
.RI \(aq Antenna \(aq
and
.RI \(aq Option \(aq.
.IP
Number is 1-based antenna# (\(oq1\(cq, \(oq2\(cq, \(oq3\(cq, ...).
.IP
.in +4n
.EX
1 = A/1
2 = B/2
3 = C/3
.EE
.in
.
.
.SH READLINE
.

Wyświetl plik

@ -146,7 +146,8 @@ enum amp_level_e
AMP_LEVEL_PWR_FWD = (1 << 4), /*!< \c Power reading forward. */
AMP_LEVEL_PWR_REFLECTED = (1 << 5), /*!< \c Power reading reverse. */
AMP_LEVEL_PWR_PEAK = (1 << 6), /*!< \c Power reading peak. */
AMP_LEVEL_FAULT = (1 << 7) /*!< \c Fault code. */
AMP_LEVEL_FAULT = (1 << 7), /*!< \c Fault code. */
AMP_LEVEL_PWR = (1 << 8), /*!< \c Power setting. */
};
//! @endcond
@ -242,6 +243,7 @@ struct amp_caps
int (*reset)(AMP *amp, amp_reset_t reset); /*!< Pointer to backend implementation of ::amp_reset(). */
int (*get_level)(AMP *amp, setting_t level, value_t *val); /*!< Pointer to backend implementation of ::amp_get_level(). */
int (*set_level)(AMP *amp, setting_t level, value_t val); /*!< Pointer to backend implementation of ::amp_get_level(). */
int (*get_ext_level)(AMP *amp, token_t level, value_t *val); /*!< Pointer to backend implementation of ::amp_get_ext_level(). */
int (*set_powerstat)(AMP *amp, powerstat_t status); /*!< Pointer to backend implementation of ::amp_set_powerstat(). */
int (*get_powerstat)(AMP *amp, powerstat_t *status); /*!< Pointer to backend implementation of ::amp_get_powerstat(). */

Wyświetl plik

@ -106,6 +106,10 @@
//! @endcond
#define AMP_MODEL_ELECRAFT_KPA1500 AMP_MAKE_MODEL(AMP_ELECRAFT, 1)
//#define AMP_MODEL_ELECRAFT_KPA500 AMP_MAKE_MODEL(AMP_ELECRAFT, 2)
#define AMP_GEMINI 3
#define AMP_BACKEND_GEMINI "gemini"
#define AMP_MODEL_GEMINI_DX1200 AMP_MAKE_MODEL(AMP_GEMINI, 1)
/**
* \brief Convenience type definition for an amplifier model.

Wyświetl plik

@ -65,6 +65,7 @@
DEFINE_INITAMP_BACKEND(dummy);
DEFINE_INITAMP_BACKEND(kpa1500);
DEFINE_INITAMP_BACKEND(gemini);
//! @endcond
/**
@ -87,6 +88,7 @@ static struct
{
{ AMP_DUMMY, AMP_BACKEND_DUMMY, AMP_FUNCNAMA(dummy) },
{ AMP_ELECRAFT, AMP_BACKEND_ELECRAFT, AMP_FUNCNAMA(kpa1500) },
{ AMP_GEMINI, AMP_BACKEND_GEMINI, AMP_FUNCNAMA(gemini) },
{ 0, NULL }, /* end */
};

Wyświetl plik

@ -97,7 +97,7 @@ int rig_set_cache_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width)
break;
default:
rig_debug(RIG_DEBUG_ERR, "%s: unknown vfo=%s\n", __func__, rig_strvfo(vfo));
rig_debug(RIG_DEBUG_WARN, "%s: unknown vfo=%s\n", __func__, rig_strvfo(vfo));
RETURNFUNC(-RIG_EINTERNAL);
}