From 7806e467fbe9bec0b7f44442c10ff49dfefe0c02 Mon Sep 17 00:00:00 2001 From: Michael Black W9MDB Date: Wed, 7 Mar 2018 14:31:15 -0500 Subject: [PATCH] Add Rohde&Schwarz xk2100 backend for W1AW --- include/hamlib/riglist.h | 1 + rs/Android.mk | 2 +- rs/Makefile.am | 2 +- rs/gp2000.c | 530 +++++++++++++++++++++++++++++++++++++++ rs/gp2000.h | 45 ++++ rs/rs.c | 2 + rs/xk2100.c | 192 ++++++++++++++ 7 files changed, 772 insertions(+), 2 deletions(-) create mode 100644 rs/gp2000.c create mode 100644 rs/gp2000.h create mode 100644 rs/xk2100.c diff --git a/include/hamlib/riglist.h b/include/hamlib/riglist.h index bed33503a..923cf20ac 100644 --- a/include/hamlib/riglist.h +++ b/include/hamlib/riglist.h @@ -541,6 +541,7 @@ #define RIG_BACKEND_RS "rs" #define RIG_MODEL_ESMC RIG_MAKE_MODEL(RIG_RS, 1) #define RIG_MODEL_EB200 RIG_MAKE_MODEL(RIG_RS, 2) +#define RIG_MODEL_XK2100 RIG_MAKE_MODEL(RIG_RS, 3) /* diff --git a/rs/Android.mk b/rs/Android.mk index 302a670d3..937d22758 100644 --- a/rs/Android.mk +++ b/rs/Android.mk @@ -2,7 +2,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES := esmc.c eb200.c rs.c +LOCAL_SRC_FILES := esmc.c eb200.c rs.c xk2000.c gp2000.c LOCAL_MODULE := rs LOCAL_CFLAGS := -DHAVE_CONFIG_H diff --git a/rs/Makefile.am b/rs/Makefile.am index e222bc876..e606b736c 100644 --- a/rs/Makefile.am +++ b/rs/Makefile.am @@ -1,4 +1,4 @@ -RSSRC = esmc.c eb200.c rs.c rs.h +RSSRC = esmc.c eb200.c rs.c rs.h gp2000.c gp2000.h xk2100.c noinst_LTLIBRARIES = libhamlib-rs.la libhamlib_rs_la_SOURCES = $(RSSRC) diff --git a/rs/gp2000.c b/rs/gp2000.c new file mode 100644 index 000000000..03ede58bf --- /dev/null +++ b/rs/gp2000.c @@ -0,0 +1,530 @@ +/* + * Hamlib R&S GP2000 backend - main file + * Reused from rs.c + * Copyright (c) 2018 by Michael Black W9MDB + * Copyright (c) 2009-2010 by Stéphane Fillod + * + * + * 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 + * + */ + +/* + * Looks like the GP2000 could be reused in other rigs so + * we implmenet that and then the XK2100 uses this interface + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include /* String function definitions */ +#include /* UNIX standard function definitions */ +#include + +#include "hamlib/rig.h" +#include "serial.h" +#include "misc.h" +#include "register.h" +#include "num_stdio.h" + +#include "gp2000.h" + +#define RESPSZ 64 + +#define LF "\x0a" +#define CR "\x0d" +#define BOM LF +#define EOM CR + +/* + * R&S GB2 protocol ? + */ + + +/* + * gp2000 + * We assume that rig!=NULL, rig->state!= NULL, data!=NULL, data_len!=NULL + */ +int +gp2000_transaction(RIG *rig, const char *cmd, int cmd_len, char *data, + int *data_len) +{ + int retval; + struct rig_state *rs; + + rig_debug(RIG_DEBUG_VERBOSE, "%s: len=%d,cmd=%s\n", __func__, cmd_len, + cmd); + + rs = &rig->state; + + serial_flush(&rs->rigport); + + rig_debug(RIG_DEBUG_VERBOSE, "gp2000_transaction: len=%d,cmd=%s\n", + cmd_len, cmd); + retval = write_block(&rs->rigport, cmd, cmd_len); + + if (retval != RIG_OK) + { + return retval; + } + + + /* no data expected */ + if (!data || !data_len) + { + return RIG_OK; + } + + retval = read_string(&rs->rigport, data, RESPSZ, CR, 1); + + if (retval < 0) + { + return retval; + } + + *data_len = retval; + + return RIG_OK; +} + +/* + * gp2000_set_freq + * Assumes rig!=NULL + */ +int +gp2000_set_freq(RIG *rig, vfo_t vfo, freq_t freq) +{ + char freqbuf[32]; + int freq_len, retval; + + rig_debug(RIG_DEBUG_VERBOSE, "%s: vfo=%s,freq=%.0f\n", __func__, + rig_strvfo(vfo), freq); + + freq_len = + snprintf(freqbuf, sizeof(freqbuf), BOM "F%" PRIll ",%" PRIll EOM, + (int64_t) freq, + (int64_t) freq); + retval = gp2000_transaction(rig, freqbuf, freq_len, NULL, NULL); + + return retval; +} + +/* + * gp2000_get_freq + * Assumes rig!=NULL + */ +int +gp2000_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) +{ + char buf[RESPSZ]; + int len, retval; + + rig_debug(RIG_DEBUG_VERBOSE, "%s: vfo=%s\n", __func__, rig_strvfo(vfo)); + +#define FREQ_QUERY BOM "F?" EOM + + retval = + gp2000_transaction(rig, FREQ_QUERY, strlen(FREQ_QUERY), buf, &len); + + if (retval < 0) + { + return retval; + } + + retval = (sscanf(buf, "%*cF%" SCNfreq, freq) == 1) ? RIG_OK : -RIG_EPROTO; + + return retval; +} + +/* + * gp2000_set_mode + * Assumes rig!=NULL + */ +int +gp2000_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) +{ + char buf[32], *smode; + int len, retval; + + rig_debug(RIG_DEBUG_VERBOSE, "%s: vfo=%s, mode=%s, width=%d\n", __func__, + rig_strvfo(vfo), rig_strvfo(mode), width); + + switch (mode) + { + case RIG_MODE_AM: + smode = "1"; + break; + + case RIG_MODE_USB: + smode = "2"; + break; + + case RIG_MODE_LSB: + smode = "3"; + break; + + case RIG_MODE_CW: + smode = "5"; + break; + + case RIG_MODE_FM: + smode = "9"; + break; + + case RIG_MODE_PKTUSB: + smode = "13"; // use the 2700 bandwidth for packet + break; + + case RIG_MODE_PKTLSB: + smode = "14"; // use the 2700 bandwidth for packet + break; + + default: + return -RIG_EINVAL; + } + + len = snprintf(buf, sizeof(buf), BOM "I%s" EOM, smode); + retval = gp2000_transaction(rig, buf, len, NULL, NULL); + + if (retval < 0) + { + return retval; + } + + if (width == RIG_PASSBAND_NOCHANGE) + { + return retval; + } + + if (width == RIG_PASSBAND_NORMAL) + { + width = rig_passband_normal(rig, mode); + } + + if (width > 0) + { + len = snprintf(buf, sizeof(buf), BOM "W%d" EOM, (int) width); + retval = gp2000_transaction(rig, buf, len, NULL, NULL); + } + + return retval; +} + +/* + * gp2000_get_mode + * Assumes rig!=NULL + */ +int +gp2000_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width) +{ + char buf[RESPSZ]; + int buf_len, retval; + + rig_debug(RIG_DEBUG_VERBOSE, "%s: vfo=%s\n", __func__, rig_strvfo(vfo)); + +#define DEM_QUERY BOM "I?" EOM + + retval = + gp2000_transaction(rig, DEM_QUERY, strlen(DEM_QUERY), buf, &buf_len); + + if (retval < 0) + { + return retval; + } + + int nmode; + char *pmode = "UNKNOWN"; + int n = sscanf(buf, "%*cI%d", &nmode); + + if (n != 1) + { + return -RIG_EPROTO; + } + + switch (nmode) + { + case 1: pmode = "AM"; break; + + case 2: pmode = "USB"; break; + + case 3: pmode = "LSB"; break; + + case 5: pmode = "CW"; break; + + case 9: pmode = "FM"; break; + + case 13: pmode = "PKTUSB"; break; + + case 14: pmode = "PKTLSB"; break; + } + + *mode = rig_parse_mode(pmode); + +#define BAND_QUERY BOM "W?" EOM + retval = + gp2000_transaction(rig, BAND_QUERY, strlen(BAND_QUERY), buf, &buf_len); + + if (retval < 0) + { + return retval; + } + + *width = atoi(&buf[2]); + + return retval; +} + + +int +gp2000_set_func(RIG *rig, vfo_t vfo, setting_t func, int status) +{ + char buf[32], *sfunc; + int len, retval; + + rig_debug(RIG_DEBUG_VERBOSE, "%s: vfo=%s\n", __func__, rig_strvfo(vfo)); + + switch (func) + { + case RIG_FUNC_SQL: + sfunc = "SQ00"; + break; + + default: + return -RIG_EINVAL; + } + + len = snprintf(buf, sizeof(buf), BOM "%s %s" EOM, sfunc, status ? "1" : "0"); + retval = gp2000_transaction(rig, buf, len, NULL, NULL); + + return retval; +} + +int +gp2000_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) +{ + char buf[RESPSZ], *sfunc; + int buf_len, retval; + + rig_debug(RIG_DEBUG_VERBOSE, "%s: vfo=%s\n", __func__, rig_strvfo(vfo)); + + switch (func) + { + case RIG_FUNC_SQL: + sfunc = BOM "SQ00?" EOM; + break; + + default: + return -RIG_EINVAL; + } + + retval = gp2000_transaction(rig, sfunc, strlen(sfunc), buf, &buf_len); + + if (retval < 0) + { + return retval; + } + + // we expecte LF+"X" where X is the status + *status = buf[2] == 1 ? 1 : 0; + + return retval; +} + +int +gp2000_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) +{ + char buf[64]; + int len, retval; + + rig_debug(RIG_DEBUG_VERBOSE, "%s: vfo=%s\n", __func__, rig_strvfo(vfo)); + + switch (level) + { + case RIG_LEVEL_AF: + len = snprintf(buf, sizeof(buf), BOM "SR%02d" EOM, (int)val.f); + break; + + case RIG_LEVEL_SQL: + len = snprintf(buf, sizeof(buf), BOM "SQ%1d" EOM, (int)val.f); + break; + + case RIG_LEVEL_AGC: + case RIG_LEVEL_RF: + return -RIG_ENIMPL; + + default: + return -RIG_EINVAL; + } + + retval = gp2000_transaction(rig, buf, len, NULL, NULL); + + return retval; +} + +int +gp2000_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) +{ + char buf[RESPSZ], *slevel; + int buf_len, retval, ival; + + rig_debug(RIG_DEBUG_VERBOSE, "%s: vfo=%s\n", __func__, rig_strvfo(vfo)); + + switch (level) + { + case RIG_LEVEL_AF: + slevel = BOM "SL?" EOM; + break; + + case RIG_LEVEL_SQL: + slevel = BOM "SQ?" EOM; + break; + + case RIG_LEVEL_STRENGTH: + case RIG_LEVEL_ATT: + case RIG_LEVEL_AGC: + case RIG_LEVEL_RF: + return -RIG_ENIMPL; + + default: + return -RIG_EINVAL; + } + + retval = gp2000_transaction(rig, slevel, strlen(slevel), buf, &buf_len); + + if (retval < 0) + { + return retval; + } + + switch (level) + { + case RIG_LEVEL_AF: + if (num_sscanf(buf, "%*cSL%d", &ival) != 1) + { + return -RIG_EPROTO; + } + + val->f = ival; + + break; + + case RIG_LEVEL_SQL: + if (num_sscanf(buf, "%*cSQ%1d", &ival) != 1) + { + return -RIG_EPROTO; + } + + val->f = ival; + + break; + + default: + return -RIG_EINVAL; + } + + return retval; +} + +const char * +gp2000_get_info(RIG *rig) +{ + static char infobuf[128]; + int info_len, retval; + + rig_debug(RIG_DEBUG_VERBOSE, "%s\n", __func__); + +#define ID_QUERY BOM "IDENT?" EOM + + retval = + gp2000_transaction(rig, ID_QUERY, strlen(ID_QUERY), infobuf, &info_len); + + if (retval < 0) + { + return NULL; + } + + int addr = -1; + char type[32] = "unk type"; + char rigid[32] = "unk rigid"; + char sernum[32] = "unk sernum"; + + char *p = strtok(infobuf, ","); + + while (p) + { + switch (p[0]) + { + case 0x0a: + sscanf(p, "%*cIDENT%s", type); + break; + + case 'i': + sscanf(p, "id%s", rigid); + break; + + case 's': + sscanf(p, "sn%s", sernum); + break; + + default: + printf("Unknown reponse: %s\n", p); + + } + + p = strtok(NULL, ","); + } + + snprintf(infobuf, sizeof(infobuf), "ADDR=%02d\nTYPE=%s\nSER#=%s\nID =%s\n", + addr, type, sernum, rigid); + + return infobuf; +} + +int +gp2000_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt) +{ + int retval = 0; + char cmd[32]; + + rig_debug(RIG_DEBUG_VERBOSE, "%s: vfo=%s\n", __func__, rig_strvfo(vfo)); + + snprintf(cmd, sizeof(cmd), "X%1d", ptt); + retval = gp2000_transaction(rig, cmd, strlen(cmd), NULL, NULL); + return retval; +} + +int +gp2000_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt) +{ + int retval = 0; + int len; + char buf[RESPSZ]; + char *cmd = BOM "X?" EOM; + + rig_debug(RIG_DEBUG_VERBOSE, "%s: vfo=%s\n", __func__, rig_strvfo(vfo)); + + retval = gp2000_transaction(rig, cmd, strlen(cmd), buf, &len); + + if (retval < 0) + { + return retval; + } + + retval = (sscanf(buf, "%*cX%1u", ptt) == 1) ? RIG_OK : -RIG_EPROTO; + return retval; +} + diff --git a/rs/gp2000.h b/rs/gp2000.h new file mode 100644 index 000000000..c1d0af53c --- /dev/null +++ b/rs/gp2000.h @@ -0,0 +1,45 @@ +/* + * Hamlib R&S backend for XK2000 - main header + * Reused from rs.c + * Copyright (c) 2018 by Michael Black W9MDB + * Copyright (c) 2009-2010 by Stephane Fillod + * + * + * 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 _XK2000_H +#define _XK2000_H 1 + +#include + + +int gp2000_set_ptt(RIG *rig, vfo_t vfo, ptt_t ptt); +int gp2000_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt); +int gp2000_set_freq(RIG *rig, vfo_t vfo, freq_t freq); +int gp2000_get_freq(RIG *rig, vfo_t vfo, freq_t *freq); +int gp2000_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width); +int gp2000_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width); +int gp2000_set_func(RIG *rig, vfo_t vfo, setting_t func, int status); +int gp2000_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status); +int gp2000_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val); +int gp2000_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val); +int gp2000_reset(RIG *rig, reset_t reset); +const char * gp2000_get_info(RIG *rig); + +extern const struct rig_caps xk2100_caps; + +#endif /* XK2000_H */ diff --git a/rs/rs.c b/rs/rs.c index 4099fb6e9..d23d61feb 100644 --- a/rs/rs.c +++ b/rs/rs.c @@ -36,6 +36,7 @@ #include "num_stdio.h" #include "rs.h" +#include "gp2000.h" #define BUFSZ 64 @@ -328,6 +329,7 @@ DECLARE_INITRIG_BACKEND(rs) rig_register(&esmc_caps); rig_register(&eb200_caps); + rig_register(&xk2100_caps); return RIG_OK; } diff --git a/rs/xk2100.c b/rs/xk2100.c new file mode 100644 index 000000000..d20c1e365 --- /dev/null +++ b/rs/xk2100.c @@ -0,0 +1,192 @@ +/* + * Hamlib R&S backend - XK2100 description + * Copyright (c) 2009-2010 by Stephane Fillod + * + * + * 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 + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include "gp2000.h" + +#define XK2100_MODES (RIG_MODE_USB|RIG_MODE_LSB|RIG_MODE_PKTUSB|RIG_MODE_PKTLSB|RIG_MODE_CW|RIG_MODE_AM|RIG_MODE_FM) + +#define XK2100_FUNC (RIG_FUNC_SQL) + +/* #define XK2100_LEVEL_ALL (RIG_LEVEL_ATT|RIG_LEVEL_SQL|RIG_LEVEL_AGC| \ + * RIG_LEVEL_RF|RIG_LEVEL_AF|RIG_LEVEL_STRENGTH) + */ + +#define XK2100_LEVEL_ALL (RIG_LEVEL_SQL|\ + RIG_LEVEL_AF) + +#define XK2100_PARM_ALL (RIG_PARM_NONE) + +#define XK2100_VFO (RIG_VFO_A) + +#define XK2100_VFO_OPS (RIG_OP_NONE) + +#define XK2100_ANTS (RIG_ANT_1) + +#define XK2100_MEM_CAP { \ + .freq = 1, \ + .mode = 1, \ + .width = 1, \ + .ant = 1, \ + .funcs = XK2100_FUNC, \ + .levels = RIG_LEVEL_SET(XK2100_LEVEL_ALL), \ + .channel_desc=1, \ + .flags = RIG_CHFLAG_SKIP, \ +} + + +/* + * XK2100 rig capabilities. + * + * Had to use NONE for flow control and set RTS high + * We are not using address mode since we're on RS232 for now + * If using RS485 should add address capability + * + * TODO + * - set/get_channels + */ + +const struct rig_caps xk2100_caps = +{ + .rig_model = RIG_MODEL_XK2100, + .model_name = "XK2100", + .mfg_name = "Rohde&Schwarz", + .version = "0.8f", + .copyright = "LGPL", + .status = RIG_STATUS_BETA, + .rig_type = RIG_TYPE_TRANSCEIVER, + .ptt_type = RIG_PTT_RIG, + // Need to set RTS on for some reason + // And HANDSHAKE_NONE even though HARDWARE is what is called for + .dcd_type = RIG_DCD_NONE, + .port_type = RIG_PORT_SERIAL, + .serial_rate_min = 9600, + .serial_rate_max = 38400, /* 7E1, RTS/CTS */ + .serial_data_bits = 7, + .serial_stop_bits = 1, + .serial_parity = RIG_PARITY_EVEN, + .serial_handshake = RIG_HANDSHAKE_NONE, + .write_delay = 0, + .post_write_delay = 0, + .timeout = 200, + .retry = 3, + + .has_get_func = XK2100_FUNC, + .has_set_func = XK2100_FUNC, + .has_get_level = XK2100_LEVEL_ALL, + .has_set_level = RIG_LEVEL_SET(XK2100_LEVEL_ALL), + .has_get_parm = XK2100_PARM_ALL, + .has_set_parm = RIG_PARM_SET(XK2100_PARM_ALL), + .level_gran = {}, + .parm_gran = {}, + .ctcss_list = NULL, + .dcs_list = NULL, + .preamp = {RIG_DBLST_END}, + .attenuator = {32, RIG_DBLST_END}, + .max_rit = Hz(0), + .max_xit = Hz(0), + .max_ifshift = Hz(0), + .targetable_vfo = 0, + .transceive = RIG_TRN_RIG, + .bank_qty = 0, + .chan_desc_sz = 7, /* FIXME */ + .vfo_ops = XK2100_VFO_OPS, + + .chan_list = { + {0, 99, RIG_MTYPE_MEM, XK2100_MEM_CAP}, + RIG_CHAN_END, + }, + + .rx_range_list1 = { + { + kHz(1500), MHz(30), XK2100_MODES, -1, -1, XK2100_VFO, + XK2100_ANTS + }, + RIG_FRNG_END, + }, + .tx_range_list1 = {RIG_FRNG_END,}, + .rx_range_list2 = { + { + kHz(1500), MHz(30), XK2100_MODES, -1, -1, XK2100_VFO, + XK2100_ANTS + }, + RIG_FRNG_END, + }, + .tx_range_list2 = {RIG_FRNG_END,}, + + /* + .tuning_steps = { + {XK2100_MODES,1}, + {XK2100_MODES,10}, + {XK2100_MODES,100}, + {XK2100_MODES,1000}, + RIG_TS_END, + }, + */ + + /* mode/filter list, remember: order matters! */ + .filters = { + {RIG_MODE_WFM, kHz(150)}, + {RIG_MODE_FM | RIG_MODE_AM, kHz(15)}, + {XK2100_MODES, kHz(2.4)}, + {XK2100_MODES, kHz(1.5)}, + {XK2100_MODES, Hz(150)}, + {XK2100_MODES, Hz(300)}, + {XK2100_MODES, Hz(600)}, + {XK2100_MODES, kHz(6)}, + {XK2100_MODES, kHz(9)}, + {XK2100_MODES, kHz(15)}, + {XK2100_MODES, kHz(30)}, + {XK2100_MODES, kHz(50)}, + {XK2100_MODES, kHz(120)}, + RIG_FLT_END, + }, + .priv = NULL, + + .set_ptt = gp2000_set_ptt, + .get_ptt = gp2000_get_ptt, + .set_freq = gp2000_set_freq, + .get_freq = gp2000_get_freq, + .set_mode = gp2000_set_mode, + .get_mode = gp2000_get_mode, + .set_level = gp2000_set_level, + .get_level = gp2000_get_level, +//.set_func = gp2000_set_func, +//.get_func = gp2000_get_func, + .get_info = gp2000_get_info, + +#if 0 + /* TODO */ + .rig_open = gp2000_rig_open, + .set_channel = gp2000_set_channel, + .get_channel = gp2000_get_channel, +#endif +}; + +/* + * Function definitions below + */