From 2ef73b49fc8a2e5ce9778abbef4694ce6ce159f1 Mon Sep 17 00:00:00 2001 From: Michael Black W9MDB Date: Mon, 15 Mar 2021 11:15:41 -0500 Subject: [PATCH] https://github.com/Hamlib/Hamlib/issues/280 https://github.com/Hamlib/Hamlib/issues/606 --- include/hamlib/rig.h | 60 ++++++---- rigs/dummy/dummy.c | 63 +++++++--- rigs/icom/frame.c | 2 +- src/misc.c | 2 + src/misc.h | 18 ++- src/rig.c | 272 +++++++++++++++++++++++-------------------- tests/Makefile.am | 10 +- tests/testcache.c | 161 +++++++++++++++++++++++++ 8 files changed, 421 insertions(+), 167 deletions(-) create mode 100644 tests/testcache.c diff --git a/include/hamlib/rig.h b/include/hamlib/rig.h index 4fdc0b454..c3a5f2696 100644 --- a/include/hamlib/rig.h +++ b/include/hamlib/rig.h @@ -402,7 +402,7 @@ typedef unsigned int vfo_t; /** \brief '' -- used in caps */ -#define RIG_VFO_N(n) (1u<<(n)) +#define RIG_VFO_N(n) ((vfo_t)(1u<<(n))) /** \brief \c VFONone -- vfo unknown */ #define RIG_VFO_NONE 0 @@ -425,12 +425,18 @@ typedef unsigned int vfo_t; /** \brief \c SubB -- alias for SUB_B */ #define RIG_VFO_SUB_B RIG_VFO_N(22) +/** \brief \c SubC -- alias for SUB_B */ +#define RIG_VFO_SUB_C RIG_VFO_N(3) + /** \brief \c MainA -- alias for MAIN_A */ #define RIG_VFO_MAIN_A RIG_VFO_N(23) /** \brief \c MainB -- alias for MAIN_B */ #define RIG_VFO_MAIN_B RIG_VFO_N(24) +/** \brief \c MainC -- alias for MAIN_C */ +#define RIG_VFO_MAIN_C RIG_VFO_N(4) + /** \brief \c Sub -- alias for SUB */ #define RIG_VFO_SUB RIG_VFO_N(25) @@ -452,7 +458,7 @@ typedef unsigned int vfo_t; /** \brief \c Flag to set all VFOS */ #define RIG_VFO_ALL RIG_VFO_N(31) -// we and also use RIG_VFO_N(31) if needed +// we can also use RIG_VFO_N(31) if needed // Misc VFO Macros @@ -2081,7 +2087,7 @@ typedef enum { struct rig_cache { int timeout_ms; // the cache timeout for invalidating itself vfo_t vfo; - freq_t freq; // to be deprecated in 4.1 when full Main/Sub/A/B caching is implemented in 4.1 + //freq_t freq; // to be deprecated in 4.1 when full Main/Sub/A/B caching is implemented in 4.1 // other abstraction here is based on dual vfo rigs and mapped to all others // So we have four possible states of rig // MainA, MainB, SubA, SubB @@ -2089,42 +2095,55 @@ struct rig_cache { // Most rigs have MainA and MainB // Dual VFO rigs can have SubA and SubB too // For dual VFO rigs simplex operations are all done on MainA/MainB -- ergo this abstraction - freq_t freqCurr; // VFO_CURR freq_t freqMainA; // VFO_A, VFO_MAIN, and VFO_MAINA freq_t freqMainB; // VFO_B, VFO_SUB, and VFO_MAINB -#if 0 freq_t freqMainC; // VFO_C, VFO_MAINC -#endif freq_t freqSubA; // VFO_SUBA -- only for rigs with dual Sub VFOs freq_t freqSubB; // VFO_SUBB -- only for rigs with dual Sub VFOs - freq_t freqMem; // VFO_MEM -- last MEM channel -#if 0 // future freq_t freqSubC; // VFO_SUBC -- only for rigs with 3 Sub VFOs -#endif - rmode_t mode; - pbwidth_t width; - pbwidth_t widthB; // if non-zero then rig has separate width for VFOB + freq_t freqMem; // VFO_MEM -- last MEM channel + rmode_t modeMainA; + rmode_t modeMainB; + rmode_t modeMainC; + rmode_t modeSubA; + rmode_t modeSubB; + rmode_t modeSubC; + rmode_t modeMem; + pbwidth_t widthMainA; // if non-zero then rig has separate width for MainA + pbwidth_t widthMainB; // if non-zero then rig has separate width for MainB + pbwidth_t widthMainC; // if non-zero then rig has separate width for MainC + pbwidth_t widthSubA; // if non-zero then rig has separate width for SubA + pbwidth_t widthSubB; // if non-zero then rig has separate width for SubB + pbwidth_t widthSubC; // if non-zero then rig has separate width for SubC + pbwidth_t widthMem; // if non-zero then rig has separate width for Mem ptt_t ptt; split_t split; vfo_t split_vfo; // split caches two values - struct timespec time_freq; - struct timespec time_freqCurr; struct timespec time_freqMainA; struct timespec time_freqMainB; -#if 0 struct timespec time_freqMainC; -#endif struct timespec time_freqSubA; struct timespec time_freqSubB; + struct timespec time_freqSubC; struct timespec time_freqMem; struct timespec time_vfo; - struct timespec time_mode; + struct timespec time_modeMainA; + struct timespec time_modeMainB; + struct timespec time_modeMainC; + struct timespec time_modeSubA; + struct timespec time_modeSubB; + struct timespec time_modeSubC; + struct timespec time_modeMem; + struct timespec time_widthMainA; + struct timespec time_widthMainB; + struct timespec time_widthMainC; + struct timespec time_widthSubA; + struct timespec time_widthSubB; + struct timespec time_widthSubC; + struct timespec time_widthMem; struct timespec time_ptt; struct timespec time_split; - vfo_t vfo_freq; // last vfo cached - vfo_t vfo_mode; // last vfo cached int satmode; // if rig is in satellite mode - rmode_t modeB; }; @@ -2982,6 +3001,7 @@ extern HAMLIB_EXPORT(int) rig_set_cache_timeout_ms(RIG *rig, hamlib_cache_t sele extern HAMLIB_EXPORT(int) rig_set_vfo_opt(RIG *rig, int status); extern HAMLIB_EXPORT(int) rig_get_vfo_info(RIG *rig, vfo_t vfo, freq_t *freq, rmode_t *mode, pbwidth_t *width, split_t *split); +extern HAMLIB_EXPORT(int) rig_get_cache(RIG *rig, vfo_t vfo, freq_t *freq, int * cache_ms_freq, rmode_t *mode, int *cache_ms_mode, pbwidth_t *width, int *cache_ms_width); typedef unsigned long rig_useconds_t; diff --git a/rigs/dummy/dummy.c b/rigs/dummy/dummy.c index 46faa1d41..1e20ddb65 100644 --- a/rigs/dummy/dummy.c +++ b/rigs/dummy/dummy.c @@ -72,6 +72,7 @@ struct dummy_priv_data channel_t vfo_a; channel_t vfo_b; + channel_t vfo_c; channel_t mem[NB_CHAN]; struct ext_list *ext_funcs; @@ -388,13 +389,23 @@ static int dummy_set_freq(RIG *rig, vfo_t vfo, freq_t freq) if (vfo == RIG_VFO_CURR) { vfo = priv->curr_vfo; } + // we emulate a rig with 100Hz set freq interval limits -- truncation + freq = freq - ((unsigned long)freq % 100); usleep(CMDSLEEP); sprintf_freq(fstr, sizeof(fstr), freq); rig_debug(RIG_DEBUG_VERBOSE, "%s called: %s %s\n", __func__, rig_strvfo(vfo), fstr); - if (vfo == RIG_VFO_A || vfo == RIG_VFO_MAIN) { priv->curr->freq = freq; } - else if (vfo == RIG_VFO_B || vfo == RIG_VFO_SUB) { priv->curr->tx_freq = freq; } + switch(vfo) + { + case RIG_VFO_MAIN: + case RIG_VFO_A: priv->vfo_a.freq = freq;break; + + case RIG_VFO_SUB: + case RIG_VFO_B: priv->vfo_b.freq = freq;break; + + case RIG_VFO_C: priv->vfo_c.freq = freq;break; + } if (!priv->split) { @@ -430,10 +441,12 @@ static int dummy_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) switch (vfo) { case RIG_VFO_MAIN: - case RIG_VFO_A: *freq = priv->curr->freq; break; + case RIG_VFO_A: *freq = priv->vfo_a.freq; break; case RIG_VFO_SUB: - case RIG_VFO_B: *freq = priv->curr->tx_freq; break; + case RIG_VFO_B: *freq = priv->vfo_b.freq; break; + + case RIG_VFO_C: *freq = priv->vfo_c.freq; break; default: RETURNFUNC(-RIG_EINVAL); } @@ -455,17 +468,28 @@ static int dummy_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) rig_debug(RIG_DEBUG_VERBOSE, "%s called: %s %s %s\n", __func__, rig_strvfo(vfo), rig_strrmode(mode), buf); - curr->mode = mode; + switch (vfo) + { + case RIG_VFO_A: priv->vfo_a.mode = mode; priv->vfo_a.width = width;break; + + case RIG_VFO_B: priv->vfo_b.mode = mode; priv->vfo_b.width = width;break; + + case RIG_VFO_C: priv->vfo_c.mode = mode; priv->vfo_c.width = width;break; + } if (RIG_PASSBAND_NOCHANGE == width) { RETURNFUNC(RIG_OK); } if (width == RIG_PASSBAND_NORMAL) { - curr->width = rig_passband_normal(rig, mode); + width = curr->width = rig_passband_normal(rig, mode); } - else + switch (vfo) { - curr->width = width; + case RIG_VFO_A: priv->vfo_a.width = width; break; + + case RIG_VFO_B: priv->vfo_b.width = width; break; + + case RIG_VFO_C: priv->vfo_c.width = width; break; } RETURNFUNC(RIG_OK); @@ -475,14 +499,23 @@ static int dummy_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) static int dummy_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width) { struct dummy_priv_data *priv = (struct dummy_priv_data *)rig->state.priv; - channel_t *curr = priv->curr; ENTERFUNC; usleep(CMDSLEEP); rig_debug(RIG_DEBUG_VERBOSE, "%s called: %s\n", __func__, rig_strvfo(vfo)); - *mode = curr->mode; - *width = curr->width; + if (vfo == RIG_VFO_CURR) vfo = rig->state.current_vfo; + + switch(vfo) + { + case RIG_VFO_MAIN: + case RIG_VFO_A: *mode = priv->vfo_a.mode;*width = priv->vfo_a.width; break; + + case RIG_VFO_SUB: + case RIG_VFO_B: *mode = priv->vfo_b.mode;*width = priv->vfo_b.width; break; + + case RIG_VFO_C: *mode = priv->vfo_c.mode;*width = priv->vfo_c.width; break; + } RETURNFUNC(RIG_OK); } @@ -497,6 +530,8 @@ static int dummy_set_vfo(RIG *rig, vfo_t vfo) usleep(CMDSLEEP); rig_debug(RIG_DEBUG_VERBOSE, "%s called: %s\n", __func__, rig_strvfo(vfo)); + if (vfo == RIG_VFO_CURR) vfo = rig->state.current_vfo; + priv->last_vfo = priv->curr_vfo; priv->curr_vfo = vfo; @@ -513,6 +548,8 @@ static int dummy_set_vfo(RIG *rig, vfo_t vfo) case RIG_VFO_B: priv->curr = &priv->vfo_b; break; + case RIG_VFO_C: priv->curr = &priv->vfo_c; break; + case RIG_VFO_MEM: if (curr->channel_num >= 0 && curr->channel_num < NB_CHAN) { @@ -2085,7 +2122,7 @@ struct rig_caps dummy_caps = .copyright = "LGPL", .status = RIG_STATUS_STABLE, .rig_type = RIG_TYPE_OTHER, - .targetable_vfo = RIG_TARGETABLE_PTT | RIG_TARGETABLE_RITXIT, + .targetable_vfo = RIG_TARGETABLE_PTT | RIG_TARGETABLE_RITXIT|RIG_TARGETABLE_FREQ|RIG_TARGETABLE_MODE, .ptt_type = RIG_PTT_RIG, .dcd_type = RIG_DCD_RIG, .port_type = RIG_PORT_NONE, @@ -2250,7 +2287,7 @@ struct rig_caps dummy_no_vfo_caps = .copyright = "LGPL", .status = RIG_STATUS_STABLE, .rig_type = RIG_TYPE_OTHER, - .targetable_vfo = RIG_TARGETABLE_PTT | RIG_TARGETABLE_RITXIT, + .targetable_vfo = RIG_TARGETABLE_PTT | RIG_TARGETABLE_RITXIT|RIG_TARGETABLE_FREQ|RIG_TARGETABLE_MODE, .ptt_type = RIG_PTT_RIG, .dcd_type = RIG_DCD_RIG, .port_type = RIG_PORT_NONE, diff --git a/rigs/icom/frame.c b/rigs/icom/frame.c index c5c2d2568..9832eb9c3 100644 --- a/rigs/icom/frame.c +++ b/rigs/icom/frame.c @@ -281,7 +281,7 @@ int icom_one_transaction(RIG *rig, int cmd, int subcmd, if (frm_len < ACKFRMLEN) { RETURNFUNC(-RIG_EPROTO); } // if we send a bad command we will get back a NAK packet // e.g. fe fe e0 50 fa fd - if (NAK == buf[frm_len - 2]) { RETURNFUNC(-RIG_ERJCTED); } + if (frm_len == 6 && NAK == buf[frm_len - 2]) { RETURNFUNC(-RIG_ERJCTED); } rig_debug(RIG_DEBUG_TRACE, "%s: frm_len=%d, frm_len-1=%02x, frm_len-2=%02x\n", __func__, frm_len, buf[frm_len-1], buf[frm_len-2]); diff --git a/src/misc.c b/src/misc.c index 7e443c7e1..105e8d4be 100644 --- a/src/misc.c +++ b/src/misc.c @@ -566,9 +566,11 @@ static struct { RIG_VFO_MAIN, "Main" }, { RIG_VFO_MAIN_A, "MainA" }, { RIG_VFO_MAIN_B, "MainB" }, + { RIG_VFO_MAIN_C, "MainB" }, { RIG_VFO_SUB, "Sub" }, { RIG_VFO_SUB_A, "SubA" }, { RIG_VFO_SUB_B, "SubB" }, + { RIG_VFO_SUB_C, "SubC" }, { RIG_VFO_NONE, "None" }, { 0xffffff, "" }, }; diff --git a/src/misc.h b/src/misc.h index 517334a42..a3c74f9db 100644 --- a/src/misc.h +++ b/src/misc.h @@ -150,18 +150,24 @@ void errmsg(int err, char *s, const char *func, const char *file, int line); return (rctmp); \ } while(0) -#if 0 // 5.0 - elapsed_ms(&rig->state.cache.time_freqMainC, HAMLIB_ELAPSED_INVALIDATE); -#endif #define CACHE_RESET {\ - elapsed_ms(&rig->state.cache.time_freq, HAMLIB_ELAPSED_INVALIDATE);\ - elapsed_ms(&rig->state.cache.time_freqCurr, HAMLIB_ELAPSED_INVALIDATE);\ elapsed_ms(&rig->state.cache.time_freqMainA, HAMLIB_ELAPSED_INVALIDATE);\ elapsed_ms(&rig->state.cache.time_freqMainB, HAMLIB_ELAPSED_INVALIDATE);\ elapsed_ms(&rig->state.cache.time_freqSubA, HAMLIB_ELAPSED_INVALIDATE);\ elapsed_ms(&rig->state.cache.time_freqSubB, HAMLIB_ELAPSED_INVALIDATE);\ elapsed_ms(&rig->state.cache.time_vfo, HAMLIB_ELAPSED_INVALIDATE);\ - elapsed_ms(&rig->state.cache.time_mode, HAMLIB_ELAPSED_INVALIDATE);\ + elapsed_ms(&rig->state.cache.time_modeMainA, HAMLIB_ELAPSED_INVALIDATE);\ + elapsed_ms(&rig->state.cache.time_modeMainB, HAMLIB_ELAPSED_INVALIDATE);\ + elapsed_ms(&rig->state.cache.time_modeMainC, HAMLIB_ELAPSED_INVALIDATE);\ + elapsed_ms(&rig->state.cache.time_modeSubA, HAMLIB_ELAPSED_INVALIDATE);\ + elapsed_ms(&rig->state.cache.time_modeSubB, HAMLIB_ELAPSED_INVALIDATE);\ + elapsed_ms(&rig->state.cache.time_modeSubC, HAMLIB_ELAPSED_INVALIDATE);\ + elapsed_ms(&rig->state.cache.time_widthMainA, HAMLIB_ELAPSED_INVALIDATE);\ + elapsed_ms(&rig->state.cache.time_widthMainB, HAMLIB_ELAPSED_INVALIDATE);\ + elapsed_ms(&rig->state.cache.time_widthMainC, HAMLIB_ELAPSED_INVALIDATE);\ + elapsed_ms(&rig->state.cache.time_widthSubA, HAMLIB_ELAPSED_INVALIDATE);\ + elapsed_ms(&rig->state.cache.time_widthSubB, HAMLIB_ELAPSED_INVALIDATE);\ + elapsed_ms(&rig->state.cache.time_widthSubC, HAMLIB_ELAPSED_INVALIDATE);\ elapsed_ms(&rig->state.cache.time_ptt, HAMLIB_ELAPSED_INVALIDATE);\ elapsed_ms(&rig->state.cache.time_split, HAMLIB_ELAPSED_INVALIDATE);\ } diff --git a/src/rig.c b/src/rig.c index c719759d8..2745504bb 100644 --- a/src/rig.c +++ b/src/rig.c @@ -1321,19 +1321,70 @@ int HAMLIB_API rig_get_twiddle(RIG *rig, int *seconds) RETURNFUNC(RIG_OK); } -/* caching prototype to be fully implemented in 4.1 */ +static int set_cache_mode(RIG *rig, vfo_t vfo, mode_t mode, pbwidth_t width) +{ + ENTERFUNC; + if (vfo == RIG_VFO_CURR) + { + // if CURR then update this before we figure out the real VFO + vfo = rig->state.current_vfo; + } + // pick a sane default + if (vfo == RIG_VFO_NONE || vfo == RIG_VFO_CURR) vfo = RIG_VFO_A; + switch (vfo) + { + case RIG_VFO_ALL: // we'll use NONE to reset all VFO caches + elapsed_ms(&rig->state.cache.time_modeMainA, HAMLIB_ELAPSED_INVALIDATE); + elapsed_ms(&rig->state.cache.time_modeMainB, HAMLIB_ELAPSED_INVALIDATE); + elapsed_ms(&rig->state.cache.time_modeMainC, HAMLIB_ELAPSED_INVALIDATE); + elapsed_ms(&rig->state.cache.time_widthMainA, HAMLIB_ELAPSED_INVALIDATE); + elapsed_ms(&rig->state.cache.time_widthMainB, HAMLIB_ELAPSED_INVALIDATE); + elapsed_ms(&rig->state.cache.time_widthMainC, HAMLIB_ELAPSED_INVALIDATE); + break; + case RIG_VFO_A: + case RIG_VFO_MAIN: + case RIG_VFO_MAIN_A: + rig->state.cache.modeMainA = mode; + if (width > 0) rig->state.cache.widthMainA = width; + elapsed_ms(&rig->state.cache.time_modeMainA, HAMLIB_ELAPSED_SET); + elapsed_ms(&rig->state.cache.time_widthMainA, HAMLIB_ELAPSED_SET); + break; + case RIG_VFO_B: + case RIG_VFO_SUB: + case RIG_VFO_MAIN_B: + rig->state.cache.modeMainB = mode; + if (width > 0) rig->state.cache.widthMainB = width; + elapsed_ms(&rig->state.cache.time_modeMainB, HAMLIB_ELAPSED_SET); + elapsed_ms(&rig->state.cache.time_widthMainB, HAMLIB_ELAPSED_SET); + break; + case RIG_VFO_C: + case RIG_VFO_MAIN_C: + rig->state.cache.modeMainC = mode; + if (width > 0) rig->state.cache.widthMainC = width; + elapsed_ms(&rig->state.cache.time_modeMainC, HAMLIB_ELAPSED_SET); + elapsed_ms(&rig->state.cache.time_widthMainC, HAMLIB_ELAPSED_SET); + break; + default: + rig_debug(RIG_DEBUG_ERR, "%s: unknown vfo=%s\n", __func__, rig_strvfo(vfo)); + RETURNFUNC(-RIG_EINTERNAL); + } + + RETURNFUNC(RIG_OK); +} + static int set_cache_freq(RIG *rig, vfo_t vfo, freq_t freq) { + ENTERFUNC; rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s, current_vfo=%s\n", __func__, rig_strvfo(vfo), rig_strvfo(rig->state.current_vfo)); if (vfo == RIG_VFO_CURR) { // if CURR then update this before we figure out the real VFO - rig->state.cache.freqCurr = freq; - elapsed_ms(&rig->state.cache.time_freqCurr, HAMLIB_ELAPSED_SET); vfo = rig->state.current_vfo; } + // pick a sane default + if (vfo == RIG_VFO_NONE || vfo == RIG_VFO_CURR) vfo = RIG_VFO_A; rig_debug(RIG_DEBUG_TRACE, "%s: set vfo=%s to freq=%.0f\n", __func__, rig_strvfo(vfo), freq); @@ -1341,17 +1392,22 @@ static int set_cache_freq(RIG *rig, vfo_t vfo, freq_t freq) switch (vfo) { case RIG_VFO_ALL: // we'll use NONE to reset all VFO caches - elapsed_ms(&rig->state.cache.time_freqCurr, HAMLIB_ELAPSED_INVALIDATE); elapsed_ms(&rig->state.cache.time_freqMainA, HAMLIB_ELAPSED_INVALIDATE); elapsed_ms(&rig->state.cache.time_freqMainB, HAMLIB_ELAPSED_INVALIDATE); + elapsed_ms(&rig->state.cache.time_freqMainC, HAMLIB_ELAPSED_INVALIDATE); elapsed_ms(&rig->state.cache.time_freqSubA, HAMLIB_ELAPSED_INVALIDATE); elapsed_ms(&rig->state.cache.time_freqSubB, HAMLIB_ELAPSED_INVALIDATE); + elapsed_ms(&rig->state.cache.time_freqSubC, HAMLIB_ELAPSED_INVALIDATE); elapsed_ms(&rig->state.cache.time_freqMem, HAMLIB_ELAPSED_INVALIDATE); - break; - - case RIG_VFO_CURR: - rig->state.cache.freqCurr = freq; - elapsed_ms(&rig->state.cache.time_freqCurr, HAMLIB_ELAPSED_SET); + elapsed_ms(&rig->state.cache.time_vfo, HAMLIB_ELAPSED_INVALIDATE); + elapsed_ms(&rig->state.cache.time_modeMainA, HAMLIB_ELAPSED_INVALIDATE); + elapsed_ms(&rig->state.cache.time_modeMainB, HAMLIB_ELAPSED_INVALIDATE); + elapsed_ms(&rig->state.cache.time_modeMainC, HAMLIB_ELAPSED_INVALIDATE); + elapsed_ms(&rig->state.cache.time_widthMainA, HAMLIB_ELAPSED_INVALIDATE); + elapsed_ms(&rig->state.cache.time_widthMainB, HAMLIB_ELAPSED_INVALIDATE); + elapsed_ms(&rig->state.cache.time_widthMainC, HAMLIB_ELAPSED_INVALIDATE); + elapsed_ms(&rig->state.cache.time_ptt, HAMLIB_ELAPSED_INVALIDATE); + elapsed_ms(&rig->state.cache.time_split, HAMLIB_ELAPSED_INVALIDATE); break; case RIG_VFO_A: @@ -1368,13 +1424,11 @@ static int set_cache_freq(RIG *rig, vfo_t vfo, freq_t freq) elapsed_ms(&rig->state.cache.time_freqMainB, HAMLIB_ELAPSED_SET); break; -#if 0 // 5.0 - - case RIG_VFO_C: // is there a MainC/SubC we need to cover? + case RIG_VFO_C: + case RIG_VFO_MAIN_C: rig->state.cache.freqMainC = freq; elapsed_ms(&rig->state.cache.time_freqMainC, HAMLIB_ELAPSED_SET); break; -#endif case RIG_VFO_SUB_A: rig->state.cache.freqSubA = freq; @@ -1386,6 +1440,11 @@ static int set_cache_freq(RIG *rig, vfo_t vfo, freq_t freq) elapsed_ms(&rig->state.cache.time_freqSubB, HAMLIB_ELAPSED_SET); break; + case RIG_VFO_SUB_C: + rig->state.cache.freqSubC = freq; + elapsed_ms(&rig->state.cache.time_freqSubC, HAMLIB_ELAPSED_SET); + break; + case RIG_VFO_MEM: rig->state.cache.freqMem = freq; elapsed_ms(&rig->state.cache.time_freqMem, HAMLIB_ELAPSED_SET); @@ -1400,65 +1459,84 @@ static int set_cache_freq(RIG *rig, vfo_t vfo, freq_t freq) RETURNFUNC(RIG_OK); } -/* caching prototype to be fully implemented in 4.1 */ -static int get_cache_freq(RIG *rig, vfo_t vfo, freq_t *freq, int *cache_ms) +int rig_get_cache(RIG *rig, vfo_t vfo, freq_t *freq, int *cache_ms_freq, rmode_t *mode, int *cache_ms_mode, pbwidth_t *width, int *cache_ms_width) { + ENTERFUNC; rig_debug(RIG_DEBUG_TRACE, "%s: vfo=%s, current_vfo=%s\n", __func__, rig_strvfo(vfo), rig_strvfo(rig->state.current_vfo)); if (vfo == RIG_VFO_CURR) { vfo = rig->state.current_vfo; } + // pick a sane default + if (vfo == RIG_VFO_CURR || vfo == RIG_VFO_NONE) { vfo = RIG_VFO_A; } // VFO_C to be implemented switch (vfo) { - case RIG_VFO_CURR: - *freq = rig->state.cache.freqCurr; - *cache_ms = elapsed_ms(&rig->state.cache.time_freqCurr, HAMLIB_ELAPSED_GET); - break; - case RIG_VFO_A: case RIG_VFO_MAIN: case RIG_VFO_MAIN_A: *freq = rig->state.cache.freqMainA; - *cache_ms = elapsed_ms(&rig->state.cache.time_freqMainA, HAMLIB_ELAPSED_GET); + *mode = rig->state.cache.modeMainA; + *width = rig->state.cache.widthMainA; + *cache_ms_freq = elapsed_ms(&rig->state.cache.time_freqMainA, HAMLIB_ELAPSED_GET); + *cache_ms_mode = elapsed_ms(&rig->state.cache.time_modeMainA, HAMLIB_ELAPSED_GET); + *cache_ms_width = elapsed_ms(&rig->state.cache.time_widthMainA, HAMLIB_ELAPSED_GET); break; case RIG_VFO_B: case RIG_VFO_SUB: *freq = rig->state.cache.freqMainB; - *cache_ms = elapsed_ms(&rig->state.cache.time_freqMainB, HAMLIB_ELAPSED_GET); + *mode = rig->state.cache.modeMainB; + *width = rig->state.cache.widthMainB; + *cache_ms_freq = elapsed_ms(&rig->state.cache.time_freqMainB, HAMLIB_ELAPSED_GET); + *cache_ms_mode = elapsed_ms(&rig->state.cache.time_modeMainB, HAMLIB_ELAPSED_GET); + *cache_ms_width = elapsed_ms(&rig->state.cache.time_widthMainB, HAMLIB_ELAPSED_GET); break; case RIG_VFO_SUB_A: *freq = rig->state.cache.freqSubA; - *cache_ms = elapsed_ms(&rig->state.cache.time_freqSubA, HAMLIB_ELAPSED_GET); + *mode = rig->state.cache.modeSubA; + *width = rig->state.cache.widthSubA; + *cache_ms_freq = elapsed_ms(&rig->state.cache.time_freqSubA, HAMLIB_ELAPSED_GET); + *cache_ms_mode = elapsed_ms(&rig->state.cache.time_modeSubA, HAMLIB_ELAPSED_GET); + *cache_ms_width = elapsed_ms(&rig->state.cache.time_widthSubA, HAMLIB_ELAPSED_GET); break; case RIG_VFO_SUB_B: *freq = rig->state.cache.freqSubB; - *cache_ms = elapsed_ms(&rig->state.cache.time_freqSubB, HAMLIB_ELAPSED_GET); + *mode = rig->state.cache.modeSubB; + *width = rig->state.cache.widthSubB; + *cache_ms_freq = elapsed_ms(&rig->state.cache.time_freqSubB, HAMLIB_ELAPSED_GET); + *cache_ms_mode = elapsed_ms(&rig->state.cache.time_modeSubB, HAMLIB_ELAPSED_GET); + *cache_ms_width = elapsed_ms(&rig->state.cache.time_widthSubB, HAMLIB_ELAPSED_GET); break; -#if 0 // 5.0 - case RIG_VFO_C: //case RIG_VFO_MAINC: // not used by any rig yet *freq = rig->state.cache.freqMainC; - *cache_ms = elapsed_ms(&rig->state.cache.time_freqMainC, HAMLIB_ELAPSED_GET); + *mode = rig->state.cache.modeMainC; + *width = rig->state.cache.widthMainC; + *cache_ms_freq = elapsed_ms(&rig->state.cache.time_freqMainC, HAMLIB_ELAPSED_GET); + *cache_ms_mode = elapsed_ms(&rig->state.cache.time_modeMainC, HAMLIB_ELAPSED_GET); + *cache_ms_width = elapsed_ms(&rig->state.cache.time_widthMainC, HAMLIB_ELAPSED_GET); break; -#endif -#if 0 // no known rigs use this yet - - case RIG_VFO_SUBC: + case RIG_VFO_SUB_C: *freq = rig->state.cache.freqSubC; - *cache_ms = rig->state.cache.time_freqSubC; + *mode = rig->state.cache.modeSubC; + *width = rig->state.cache.widthSubC; + *cache_ms_freq = elapsed_ms(&rig->state.cache.time_freqSubC, HAMLIB_ELAPSED_GET); + *cache_ms_mode = elapsed_ms(&rig->state.cache.time_modeSubC, HAMLIB_ELAPSED_GET); + *cache_ms_width = elapsed_ms(&rig->state.cache.time_widthSubC, HAMLIB_ELAPSED_GET); break; -#endif case RIG_VFO_MEM: *freq = rig->state.cache.freqMem; - *cache_ms = elapsed_ms(&rig->state.cache.time_freqMem, HAMLIB_ELAPSED_GET); + *mode = rig->state.cache.modeMem; + *width = rig->state.cache.widthMem; + *cache_ms_freq = elapsed_ms(&rig->state.cache.time_freqMem, HAMLIB_ELAPSED_GET); + *cache_ms_mode = elapsed_ms(&rig->state.cache.time_modeMem, HAMLIB_ELAPSED_GET); + *cache_ms_width = elapsed_ms(&rig->state.cache.time_widthMem, HAMLIB_ELAPSED_GET); break; default: @@ -1591,7 +1669,7 @@ int HAMLIB_API rig_set_freq(RIG *rig, vfo_t vfo, freq_t freq) if (retcode != RIG_OK) { RETURNFUNC(retcode); } - set_cache_freq(rig, RIG_VFO_ALL, (freq_t)0); + set_cache_freq(rig, vfo, (freq_t)0); if (caps->get_freq) { @@ -1679,7 +1757,6 @@ int HAMLIB_API rig_set_freq(RIG *rig, vfo_t vfo, freq_t freq) #endif ) { - elapsed_ms(&rig->state.cache.time_freq, HAMLIB_ELAPSED_INVALIDATE); set_cache_freq(rig, RIG_VFO_ALL, (freq_t)0); retcode = rig_get_freq(rig, vfo, &freq_new); @@ -1697,12 +1774,7 @@ int HAMLIB_API rig_set_freq(RIG *rig, vfo_t vfo, freq_t freq) // update our current freq too if (vfo == RIG_VFO_CURR || vfo == rig->state.current_vfo) { rig->state.current_freq = freq_new; } - - elapsed_ms(&(rig->state.cache.time_freq), HAMLIB_ELAPSED_SET); - rig->state.cache.freq = freq_new; - //future 4.1 caching set_cache_freq(rig, vfo, freq_new); - rig->state.cache.vfo_freq = vfo; RETURNFUNC(retcode); } @@ -1728,8 +1800,9 @@ int HAMLIB_API rig_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) { const struct rig_caps *caps; int retcode; - int cache_ms; vfo_t curr_vfo; + rmode_t mode; + pbwidth_t width; rig_debug(RIG_DEBUG_VERBOSE, "%s called vfo=%s\n", __func__, rig_strvfo(vfo)); @@ -1757,7 +1830,8 @@ int HAMLIB_API rig_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) rig->state.cache.split, rig->state.cache.satmode, rig_strvfo(rig->state.tx_vfo)); // always return the cached freq for this clause - get_cache_freq(rig, vfo, freq, &cache_ms); + int cache_ms_freq, cache_ms_mode, cache_ms_width; + rig_get_cache(rig, vfo, freq, &cache_ms_freq, &mode, &cache_ms_mode, &width, &cache_ms_width); RETURNFUNC(RIG_OK); } @@ -1787,26 +1861,21 @@ int HAMLIB_API rig_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) } } + int cache_ms_freq, cache_ms_mode, cache_ms_width; + rig_get_cache(rig, vfo, freq, &cache_ms_freq, &mode, &cache_ms_mode, &width, &cache_ms_width); + rig_debug(RIG_DEBUG_TRACE, "%s: cache check1 age=%dms\n", __func__, cache_ms_freq); - //future 4.1 caching - cache_ms = 10000; - get_cache_freq(rig, vfo, freq, &cache_ms); - rig_debug(RIG_DEBUG_TRACE, "%s: cache check1 age=%dms\n", __func__, cache_ms); - //future 4.1 caching needs to check individual VFO timeouts - //cache_ms = elapsed_ms(&rig->state.cache.time_freq, HAMLIB_ELAPSED_GET); - //rig_debug(RIG_DEBUG_TRACE, "%s: cache check2 age=%dms\n", __func__, cache_ms); - - if (freq != 0 && cache_ms < rig->state.cache.timeout_ms) + if (freq != 0 && cache_ms_freq < rig->state.cache.timeout_ms) { rig_debug(RIG_DEBUG_TRACE, "%s: %s cache hit age=%dms, freq=%.0f\n", __func__, - rig_strvfo(vfo), cache_ms, *freq); + rig_strvfo(vfo), cache_ms_freq, *freq); RETURNFUNC(RIG_OK); } else { rig_debug(RIG_DEBUG_TRACE, - "%s: cache miss age=%dms, cached_vfo=%s, asked_vfo=%s\n", __func__, cache_ms, - rig_strvfo(rig->state.cache.vfo_freq), rig_strvfo(vfo)); + "%s: cache miss age=%dms, cached_vfo=%s, asked_vfo=%s\n", __func__, cache_ms_freq, + rig_strvfo(vfo), rig_strvfo(vfo)); } caps = rig->caps; @@ -1834,15 +1903,15 @@ int HAMLIB_API rig_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) // sometimes a network rig like FLRig will return freq=0 // so we'll just reuse the cache for that condition if (*freq == 0) { - *freq = rig->state.cache.freq; + rmode_t mode; + pbwidth_t width; + int freq_ms,mode_ms,width_ms; + rig_get_cache(rig,vfo,freq,&freq_ms,&mode,&mode_ms,&width,&width_ms); } if (retcode == RIG_OK) { - rig->state.cache.freq = *freq; - //future 4.1 caching set_cache_freq(rig, vfo, *freq); - rig->state.cache.vfo_freq = *freq; } } else @@ -1867,13 +1936,7 @@ int HAMLIB_API rig_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) if (RIG_OK == retcode) { - cache_ms = elapsed_ms(&(rig->state.cache.time_freq), HAMLIB_ELAPSED_SET); - rig_debug(RIG_DEBUG_TRACE, "%s: cache reset age=%dms, vfo=%s, freq=%.0f\n", - __func__, cache_ms, rig_strvfo(vfo), *freq); - rig->state.cache.freq = *freq; - //future 4.1 caching set_cache_freq(rig, vfo, *freq); - rig->state.cache.vfo_freq = vfo; /* return the first error code */ retcode = rc2; } @@ -1896,14 +1959,7 @@ int HAMLIB_API rig_get_freq(RIG *rig, vfo_t vfo, freq_t *freq) *freq += rig->state.lo_freq; } - - cache_ms = elapsed_ms(&(rig->state.cache.time_freq), HAMLIB_ELAPSED_SET); - rig_debug(RIG_DEBUG_TRACE, "%s: cache reset age=%dms, vfo=%s, freq=%.0f\n", - __func__, cache_ms, rig_strvfo(vfo), *freq); - rig->state.cache.freq = *freq; - //future 4.1 caching set_cache_freq(rig, vfo, *freq); - rig->state.cache.vfo_freq = vfo; RETURNFUNC(retcode); } @@ -2010,25 +2066,10 @@ int HAMLIB_API rig_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width) } } - if (retcode == RIG_OK - && (vfo == RIG_VFO_CURR || vfo == rig->state.current_vfo)) - { - rig->state.current_mode = mode; - rig->state.current_width = width; - } - - if (vfo == RIG_VFO_B || vfo == RIG_VFO_SUB || vfo == RIG_VFO_MAIN_B) - { - rig->state.cache.mode = mode; - } - else - { - rig->state.cache.modeB = mode; - } - - rig->state.cache.vfo_mode = mode; // is this still needed? - elapsed_ms(&rig->state.cache.time_mode, HAMLIB_ELAPSED_SET); + if (retcode != RIG_OK) RETURNFUNC(retcode); + set_cache_mode(rig,vfo,mode,width); + RETURNFUNC(retcode); } @@ -2059,7 +2100,7 @@ int HAMLIB_API rig_get_mode(RIG *rig, { const struct rig_caps *caps; int retcode; - int cache_ms; + freq_t freq; ENTERFUNC; @@ -2075,26 +2116,20 @@ int HAMLIB_API rig_get_mode(RIG *rig, RETURNFUNC(-RIG_ENAVAIL); } - cache_ms = elapsed_ms(&rig->state.cache.time_mode, HAMLIB_ELAPSED_GET); + int cache_ms_freq, cache_ms_mode, cache_ms_width; + rig_get_cache(rig, vfo, &freq, &cache_ms_freq, mode, &cache_ms_mode, width, &cache_ms_width); rig_debug(RIG_DEBUG_TRACE, "%s: %s cache check age=%dms\n", __func__, - rig_strvfo(vfo), cache_ms); + rig_strvfo(vfo), cache_ms_freq); - if (cache_ms < rig->state.cache.timeout_ms && rig->state.cache.vfo_mode == vfo) + if (cache_ms_mode < rig->state.cache.timeout_ms || cache_ms_width < rig->state.cache.timeout_ms) { - rig_debug(RIG_DEBUG_TRACE, "%s: cache hit age=%dms\n", __func__, cache_ms); - *mode = rig->state.cache.mode; - *width = rig->state.cache.width; - - if (vfo == RIG_VFO_B || vfo == RIG_VFO_SUB || vfo == RIG_VFO_MAIN_B) - { - *width = rig->state.cache.widthB; - } + rig_debug(RIG_DEBUG_TRACE, "%s: cache hit age mode=%dms, width=%dms\n", __func__, cache_ms_mode, cache_ms_width); RETURNFUNC(RIG_OK); } else { - rig_debug(RIG_DEBUG_TRACE, "%s: cache miss age=%dms\n", __func__, cache_ms); + rig_debug(RIG_DEBUG_TRACE, "%s: cache miss age mode=%dms, width=%dms\n", __func__, cache_ms_mode, cache_ms_width); } if ((caps->targetable_vfo & RIG_TARGETABLE_MODE) @@ -2149,23 +2184,7 @@ int HAMLIB_API rig_get_mode(RIG *rig, *width = rig_passband_normal(rig, *mode); } - rig->state.cache.mode = *mode; - - if (vfo == RIG_VFO_B || vfo == RIG_VFO_SUB || vfo == RIG_VFO_MAIN_B) - { - rig->state.cache.widthB = *width; - - if (*width == 0) { *width = rig->state.cache.width; } - - rig->state.cache.modeB = vfo; - } - else - { - rig->state.cache.width = *width; - rig->state.cache.vfo_mode = vfo; - } - - cache_ms = elapsed_ms(&rig->state.cache.time_mode, HAMLIB_ELAPSED_SET); + set_cache_mode(rig,vfo,*mode,*width); RETURNFUNC(retcode); } @@ -2405,14 +2424,19 @@ int HAMLIB_API rig_set_vfo(RIG *rig, vfo_t vfo) __func__, rigerror(retcode)); } - else // don't expire cache if we just read it - { - elapsed_ms(&rig->state.cache.time_freq, HAMLIB_ELAPSED_INVALIDATE); + else + { // if no get_freq clear all cache to be sure we refresh whatever we can + set_cache_freq(rig, RIG_VFO_ALL, (freq_t)0); } // expire several cached items when we switch VFOs elapsed_ms(&rig->state.cache.time_vfo, HAMLIB_ELAPSED_INVALIDATE); - elapsed_ms(&rig->state.cache.time_mode, HAMLIB_ELAPSED_INVALIDATE); + elapsed_ms(&rig->state.cache.time_modeMainA, HAMLIB_ELAPSED_INVALIDATE); + elapsed_ms(&rig->state.cache.time_modeMainB, HAMLIB_ELAPSED_INVALIDATE); + elapsed_ms(&rig->state.cache.time_modeMainC, HAMLIB_ELAPSED_INVALIDATE); + elapsed_ms(&rig->state.cache.time_widthMainA, HAMLIB_ELAPSED_INVALIDATE); + elapsed_ms(&rig->state.cache.time_widthMainB, HAMLIB_ELAPSED_INVALIDATE); + elapsed_ms(&rig->state.cache.time_widthMainC, HAMLIB_ELAPSED_INVALIDATE); rig_debug(RIG_DEBUG_TRACE, "%s: return %d, vfo=%s\n", __func__, retcode, rig_strvfo(vfo)); diff --git a/tests/Makefile.am b/tests/Makefile.am index 7d5ff2172..86381d7db 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -10,7 +10,7 @@ DISTCLEANFILES = rigctl.log rigctl.sum testbcd.log testbcd.sum hamlibdatetime.h bin_PROGRAMS = rigctl rigctld rigmem rigsmtr rigswr rotctl rotctld rigctlcom ampctl ampctld -check_PROGRAMS = dumpmem testrig testrigopen testrigcaps testtrn testbcd testfreq listrigs testloc rig_bench cachetest cachetest2 +check_PROGRAMS = dumpmem testrig testrigopen testrigcaps testtrn testbcd testfreq listrigs testloc rig_bench testcache cachetest cachetest2 RIGCOMMONSRC = rigctl_parse.c rigctl_parse.h dumpcaps.c uthash.h hamlibdatetime.h ROTCOMMONSRC = rotctl_parse.c rotctl_parse.h dumpcaps_rot.c uthash.h hamlibdatetime.h @@ -77,7 +77,7 @@ EXTRA_DIST = rigmatrix_head.html rig_split_lst.awk testctld.pl testrotctld.pl \ hamlibdatetime.h.in # Support 'make check' target for simple tests -check_SCRIPTS = testrig.sh testfreq.sh testbcd.sh testloc.sh testrigcaps.sh +check_SCRIPTS = testrig.sh testfreq.sh testbcd.sh testloc.sh testrigcaps.sh testcache.sh TESTS = $(check_SCRIPTS) @@ -102,6 +102,10 @@ testrigcaps.sh: echo './testrigcaps' > testrigcaps.sh chmod +x ./testrigcaps.sh +testcache.sh: + echo './testcache 1' > testcache.sh + chmod +x ./testcache.sh + # If we have a .git directory then we will generate the hamlibdate.h # file and replace it if it is different. Fall back to a copy of a # generic hamlibdatetime.h.in in the source tree. Build looks in build @@ -126,4 +130,4 @@ FORCE: dist-hook: test ./ -ef $(srcdir)/ || test ! -f hamlibdatetime.h || cp -f hamlibdatetime.h $(srcdir)/ -CLEANFILES = testrig.sh testfreq.sh testbcd.sh testloc.sh testrigcaps.sh +CLEANFILES = testrig.sh testfreq.sh testbcd.sh testloc.sh testrigcaps.sh testcache.sh diff --git a/tests/testcache.c b/tests/testcache.c new file mode 100644 index 000000000..853f009a1 --- /dev/null +++ b/tests/testcache.c @@ -0,0 +1,161 @@ +/* This program does a check of cache timing and hit/miss + * By Michael Black W9MDB + * Used in testing caching effects that have been added + * To compile: + * gcc -I../src -I../include -g -o cachetest3 cachetest3.c -lhamlib + * To run: + * ./cachetest3 + */ + +#include +#include +#include +#include +#include +//#include "misc.h" + + +int main(int argc, char *argv[]) +{ + RIG *my_rig; + char *rig_file, *info_buf; + int retcode; + int model; + int cache_timeout = 0; + + model = 1; // we'll just use the dummy rig by default + rig_file = "127.0.0.1:4532"; // default if we use model#2 + + if (argc == 2) + { + model = atoi(argv[1]); + + if (model == 1) { rig_file = ""; } + } + + if (argc == 3) + { + rig_file = argv[2]; + } + + printf("Model#%d\n", model); + rig_set_debug(RIG_DEBUG_WARN); + + /* Instantiate a rig */ + my_rig = rig_init(model); // your rig model. + + /* Set up serial port, baud rate */ + + strncpy(my_rig->state.rigport.pathname, rig_file, HAMLIB_FILPATHLEN - 1); + + /* Open my rig */ + retcode = rig_open(my_rig); + + if (retcode != RIG_OK) + { + fprintf(stderr, "%s: rig_open failed %s\n", __func__, + rigerror(retcode)); + return 1; + } + + rig_set_cache_timeout_ms(my_rig, HAMLIB_CACHE_ALL, cache_timeout); + /* Give me ID info, e.g., firmware version. */ + info_buf = (char *)rig_get_info(my_rig); + + if (info_buf) + { + strtok(info_buf, "\r\n"); + printf("Rig_info: '%s'\n", info_buf); + } + + vfo_t vfo; + retcode = rig_get_vfo(my_rig, &vfo); + + if (vfo != RIG_VFO_A) + { + printf("VFO != VFOA\n"); + exit(1); + } + + printf("VFO: %s\n", rig_strvfo(vfo)); + freq_t freqA, freqB, freqC; + rmode_t modeA, modeB, modeC; + pbwidth_t widthA, widthB, widthC; + int freq_ms, mode_ms, width_ms; + rig_get_cache(my_rig, vfo, &freqA, &freq_ms, &modeA, &mode_ms, &widthA, + &width_ms); + printf("freq=%.0f cache times=%d,%d,%d\n", freqA, freq_ms, mode_ms, width_ms); + rig_get_cache(my_rig, vfo, &freqA, &freq_ms, &modeA, &mode_ms, &widthA, + &width_ms); + printf("freq=%.0f cache times=%d,%d,%d\n", freqA, freq_ms, mode_ms, width_ms); + rig_set_freq(my_rig, RIG_VFO_A, 14074055); + rig_set_freq(my_rig, RIG_VFO_B, 14074155); + rig_set_freq(my_rig, RIG_VFO_C, 14074255); + rig_set_mode(my_rig, RIG_VFO_A, RIG_MODE_USB, 1000); + rig_set_mode(my_rig, RIG_VFO_B, RIG_MODE_LSB, 2000); + rig_set_mode(my_rig, RIG_VFO_C, RIG_MODE_PKTUSB, 3000); + + rig_get_cache(my_rig, RIG_VFO_A, &freqA, &freq_ms, &modeA, &mode_ms, &widthA, + &width_ms); + printf("VFOA freq=%.0f, mode=%s, width=%d, cache times=%d,%d,%d\n", freqA, + rig_strrmode(modeA), (int)widthA, freq_ms, mode_ms, width_ms); + + rig_get_cache(my_rig, RIG_VFO_B, &freqB, &freq_ms, &modeB, &mode_ms, &widthB, + &width_ms); + printf("VFOB freq=%.0f, mode=%s, width=%d, cache times=%d,%d,%d\n", freqB, + rig_strrmode(modeB), (int)widthB, freq_ms, mode_ms, width_ms); + + rig_get_cache(my_rig, RIG_VFO_C, &freqC, &freq_ms, &modeC, &mode_ms, &widthC, + &width_ms); + printf("VFOC freq=%.0f, mode=%s, width=%d, cache times=%d,%d,%d\n", freqC, + rig_strrmode(modeC), (int)widthC, freq_ms, mode_ms, width_ms); + + if (freqA != 14074000) { printf("freqA == %.1f\n", freqA); exit(1); } + + if (modeA != RIG_MODE_USB) { printf("modeA = %s\n", rig_strrmode(modeA)); exit(1); } + + if (widthA != 1000) { printf("widthA = %d\n", (int)widthA); exit(1); } + + if (freqB != 14074100) { printf("freqB = %.1f\n", freqB); exit(1); } + + if (modeB != RIG_MODE_LSB) { printf("modeB = %s\n", rig_strrmode(modeB)); exit(1); } + + if (widthB != 2000) { printf("widthB = %d\n", (int)widthB); exit(1); } + + if (freqC != 14074200) { printf("freqC = %.1f\n", freqC); exit(1); } + + if (modeC != RIG_MODE_PKTUSB) { printf("modeC = %s\n", rig_strrmode(modeC)); exit(1); } + + if (widthC != 3000) { printf("widthC = %d\n", (int)widthC); exit(1); } + + printf("PTT ON\n"); + rig_set_ptt(my_rig,RIG_VFO_CURR,RIG_PTT_ON); + ptt_t ptt; + printf("PTT get ptt ON\n"); + rig_get_ptt(my_rig,RIG_VFO_CURR,&ptt); + if (ptt != RIG_PTT_ON) { printf("ptt != ON\n"); exit(1); } + hl_usleep(1000*1000); + rig_get_ptt(my_rig,RIG_VFO_CURR,&ptt); + printf("PTT get ptt ON\n"); + if (ptt != RIG_PTT_ON) { printf("ptt != ON\n"); exit(1); } + printf("PTT ptt OFF\n"); + rig_set_ptt(my_rig,RIG_VFO_CURR,RIG_PTT_OFF); + if (ptt != RIG_PTT_ON) { printf("ptt != ON\n"); exit(1); } + rig_get_ptt(my_rig,RIG_VFO_CURR,&ptt); + printf("PTT get ptt OFF\n"); + + vfo_t tx_vfo; + split_t split; + rig_get_split_vfo(my_rig,RIG_VFO_A,&split, &tx_vfo); + printf("split=%d, tx_vfo=%s\n", split, rig_strvfo(tx_vfo)); + if (split !=0 || tx_vfo != RIG_VFO_A) { printf("split#1 failed\n"); exit(1); } + rig_set_split_vfo(my_rig,RIG_VFO_A,RIG_SPLIT_ON,RIG_VFO_B); + hl_usleep(1000*1000); + rig_get_split_vfo(my_rig,RIG_VFO_A,&split,&tx_vfo); + printf("split=%d, tx_vfo=%s\n", split, rig_strvfo(tx_vfo)); + if (split != RIG_SPLIT_ON || tx_vfo != RIG_VFO_B) { printf("split#2 failed\n"); exit(1); } + + printf("All OK\n"); + rig_close(my_rig); + return 0 ; +};