diff --git a/.gitignore b/.gitignore index 12c8f00da..0bce46adf 100644 --- a/.gitignore +++ b/.gitignore @@ -63,3 +63,4 @@ src/hamlibdatetime.h build/ libs/ obj/ +.project diff --git a/configure.ac b/configure.ac index ef2ba34e1..6ea8a04fa 100644 --- a/configure.ac +++ b/configure.ac @@ -47,7 +47,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" +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/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" @@ -80,6 +80,7 @@ AM_CPPFLAGS="${AM_CPPFLAGS} -I\$(top_srcdir)/include -I\$(top_srcdir)/src -I\$(t dnl Checks for programs. AC_PROG_CC +AC_PROG_CC_STDC AC_PROG_CXX AC_PROG_CPP AC_PROG_AWK @@ -868,6 +869,7 @@ rigs/uniden/Makefile rigs/winradio/Makefile rigs/wj/Makefile rigs/yaesu/Makefile +rigs/gomspace/Makefile tests/Makefile scripts/Makefile android/Makefile diff --git a/include/hamlib/riglist.h b/include/hamlib/riglist.h index 301e5324f..c8a409936 100644 --- a/include/hamlib/riglist.h +++ b/include/hamlib/riglist.h @@ -643,6 +643,13 @@ #define RIG_BACKEND_CODAN "codan" #define RIG_MODEL_CODAN_ENVOY RIG_MAKE_MODEL(RIG_CODAN, 1) #define RIG_MODEL_CODAN_NGT RIG_MAKE_MODEL(RIG_CODAN, 2) + +/* + * Gomspace + */ +#define RIG_GOMSPACE 34 +#define RIG_BACKEND_GOMSPACE "gomspace" +#define RIG_MODEL_GS100 RIG_MAKE_MODEL(RIG_GOMSPACE, 1) //! @endcond /* diff --git a/rigs/gomspace/Makefile.am b/rigs/gomspace/Makefile.am new file mode 100644 index 000000000..6d56c6d30 --- /dev/null +++ b/rigs/gomspace/Makefile.am @@ -0,0 +1,6 @@ +GOMSPACESRC = gs100.c gs100.h + +noinst_LTLIBRARIES = libhamlib-gomspace.la +libhamlib_gomspace_la_SOURCES = $(GOMSPACESRC) + +EXTRA_DIST = Android.mk diff --git a/rigs/gomspace/gs100.c b/rigs/gomspace/gs100.c new file mode 100644 index 000000000..aea918016 --- /dev/null +++ b/rigs/gomspace/gs100.c @@ -0,0 +1,548 @@ +/* + * GomSpace backend and the GS100 radio control module + * + * Created in 2022 by Richard Linhart OK1CTR OK1CTR@gmail.com + * and used during VZLUSAT-2 satellite mission. + * + * 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 + * + */ + +/* Includes ------------------------------------------------------------------*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "hamlib/rig.h" +#include "serial.h" +#include "parallel.h" +#include "cm108.h" +#include "gpio.h" +#include "misc.h" +#include "tones.h" +#include "idx_builtin.h" +#include "register.h" + +#include "gs100.h" + +/* Private Defines -----------------------------------------------------------*/ + +// If defined, commands are software simulated only +#undef _LOCAL_SIMULATION_ + +// If true, configuration table switching is minimized +#define PARAM_MEM_MINIMAL 1 + +// Buffer size for serial transfers +#define BUFSZ 256 +// Last character on each line received from RIG +#define GOM_STOPSET "\n" +// Exact character sequence on the RIG's command prompt +#define GOM_PROMPT "\x1B[1;32mnanocom-ax\x1B[1;30m # \x1B[0m\x1B[0m" +// Maximum number of lines parsed from GS100 response +#define GOM_MAXLINES 20 + +// RIG's parametric table number for receive +#define GOM_CONFIG_TAB_RX 1 +// RIG's parametric table number for transmit +#define GOM_CONFIG_TAB_TX 5 + +/* Private Typedefs ----------------------------------------------------------*/ + +/** + * GS100 rig private data structure + */ +struct gs100_priv_data +{ + freq_t freq_rx; ///< currently just for backup and TRX emulation + freq_t freq_tx; ///< currently just for backup and TRX emulation + int param_mem; ///< last value of configuration table selection +}; + +/* Imported Functions --------------------------------------------------------*/ + +struct ext_list *alloc_init_ext(const struct confparams *cfp); +struct ext_list *find_ext(struct ext_list *elp, token_t token); + +/* Private function prototypes -----------------------------------------------*/ + +/** + * Set variable in the GS100 configuration table + */ +static int gomx_set(RIG *rig, int table, char *varname, char *varvalue); + +/** + * Get variable from the GS100 configuration table + */ +static int gomx_get(RIG *rig, int table, char *varname, char *varvalue); + +/** + * Sends a message to the GS100 and parses response lines + */ +static int gomx_transaction(RIG *rig, char *message, char *response); + +/* Functions -----------------------------------------------------------------*/ + +/* GS100 transceiver control init */ +static int gs100_init(RIG *rig) +{ + struct gs100_priv_data *priv; + + ENTERFUNC; + + if (!rig || !rig->caps) + { + RETURNFUNC(-RIG_EINVAL); + } + + priv = (struct gs100_priv_data *)malloc(sizeof(struct gs100_priv_data)); + if (!priv) + { + RETURNFUNC(-RIG_ENOMEM); + } + + rig->state.priv = (void *)priv; + +#ifdef _LOCAL_SIMULATION_ + rig->state.rigport.type.rig = RIG_PORT_NONE; // just simulation + priv->freq_rx = rig->caps->rx_range_list1->startf; + priv->freq_tx = rig->caps->tx_range_list1->startf; +#endif + + priv->param_mem = -1; // means undefined last selection + + RETURNFUNC(RIG_OK); +} + + +/* GS100 transceiver control deinit */ +static int gs100_cleanup(RIG *rig) +{ + struct gs100_priv_data *priv = (struct gs100_priv_data *)rig->state.priv; + + ENTERFUNC; + + if (rig->state.priv) + { + free(rig->state.priv); + } + + rig->state.priv = NULL; + + RETURNFUNC(RIG_OK); +} + + +/* GS100 transceiver open */ +static int gs100_open(RIG *rig) +{ + ENTERFUNC; + + if (rig->caps->rig_model == RIG_MODEL_GS100) + { + rig_debug(RIG_DEBUG_VERBOSE, "%s: OPENING'\n", __func__); + } + + RETURNFUNC(RIG_OK); +} + + +/* GS100 transceiver close */ +static int gs100_close(RIG *rig) +{ + ENTERFUNC; + + if (rig->caps->rig_model == RIG_MODEL_GS100) + { + rig_debug(RIG_DEBUG_VERBOSE, "%s: CLOSING'\n", __func__); + } + + RETURNFUNC(RIG_OK); +} + + +/* GS100 transceiver set configuration */ +static int gs100_set_conf(RIG *rig, token_t token, const char *val) +{ + struct gs100_priv_data *priv; + + ENTERFUNC; + + priv = (struct gs100_priv_data *)rig->state.priv; + + switch (token) + { + case 0: + break; + + case 1: + break; + + default: + RETURNFUNC(-RIG_EINVAL); + } + + RETURNFUNC(RIG_OK); +} + + +/* GS100 transceiver get configuration */ +static int gs100_get_conf(RIG *rig, token_t token, char *val) +{ + struct gs100_priv_data *priv; + + ENTERFUNC; + + priv = (struct gs100_priv_data *)rig->state.priv; + + switch (token) + { + case 0: + break; + + default: + RETURNFUNC(-RIG_EINVAL); + } + + RETURNFUNC(RIG_OK); +} + + +/* GS100 transceiver set receiver frequency */ +static int gs100_set_freq(RIG *rig, vfo_t vfo, freq_t freq) +{ + struct gs100_priv_data *priv = (struct gs100_priv_data *)rig->state.priv; + char fstr[20], value[20]; + int retval; + + ENTERFUNC; + + // reporting + sprintf_freq(fstr, sizeof(fstr), freq); + rig_debug(RIG_DEBUG_VERBOSE, "%s: fstr = '%s'\n", __func__, fstr); + +#ifdef _LOCAL_SIMULATION_ + priv->freq_rx = freq; +#endif + + // range check - GS100 don't do it! + if (freq < rig->caps->rx_range_list1->startf || freq > rig->caps->rx_range_list1->endf) RETURNFUNC(-RIG_EDOM); + + // perform set command + sprintf(value, "%1.0lf", freq); + retval = gomx_set(rig, GOM_CONFIG_TAB_RX, "freq", value); + if (retval != RIG_OK) RETURNFUNC(retval); + + RETURNFUNC(retval); +} + + +/* GS100 transceiver get receiver frequency */ +static int gs100_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) +{ + struct gs100_priv_data *priv = (struct gs100_priv_data *)rig->state.priv; + char fstr[20], resp[20]; + int retval; + freq_t f; + + ENTERFUNC; + + // perform the get command + retval = gomx_get(rig, GOM_CONFIG_TAB_RX, "freq", resp); + if (retval != RIG_OK) RETURNFUNC(retval); + +#ifdef _LOCAL_SIMULATION_ + *freq = priv->freq_rx; +#else + retval = sscanf(resp, "%lf", &f); +#endif + + // relevance check + if (retval != 1) RETURNFUNC(-RIG_EPROTO); + if (f < rig->caps->rx_range_list1->startf || f > rig->caps->rx_range_list1->endf) RETURNFUNC(-RIG_EDOM); + *freq = f; + + RETURNFUNC(RIG_OK); +} + + +/* GS100 transceiver set transmitter frequency */ +static int gs100_set_tx_freq(RIG *rig, vfo_t vfo, freq_t freq) +{ + struct gs100_priv_data *priv = (struct gs100_priv_data *)rig->state.priv; + char fstr[20], value[20]; + int retval; + + ENTERFUNC; + + // reporting + sprintf_freq(fstr, sizeof(fstr), freq); + rig_debug(RIG_DEBUG_VERBOSE, "%s: fstr = '%s'\n", __func__, fstr); + +#ifdef _LOCAL_SIMULATION_ + priv->freq_tx = freq; +#endif + + // range check - GS100 don't do it! + if (freq < rig->caps->tx_range_list1->startf || freq > rig->caps->tx_range_list1->endf) RETURNFUNC(-RIG_EDOM); + + // perform set command + sprintf(value, "%1.0lf", freq); + retval = gomx_set(rig, GOM_CONFIG_TAB_TX, "freq", value); + if (retval != RIG_OK) RETURNFUNC(retval); + + RETURNFUNC(RIG_OK); +} + + +/* GS100 transceiver get transmitter frequency */ +static int gs100_get_tx_freq(RIG *rig, vfo_t vfo, freq_t *freq) +{ + struct gs100_priv_data *priv = (struct gs100_priv_data *)rig->state.priv; + char fstr[20], resp[20]; + int retval; + freq_t f; + + ENTERFUNC; + + // perform the get command + retval = gomx_get(rig, GOM_CONFIG_TAB_TX, "freq", resp); + if (retval != RIG_OK) RETURNFUNC(retval); + +#ifdef _LOCAL_SIMULATION_ + *freq = priv->freq_tx; +#else + retval = sscanf(resp, "%lf", &f); +#endif + + // relevance check + if (retval != 1) RETURNFUNC(-RIG_EPROTO); + if (f < rig->caps->tx_range_list1->startf || f > rig->caps->tx_range_list1->endf) RETURNFUNC(-RIG_EDOM); + *freq = f; + + RETURNFUNC(RIG_OK); +} + + +/* GS100 transceiver get info */ +static const char *gs100_get_info(RIG *rig) +{ + return("Gomspace Ground Station Transceiver GS100"); +} + +/* The HAMLIB RIG Capabilities Structure Definition --------------------------*/ + +#define GS100_FUNC (0) +#define GS100_LEVEL (0) +#define GS100_PARM (0) +#define GS100_VFO_OPS RIG_OP_TUNE +#define GS100_VFOS (RIG_VFO_A) +#define GS100_MODES (RIG_MODE_PKTFM) + +struct rig_caps GS100_caps = +{ + RIG_MODEL(RIG_MODEL_GS100), + .model_name = "GS100", + .mfg_name = "GOMSPACE", + .version = "20211117.0", + .copyright = "LGPL", + .status = RIG_STATUS_ALPHA, + .rig_type = RIG_TYPE_TRANSCEIVER, + .targetable_vfo = 0, + .ptt_type = RIG_PTT_NONE, + .dcd_type = RIG_DCD_NONE, + .port_type = RIG_PORT_SERIAL, + .serial_rate_min = 115200, + .serial_rate_max = 500000, + .serial_data_bits = 8, + .serial_stop_bits = 1, + .serial_parity = RIG_PARITY_NONE, + .serial_handshake = RIG_HANDSHAKE_NONE, + .write_delay = 1, + .post_write_delay = 1, + .timeout = 250, + .retry = 0, + .has_get_func = GS100_FUNC, + .has_set_func = GS100_FUNC, + .has_get_level = GS100_LEVEL, + .has_set_level = GS100_LEVEL, + .has_get_parm = GS100_PARM, + .has_set_parm = GS100_PARM, + .vfo_ops = GS100_VFO_OPS, + .rx_range_list1 = { { + .startf = MHz(430), .endf = MHz(440), .modes = GS100_MODES, + .low_power = -1, .high_power = -1, GS100_VFOS, + .label = "GS100#1" + }, RIG_FRNG_END, }, + .tx_range_list1 = { { + .startf = MHz(430), .endf = MHz(440), .modes = GS100_MODES, + .low_power = -1, .high_power = -1, GS100_VFOS, + .label = "GS100#1" + }, RIG_FRNG_END, }, + .tuning_steps = { {GS100_MODES, Hz(10)}, RIG_TS_END, }, + .priv = NULL, + .rig_init = gs100_init, + .rig_cleanup = gs100_cleanup, + .rig_open = gs100_open, + .rig_close = gs100_close, + .set_conf = gs100_set_conf, + .get_conf = gs100_get_conf, + .set_freq = gs100_set_freq, + .get_freq = gs100_get_freq, + .set_split_freq = gs100_set_tx_freq, + .get_split_freq = gs100_get_tx_freq, + .get_info = gs100_get_info, +}; + +/* Private functions ---------------------------------------------------------*/ + +/* Set variable in the GS100 configuration table */ +static int gomx_set(RIG *rig, int table, char *varname, char *varvalue) +{ + struct gs100_priv_data *priv = (struct gs100_priv_data *)rig->state.priv; + int retval; + char msg[BUFSZ], resp[BUFSZ]; + + assert(rig != NULL); + assert(varname != NULL); + assert(varvalue != NULL); + + rig_debug(RIG_DEBUG_TRACE, "%s: table=%d, '%s' = '%s'\n", __func__, table, varname, varvalue); + + if (!PARAM_MEM_MINIMAL || table != priv->param_mem) + { + // select the configuration table + priv->param_mem = table; + sprintf(msg, "param mem %d\n", table); + retval = gomx_transaction(rig, msg, resp); + if (retval != RIG_OK) return(retval); + } + + // set the variable + sprintf(msg, "param set %s %s\n", varname, varvalue); + retval = gomx_transaction(rig, msg, resp); + if (retval != RIG_OK) return(retval); + + // check response + if (strlen(resp) > 0) return(-RIG_EPROTO); + return(RIG_OK); +} + + +/* Get variable from the GS100 configuration table */ +static int gomx_get(RIG *rig, int table, char *varname, char *varvalue) +{ + struct gs100_priv_data *priv = (struct gs100_priv_data *)rig->state.priv; + int retval; + char msg[BUFSZ], resp[BUFSZ], *c; + + assert(rig != NULL); + assert(varname != NULL); + assert(varvalue != NULL); + + rig_debug(RIG_DEBUG_TRACE, "%s: table=%d, '%s'\n", __func__, table, varname); + + if (!PARAM_MEM_MINIMAL || table != priv->param_mem) + { + // select the configuration table + priv->param_mem = table; + sprintf(msg, "param mem %d\n", table); + retval = gomx_transaction(rig, msg, resp); + if (retval != RIG_OK) return(retval); + } + + // get the variable + sprintf(msg, "param get %s\n", varname); + retval = gomx_transaction(rig, msg, resp); + if (retval != RIG_OK) return(retval); + + // check response and extract the value + if ((c = strchr(resp, '=')) == NULL) return(-RIG_EPROTO); + if (sscanf(c + 1, "%s", varvalue) != 1) return(-RIG_EPROTO); + return(RIG_OK); +} + + +/* Sends a message to the GS100 and parses response lines */ +static int gomx_transaction(RIG *rig, char *message, char *response) +{ + struct gs100_priv_data *priv; + struct rig_state *rs; + int retval, n = 0; + char buf[BUFSZ]; + + assert(rig != NULL); + assert(message != NULL); + assert(response != NULL); + + rig_debug(RIG_DEBUG_TRACE, "%s: msg='%s'\n", __func__, message == NULL ? "NULL" : message); + + // access to private variables + rs = &rig->state; + priv = (struct gs100_priv_data *)rs->priv; + + // send message to the transceiver + rig_flush(&rs->rigport); + retval = write_block(&rs->rigport, message, strlen(message)); + if (retval != RIG_OK) return(retval); + + while (1) + { + // read the response line + retval = read_string(&rs->rigport, buf, BUFSZ, GOM_STOPSET, strlen(GOM_STOPSET), 0); + if (retval < 0) return(retval); + if (retval == 0) return(-RIG_ETIMEOUT); + n++; + // prompt is always the last line + if (strcmp(buf, GOM_PROMPT) == 0) break; + // before last line would be the response + if (n > 1) strcpy(response, buf); + else *response = '\0'; // don't return command echo + if (n > GOM_MAXLINES) return(-RIG_EPROTO); + } + + // report the response + rig_debug(RIG_DEBUG_VERBOSE, "%s: returning response='%s'\n", __func__, response == NULL ? "NULL" : response); + return(RIG_OK); +} + +/* System Integration Functions ----------------------------------------------*/ + +/* Init RIG backend function */ +DECLARE_INITRIG_BACKEND(gomspace) +{ + ENTERFUNC; + rig_debug(RIG_DEBUG_VERBOSE, "%s: _init called\n", __func__); + rig_register(&GS100_caps); + RETURNFUNC(RIG_OK); +} + + +/* Probe RIG backend function */ +DECLARE_PROBERIG_BACKEND(gomspace) +{ + return(RIG_MODEL_GS100); +} + +/*----------------------------------------------------------------------------*/ diff --git a/rigs/gomspace/gs100.h b/rigs/gomspace/gs100.h new file mode 100644 index 000000000..2372499c1 --- /dev/null +++ b/rigs/gomspace/gs100.h @@ -0,0 +1,55 @@ +/* + * GomSpace backend and the GS100 radio control module + * + * Created in 2022 by Richard Linhart OK1CTR OK1CTR@gmail.com + * and used during VZLUSAT-2 satellite mission. + * + * 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 _GS100_H +#define _GS100_H 1 + +/* Includes ------------------------------------------------------------------*/ + +#include "hamlib/rig.h" +#include "token.h" + +/* Definitions ---------------------------------------------------------------*/ + +/* backend conf */ +#define TOK_CFG_MAGICCONF TOKEN_BACKEND(1) +#define TOK_CFG_STATIC_DATA TOKEN_BACKEND(2) + +/* ext_level's and ext_parm's tokens */ +#define TOK_EL_MAGICLEVEL TOKEN_BACKEND(1) +#define TOK_EL_MAGICFUNC TOKEN_BACKEND(2) +#define TOK_EL_MAGICOP TOKEN_BACKEND(3) +#define TOK_EP_MAGICPARM TOKEN_BACKEND(4) +#define TOK_EL_MAGICCOMBO TOKEN_BACKEND(5) +#define TOK_EL_MAGICEXTFUNC TOKEN_BACKEND(6) + +/* Public variables ----------------------------------------------------------*/ + +/* RIG capabilities descriptions */ +extern struct rig_caps gs100_caps; +extern struct rig_caps netrigctl_caps; +extern const struct rig_caps flrig_caps; +extern const struct rig_caps trxmanager_caps; + +/*----------------------------------------------------------------------------*/ + +#endif /* _GS100_H */ diff --git a/rigs/gomspace/gs100_sim/gs100_sim.ino b/rigs/gomspace/gs100_sim/gs100_sim.ino new file mode 100644 index 000000000..9ed585f91 --- /dev/null +++ b/rigs/gomspace/gs100_sim/gs100_sim.ino @@ -0,0 +1,400 @@ +/* + * Simple fundamental function simulator of GOMSPACE GS100 satellite + * radio transceiver + * + * Created in 2022 by Richard Linhart OK1CTR OK1CTR@gmail.com + * and used during VZLUSAT-2 satellite mission. + * + * This sorce code 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 + * + */ + +/* Includes ------------------------------------------------------------------*/ + +#include +#include +#include + +/* Private defines -----------------------------------------------------------*/ + +//! If defined, also silent commands print their result +#undef _DBG_SILENT_ +//! If defined, value range bounds are checked (originally not) +#undef _CHECK_BOUNDS_ + +//! Function finished with success +#define STATUS_OK 0 +//! Function finished with error +#define STATUS_ERROR -1 +//! Serial baud rate - cannot use 500000 as the GS100 have +#define BAUD_RATE 115200 +//! Incomming serial buffer length +#define BUF_LENGTH 32 +//! New line character on receive +#define NLRX '\n' +//! New line character on transmit +#define NLTX "\r\r\n" +//! Displayed prompt +#define PROMPT "\x1B[1;32mnanocom-ax\x1B[1;30m # \x1B[0m\x1B[0m" + +/* Private macros ------------------------------------------------------------*/ + +//! Checks leading substring as command +#define LEADINGSTR(a,b) (strncmp((a), (b), strlen(b)) == 0) +//! Find the first alphabet character in string +#define FIRSTALPHA(a) while(*(a) != '\0' && !isalpha(*(a))) { (a)++; } +//! Find the first alphabet character or number in string +#define FIRSTALNUM(a) while(*(a) != '\0' && !isalnum(*(a))) { (a)++; } +//! Find the first space in string +#define FIRSTSPACE(a) while(*(a) != '\0' && *(a) != ' ') { (a)++; } + +/* Private typedefs ----------------------------------------------------------*/ + +//! Types of hint outputs +typedef enum { + hint_param1, + hint_param2, + hint_mem, + hint_get1, + hint_get2, + hint_set +} hint_t; + +/* Private constants ---------------------------------------------------------*/ + +//! Low frequency limit, both for receive and transmit +static const unsigned long f_min = 430000000; +//! High frequency limit, both for receive and transmit +static const unsigned long f_max = 440000000; + +/* Private variables ---------------------------------------------------------*/ + +//! Selected configuration table memory +static uint8_t mem = 0; +//! Radio receive frequency +static unsigned long rx_freq; +//! Radio transmit frequency +static unsigned long tx_freq; + +/* Private function prototypes -----------------------------------------------*/ + +/** + * @brief Store incomming serial characters unitl line end + * @return The line if received successfully or NULL + */ +static char *serReadLine(void); + +/** + * @brief Process the command PARAM + * @param The input command string + * @return 0 in case of success + */ +static int cmdParam(char *cmd); + +/** + * @brief Process the command MEM + * @param The input command string + * @return 0 in case of success + */ +static int cmdMem(char *cmd); + +/** + * @brief Process the command GET + * @param The input command string + * @return 0 in case of success + */ +static int cmdGet(char *cmd); + +/** + * @brief Process the command SET + * @param The input command string + * @return 0 in case of success + */ +static int cmdSet(char *cmd); + +/** + * @brief Displays command prompt + */ +static void prnPrompt(void); + +/** + * @brief Displays hint output for commands + * @param hint_type Type or command + * @oaram cmd Part of commend to comment + */ +static void prnHint(hint_t hint_type, char *cmd); + +/* Functions -----------------------------------------------------------------*/ + +/** + * @brief Arduino SETUP function + */ +void setup(void) +{ + Serial.begin(BAUD_RATE); + rx_freq = f_min; + tx_freq = f_min; + return; +} + + +/** + * @brief Arduino LOOP function + */ +void loop(void) +{ + char *c; + + // reading command line from serial + if ((c = serReadLine()) != NULL) + { + FIRSTALPHA(c); + if (LEADINGSTR(c, "param")) + { + cmdParam(c); + } else { + if (strlen(c) > 0) + { + Serial.print("Unknown command '"); + Serial.print(c); + Serial.print("'"); + Serial.print(NLTX); + } + } + prnPrompt(); + } + + return; +} + +/* Private functions ---------------------------------------------------------*/ + +/* Store incomming serial characters unitl line end */ +static char *serReadLine(void) +{ + int inchar; + static char buf[BUF_LENGTH] = "\0", *p = buf; + + if (Serial.available()) + { + inchar = Serial.read(); + // is it end of line? + if (inchar > 0) + { + if (inchar == NLRX) + { + Serial.print(NLTX); // enf of line repeated strange + *p = '\0'; // terminate the string + p = buf; // reset the buffer + return(buf); + } + // repeat received character + Serial.write(inchar & 0xFF); + // insert new character into the buffer + *p = inchar & 0xFF; + if (p - buf < BUF_LENGTH - 1) + { + p++; + } else { + p = buf; // reset the buffer + } + } + } + return(NULL); +} + + +/* Process the command PARAM */ +static int cmdParam(char *cmd) +{ + FIRSTSPACE(cmd); + FIRSTALPHA(cmd); + if (strlen(cmd) > 0) + { + if (LEADINGSTR(cmd, "mem")) return(cmdMem(cmd)); + if (LEADINGSTR(cmd, "get")) return(cmdGet(cmd)); + if (LEADINGSTR(cmd, "set")) return(cmdSet(cmd)); + prnHint(hint_param1, cmd); + return(STATUS_ERROR); + } else { + prnHint(hint_param2, NULL); + return(STATUS_ERROR); + } +} + + +/* Process the command MEM */ +static int cmdMem(char *cmd) +{ + FIRSTSPACE(cmd); + FIRSTALNUM(cmd); + if (strlen(cmd) > 0) + { + mem = strtol(cmd, &cmd, 10) & 0xFF; +#ifdef _DBG_SILENT_ + Serial.print(mem); + Serial.print(NLTX); +#endif + return(STATUS_OK); + } else { + prnHint(hint_mem, NULL); + return(STATUS_ERROR); + } +} + + +/* Process the command GET */ +static int cmdGet(char *cmd) +{ + unsigned long f; + + FIRSTSPACE(cmd); + FIRSTALPHA(cmd); + if (strlen(cmd) > 0) + { + if (LEADINGSTR(cmd, "freq")) + { + switch (mem) + { + case 1: f = rx_freq; break; + case 5: f = tx_freq; break; + default: return(STATUS_ERROR); + } + Serial.print(" GET freq = "); + Serial.print(f); + Serial.print(NLTX); + return(STATUS_OK); + } else { + prnHint(hint_get1, cmd); + return(STATUS_ERROR); + } + } else { + prnHint(hint_get2, NULL); + return(STATUS_ERROR); + } +} + + +/* Process the command SET */ +static int cmdSet(char *cmd) +{ + unsigned long f; + + FIRSTSPACE(cmd); + FIRSTALPHA(cmd); + if (strlen(cmd) > 0) + { + if (LEADINGSTR(cmd, "freq")) + { + FIRSTSPACE(cmd); + FIRSTALNUM(cmd); + if (strlen(cmd) == 0) + { + prnHint(hint_set, NULL); + return(STATUS_ERROR); + } + f = strtol(cmd, &cmd, 10); +#ifdef _DBG_SILENT_ + Serial.print(f); + Serial.print(NLTX); +#endif +#ifdef _CHECK_BOUNDS_ + if (f < f_min) f = f_min; + if (f > f_max) f = f_max; +#endif + switch (mem) + { + case 1: rx_freq = f; break; + case 5: tx_freq = f; break; + default: return(STATUS_ERROR); + } + return(STATUS_OK); + } else { + // different behavior than at GET + prnHint(hint_set, NULL); + return(STATUS_ERROR); + } + } else { + prnHint(hint_set, NULL); + return(STATUS_ERROR); + } +} + + +/* Displays command prompt */ +static void prnPrompt(void) +{ + Serial.print(PROMPT); + return; +} + + +/* Displays hint output for commands */ +static void prnHint(hint_t hint_type, char *cmd) +{ + switch (hint_type) + { + case hint_param1: + Serial.print("Unknown command 'param "); + Serial.print(cmd); + Serial.print("'"); + Serial.print(NLTX); + return; + + case hint_param2: + // reduced on simulated commads only! + Serial.print("'param' contains sub-commands:"); + Serial.print(NLTX); + Serial.print(" mem Set cmds working mem"); + Serial.print(NLTX); + Serial.print(" set Set parameter"); + Serial.print(NLTX); + Serial.print(" get Get parameter"); + Serial.print(NLTX); + break; + + case hint_mem: + Serial.print("usage: mem "); + Serial.print(NLTX); + Serial.print("Could not execute command 'param mem', error -2"); + Serial.print(NLTX); + break; + + case hint_get1: + Serial.print("Unknown parameter "); + Serial.print(cmd); + Serial.print(NLTX); + Serial.print("Could not execute command 'param get shit', error -1"); + Serial.print(NLTX); + break; + + case hint_get2: + Serial.print("usage: get "); + Serial.print(NLTX); + Serial.print("Could not execute command 'param get', error -2"); + Serial.print(NLTX); + break; + + case hint_set: + Serial.print("usage: set [quiet]"); + Serial.print(NLTX); + Serial.print("Could not execute command 'param set', error -2"); + Serial.print(NLTX); + break; + } + return; +} + +/*----------------------------------------------------------------------------*/ diff --git a/src/register.c b/src/register.c index b92be9e93..b1173f01c 100644 --- a/src/register.c +++ b/src/register.c @@ -89,6 +89,7 @@ DEFINE_INITRIG_BACKEND(dorji); DEFINE_INITRIG_BACKEND(barrett); DEFINE_INITRIG_BACKEND(elad); DEFINE_INITRIG_BACKEND(codan); +DEFINE_INITRIG_BACKEND(gomspace); //! @endcond #ifdef HAVE_WINRADIO @@ -146,6 +147,7 @@ static struct { RIG_BARRETT, RIG_BACKEND_BARRETT, RIG_FUNCNAMA(barrett) }, { RIG_ELAD, RIG_BACKEND_ELAD, RIG_FUNCNAMA(elad) }, { RIG_CODAN, RIG_BACKEND_CODAN, RIG_FUNCNAMA(codan) }, + { RIG_GOMSPACE, RIG_BACKEND_GOMSPACE, RIG_FUNCNAM(gomspace) }, { 0, NULL }, /* end */ }; diff --git a/src/serial.c b/src/serial.c index efd89039c..6fd2123bb 100644 --- a/src/serial.c +++ b/src/serial.c @@ -370,6 +370,13 @@ int HAMLIB_API serial_setup(hamlib_port_t *rp) break; #endif +#ifdef B500000 + + case 500000: + speed = B500000; /* extra super awesome! */ + break; +#endif + default: rig_debug(RIG_DEBUG_ERR, "%s: unsupported rate specified: %d\n",