From 3b45dfa4b845d581dd187c819876db6ccde447d7 Mon Sep 17 00:00:00 2001 From: Mike Black W9MDB Date: Sat, 27 May 2023 11:04:56 -0500 Subject: [PATCH] Add AnyTone D578UVIII https://github.com/Hamlib/Hamlib/issues/1303 --- configure.ac | 3 +- include/hamlib/riglist.h | 8 + rigs/anytone/Android.mk | 12 ++ rigs/anytone/Makefile.am | 6 + rigs/anytone/anytone.c | 405 +++++++++++++++++++++++++++++++++++++++ rigs/anytone/anytone.h | 31 +++ rigs/anytone/d578.c | 92 +++++++++ src/register.c | 6 +- 8 files changed, 560 insertions(+), 3 deletions(-) create mode 100644 rigs/anytone/Android.mk create mode 100644 rigs/anytone/Makefile.am create mode 100644 rigs/anytone/anytone.c create mode 100644 rigs/anytone/anytone.h create mode 100644 rigs/anytone/d578.c diff --git a/configure.ac b/configure.ac index cee1aff02..08ba1fa48 100644 --- a/configure.ac +++ b/configure.ac @@ -49,7 +49,7 @@ dnl added to AC_CONFIG_FILES near the end of this file. See README.developer dnl Beware of duplication should a backend directory include both rig and dnl rotor definitions, e.g. "dummy". Optional backends will not be listed 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 rigs/mds" +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 rigs/mds rigs/anytone" ROT_BACKEND_LIST="rotators/amsat rotators/apex rotators/ars rotators/celestron rotators/cnctrk rotators/grbltrk rotators/easycomm rotators/ether6 rotators/flir rotators/fodtrack rotators/gs232a rotators/heathkit rotators/m2 rotators/meade rotators/rotorez rotators/sartek rotators/saebrtrack rotators/spid rotators/ts7400 rotators/prosistel rotators/ioptron rotators/satel rotators/radant" # Amplifiers are all in the amplifiers directory AMP_BACKEND_LIST="amplifiers/elecraft amplifiers/gemini amplifiers/expert" @@ -912,6 +912,7 @@ rigs/wj/Makefile rigs/yaesu/Makefile rigs/gomspace/Makefile rigs/mds/Makefile +rigs/anytone/Makefile tests/Makefile scripts/Makefile android/Makefile diff --git a/include/hamlib/riglist.h b/include/hamlib/riglist.h index f73e639fc..94c29c9d8 100644 --- a/include/hamlib/riglist.h +++ b/include/hamlib/riglist.h @@ -656,6 +656,14 @@ etc. */ +/* + * AnyTone rigs + */ +#define RIG_ANYTONE 37 +#define RIG_BACKEND_ANYTONE "AnyTone" +#define RIG_MODEL_ATD578UVIII RIG_MAKE_MODEL(RIG_ANYTONE, 1) + + //! @endcond /*! \typedef typedef int rig_model_t diff --git a/rigs/anytone/Android.mk b/rigs/anytone/Android.mk new file mode 100644 index 000000000..8fbe3b54f --- /dev/null +++ b/rigs/anytone/Android.mk @@ -0,0 +1,12 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := anytone.c d578.c +LOCAL_MODULE := anytone + +LOCAL_CFLAGS := +LOCAL_C_INCLUDES := android include src +LOCAL_LDLIBS := $(LOCAL_SHARED_LIBRARIES) -Lobj/local/$(TARGET_ARCH_ABI) + +include $(BUILD_STATIC_LIBRARY) diff --git a/rigs/anytone/Makefile.am b/rigs/anytone/Makefile.am new file mode 100644 index 000000000..5e32ba81a --- /dev/null +++ b/rigs/anytone/Makefile.am @@ -0,0 +1,6 @@ +ANYTONESRC = anytone.c d578.c + +noinst_LTLIBRARIES = libhamlib-anytone.la +libhamlib_anytone_la_SOURCES = $(ANYTONESRC) + +EXTRA_DIST = Android.mk diff --git a/rigs/anytone/anytone.c b/rigs/anytone/anytone.c new file mode 100644 index 000000000..7b95f0a28 --- /dev/null +++ b/rigs/anytone/anytone.c @@ -0,0 +1,405 @@ +// --------------------------------------------------------------------------- +// AnyTone D578 Hamlib Backend +// --------------------------------------------------------------------------- +// +// d578.c +// +// Created by Michael Black W9MDB +// Copyright © 2023 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 + +// --------------------------------------------------------------------------- +// SYSTEM INCLUDES +// --------------------------------------------------------------------------- + +#include +#include +#include +#include + +// --------------------------------------------------------------------------- +// HAMLIB INCLUDES +// --------------------------------------------------------------------------- + +#include +#include "serial.h" +#include "misc.h" +#include "register.h" +#include "riglist.h" + +// --------------------------------------------------------------------------- +// ANYTONE INCLUDES +// --------------------------------------------------------------------------- + +#include "anytone.h" + +DECLARE_INITRIG_BACKEND(anytone) +{ + int retval = RIG_OK; + + rig_register(&anytone_d578_caps); + + return retval; +} + + + +// --------------------------------------------------------------------------- +// proberig_anytone +// --------------------------------------------------------------------------- +DECLARE_PROBERIG_BACKEND(anytone) +{ + int retval = RIG_OK; + + if (!port) + { + return RIG_MODEL_NONE; + } + + if (port->type.rig != RIG_PORT_SERIAL) + { + return RIG_MODEL_NONE; + } + + port->write_delay = port->post_write_delay = 0; + port->parm.serial.stop_bits = 1; + port->retry = 1; + + + retval = serial_open(port); + + if (retval != RIG_OK) + { + retval = RIG_MODEL_NONE; + } + else + { + char acBuf[ ANYTONE_RESPSZ + 1 ]; + int nRead = 0; + + memset(acBuf, 0, ANYTONE_RESPSZ + 1); + +#if 0 + retval = write_block(port, + (unsigned char *)ADAT_CMD_DEF_STRING_GET_ID_CODE, + strlen(ADAT_CMD_DEF_STRING_GET_ID_CODE)); + nRead = read_string(port, (unsigned char *) acBuf, ANYTONE_RESPSZ, + ADAT_EOM, 1, 0, 1); +#endif + close(port->fd); + + if ((retval != RIG_OK || nRead < 0)) + { + retval = RIG_MODEL_NONE; + } + else + { + rig_debug(RIG_DEBUG_VERBOSE, "Received ID = %s.", + acBuf); + + retval = RIG_MODEL_ADT_200A; + } + } + + return retval; +} + +// --------------------------------------------------------------------------- +// anytone_send +// --------------------------------------------------------------------------- +int anytone_send(RIG *rig, + char *cmd, int cmd_len) +{ + int retval = RIG_OK; + struct rig_state *rs = &rig->state; + + ENTERFUNC; + + rig_flush(&rs->rigport); + + retval = write_block(&rs->rigport, (unsigned char *) cmd, + cmd_len); + + RETURNFUNC(retval); +} + +// --------------------------------------------------------------------------- +// anytone_receive +// --------------------------------------------------------------------------- +int anytone_receive(RIG *rig, char *buf, int buf_len, int expected) +{ + int retval = RIG_OK; + struct rig_state *rs = &rig->state; + + ENTERFUNC; + + retval = read_string(&rs->rigport, (unsigned char *) buf, buf_len, + NULL, 0, 0, expected); + + if (retval > 0) + { + retval = RIG_OK; + rig_debug(RIG_DEBUG_VERBOSE, "%s: read %d byte=0x%02x\n", __func__, retval, + buf[0]); + } + + RETURNFUNC(retval); +} + +// --------------------------------------------------------------------------- +// anytone_transaction +// --------------------------------------------------------------------------- +int anytone_transaction(RIG *rig, char *cmd, int cmd_len) +{ + int retval = RIG_OK; + + ENTERFUNC; + + if (rig == NULL) + { + retval = -RIG_EARG; + } + else + { + retval = anytone_send(rig, cmd, cmd_len); + + if (retval == RIG_OK) + { + char buf[16]; + anytone_receive(rig, buf, sizeof(buf), 1); + } + } + + RETURNFUNC(retval); +} + +// --------------------------------------------------------------------------- +// Function anytone_init +// --------------------------------------------------------------------------- +int anytone_init(RIG *rig) +{ + int retval = RIG_OK; + + ENTERFUNC; + // Check Params + + if (rig != NULL) + { + anytone_priv_data_ptr pPriv = NULL; + + // Get new Priv Data + + pPriv = calloc(1, sizeof(anytone_priv_data_t)); + + if (pPriv == NULL) + { + retval = -RIG_ENOMEM; + } + + rig->state.priv = pPriv; + anytone_priv_data_t *p = rig->state.priv; + p->vfo_curr = RIG_VFO_NONE; + } + + RETURNFUNC(retval); +} + +// --------------------------------------------------------------------------- +// Function anytone_cleanup +// --------------------------------------------------------------------------- +int anytone_cleanup(RIG *rig) +{ + int retval = RIG_OK; + + ENTERFUNC; + + if (rig == NULL) + { + retval = -RIG_EARG; + } + else + { + if (rig->state.priv != NULL) + { + free(rig->state.priv); + rig->state.priv = NULL; + } + } + + RETURNFUNC(retval); +} + +// --------------------------------------------------------------------------- +// Function anytone_open +// --------------------------------------------------------------------------- +int anytone_open(RIG *rig) +{ + int retval = RIG_OK; + + ENTERFUNC; + // Check Params + + if (rig == NULL) + { + retval = -RIG_EARG; + } + else + { + // grace period for the radio to be there + + // hl_usleep(500); // do we need this for AnyTone? + + // can we ask for any information? Maybe just toggle A/B? + } + + RETURNFUNC(retval); +} + +// --------------------------------------------------------------------------- +// Function anytone_close +// --------------------------------------------------------------------------- +int anytone_close(RIG *rig) +{ + int retval = RIG_OK; +#if 0 + anytone_priv_data_ptr pPriv = (anytone_priv_data_ptr) rig->state.priv; + + if (pPriv->pcCmd != NULL) { free(pPriv->pcCmd); } + + if (pPriv->pcResult != NULL) { free(pPriv->pcResult); } + +#endif + + ENTERFUNC; +#if 0 + // Now switch to interactive mode + + retval = anytone_transaction(rig, &anytone_cmd_list_close_adat); +#endif + + RETURNFUNC(retval); +} + +// --------------------------------------------------------------------------- +// Function anytone_get_vfo +// --------------------------------------------------------------------------- +int anytone_get_vfo(RIG *rig, vfo_t *vfo) +{ + int retval = RIG_OK; + + ENTERFUNC; + // Check Params + + if (rig == NULL) + { + retval = -RIG_EARG; + } + else + { + anytone_priv_data_ptr pPriv = (anytone_priv_data_ptr) rig->state.priv; + + *vfo = pPriv->vfo_curr; + } + + RETURNFUNC(retval); +} + +// --------------------------------------------------------------------------- +// Function anytone_set_vfo +// --------------------------------------------------------------------------- +int anytone_set_vfo(RIG *rig, vfo_t vfo) +{ + int retval = RIG_OK; + + ENTERFUNC; + // Check Params + + if (rig == NULL) + { + retval = -RIG_EARG; + } + else + { + if (vfo == RIG_VFO_A) + { + char buf1[8] = { 0x41, 0x00, 0x01, 0x00, 0x1a, 0x00, 0x00, 0x06 }; + char buf2[8] = { 0x41, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x06 }; + anytone_transaction(rig, buf1, 8); + hl_usleep(100 * 1000); + anytone_transaction(rig, buf2, 8); + } + else + { + char buf1[8] = { 0x41, 0x00, 0x01, 0x00, 0x1b, 0x00, 0x00, 0x06 }; + char buf2[8] = { 0x41, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x06 }; + anytone_transaction(rig, buf1, 8); + hl_usleep(100 * 1000); + anytone_transaction(rig, buf2, 8); + } + + } + + RETURNFUNC(retval); +} + +// --------------------------------------------------------------------------- +// Function anytone_get_ptt +// --------------------------------------------------------------------------- +int anytone_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt) +{ + int retval = RIG_OK; + + ENTERFUNC; + // Check Params + + if (rig == NULL) + { + retval = -RIG_EARG; + } + else + { + } + + return retval; +} +// --------------------------------------------------------------------------- +// anytone_set_ptt +// --------------------------------------------------------------------------- +int anytone_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt) +{ + int retval = RIG_OK; + + ENTERFUNC; + + if (rig == NULL) + { + retval = -RIG_EARG; + } + else + { + char buf[8] = { 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06 }; + + if (ptt) { buf[1] = 0x01; } + + anytone_transaction(rig, buf, 8); + } + + RETURNFUNC(retval); +} + +// --------------------------------------------------------------------------- +// END OF FILE +// --------------------------------------------------------------------------- diff --git a/rigs/anytone/anytone.h b/rigs/anytone/anytone.h new file mode 100644 index 000000000..bafa6f60c --- /dev/null +++ b/rigs/anytone/anytone.h @@ -0,0 +1,31 @@ +#ifndef _ANYTONE_H +#define _ANYTONE_H 1 + +#include "hamlib/rig.h" + +#define BACKEND_VER "20230527" + +#define ANYTONE_RESPSZ 64 + +extern const struct rig_caps anytone_d578_caps; + +typedef struct _anytone_priv_data +{ + int ptt; + vfo_t vfo_curr; +} anytone_priv_data_t, +* anytone_priv_data_ptr; + + +extern int anytone_init(RIG *rig); +extern int anytone_cleanup(RIG *rig); +extern int anytone_open(RIG *rig); +extern int anytone_close(RIG *rig); + +extern int anytone_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt); +extern int anytone_get_ptt(RIG *rig, vfo_t vfo,ptt_t *ptt); + +extern int anytone_set_vfo(RIG *rig, vfo_t vfo); +extern int anytone_get_vfo(RIG *rig, vfo_t *vfo); + +#endif /* _ANYTONE_H */ diff --git a/rigs/anytone/d578.c b/rigs/anytone/d578.c new file mode 100644 index 000000000..f6d56dd37 --- /dev/null +++ b/rigs/anytone/d578.c @@ -0,0 +1,92 @@ +// --------------------------------------------------------------------------- +// Anytone D578UVIII +// --------------------------------------------------------------------------- +// +// d578.c +// +// Created by Michael Black W9MDB +// Copyright © 2023, 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 "anytone.h" + +#define D578_VFO (RIG_VFO_A|RIG_VFO_B) +#define D578_MODES (RIG_MODE_USB|RIG_MODE_AM) + +const struct rig_caps anytone_d578_caps = +{ + RIG_MODEL(RIG_MODEL_ATD578UVIII), + .model_name = "D578A", + .mfg_name = "AnyTone", + .version = BACKEND_VER ".0", + .copyright = "Michael Black W9MDB: GNU LGPL", + .status = RIG_STATUS_ALPHA, + .rig_type = RIG_TYPE_TRANSCEIVER, + .ptt_type = RIG_PTT_RIG, + .dcd_type = RIG_DCD_NONE, + .port_type = RIG_PORT_SERIAL, + .serial_rate_min = 115200, + .serial_rate_max = 115200, + .serial_data_bits = 8, + .serial_stop_bits = 1, + .serial_parity = RIG_PARITY_NONE, + .serial_handshake = RIG_HANDSHAKE_NONE, + .write_delay = 0, + .post_write_delay = 0, + .timeout = 1000, + .retry = 3, + + .level_gran = {}, + .parm_gran = {}, + .ctcss_list = NULL, + .dcs_list = NULL, + .targetable_vfo = RIG_TARGETABLE_NONE, + .transceive = 0, + + .rx_range_list1 = + { + { MHz(108), MHz(174), D578_MODES, -1, -1, D578_VFO }, + { MHz(144), MHz(148), D578_MODES, -1, -1, D578_VFO }, + { MHz(222), MHz(225), D578_MODES, -1, -1, D578_VFO }, + { MHz(420), MHz(450), D578_MODES, -1, -1, D578_VFO }, + RIG_FRNG_END, + }, + + .tx_range_list1 = + { + { MHz(144), MHz(148), D578_MODES, W(1), W(55), D578_VFO }, + { MHz(222), MHz(225), D578_MODES, W(1), W(40), D578_VFO }, + { MHz(420), MHz(450), D578_MODES, W(1), W(25), D578_VFO }, + RIG_FRNG_END, + }, + + .rig_init = anytone_init, + .rig_cleanup = anytone_cleanup, + .rig_open = anytone_open, + .rig_close = anytone_close, + + .get_vfo = anytone_get_vfo, + .set_vfo = anytone_set_vfo, + + .get_ptt = anytone_get_ptt, + .set_ptt = anytone_set_ptt, + + .hamlib_check_rig_caps = HAMLIB_CHECK_RIG_CAPS +}; + +// --------------------------------------------------------------------------- +// END OF FILE +// --------------------------------------------------------------------------- diff --git a/src/register.c b/src/register.c index 7b02f3528..70bbaed7c 100644 --- a/src/register.c +++ b/src/register.c @@ -89,6 +89,7 @@ DEFINE_INITRIG_BACKEND(elad); DEFINE_INITRIG_BACKEND(codan); DEFINE_INITRIG_BACKEND(gomspace); DEFINE_INITRIG_BACKEND(mds); +DEFINE_INITRIG_BACKEND(anytone); //! @endcond #ifdef HAVE_WINRADIO @@ -148,6 +149,7 @@ static struct { RIG_CODAN, RIG_BACKEND_CODAN, RIG_FUNCNAMA(codan) }, { RIG_GOMSPACE, RIG_BACKEND_GOMSPACE, RIG_FUNCNAM(gomspace) }, { RIG_MDS, RIG_BACKEND_MDS, RIG_FUNCNAMA(mds) }, + { RIG_ANYTONE, RIG_BACKEND_ANYTONE, RIG_FUNCNAMA(anytone) }, { 0, NULL }, /* end */ }; @@ -199,8 +201,8 @@ int HAMLIB_API rig_register(const struct rig_caps *caps) return -RIG_EINVAL; } -#if 0 - rig_debug(RIG_DEBUG_VERBOSE, +#if 1 + rig_debug(RIG_DEBUG_ERR, "%s: rig_register (%u)\n", __func__, caps->rig_model);