From ff9c1badfaf3772c20cc131d64115ce560d184a5 Mon Sep 17 00:00:00 2001 From: Stephane Fillod Date: Sat, 6 Mar 2021 10:14:17 +0100 Subject: [PATCH] prm80 : more feature coverage and fixes Tested-by: Claus --- rigs/prm80/prm80.c | 263 +++++++++++++++++++++++++++++++++++++------ rigs/prm80/prm80.h | 4 +- rigs/prm80/prm8060.c | 34 +++++- 3 files changed, 259 insertions(+), 42 deletions(-) diff --git a/rigs/prm80/prm80.c b/rigs/prm80/prm80.c index 93df5af26..8b9e2a8bb 100644 --- a/rigs/prm80/prm80.c +++ b/rigs/prm80/prm80.c @@ -551,33 +551,19 @@ static int hhtoi(const char *p) return (int)strtol(buf, NULL, 16); } -/* - * prm80_get_channel - * Assumes rig!=NULL +/** + * Get system state [E] from rig into \a statebuf */ -int prm80_get_channel(RIG *rig, vfo_t vfo, channel_t *chan, int read_only) +static int prm80_read_system_state(hamlib_port_t *rigport, char *statebuf) { - struct prm80_priv_data *priv = (struct prm80_priv_data *)rig->state.priv; - struct rig_state *rs = &rig->state; - char statebuf[BUFSZ]; char *p; - int ret, chanstate, mode_byte, lock_byte; - - if (chan->vfo == RIG_VFO_MEM) - { - ret = prm80_set_mem(rig, RIG_VFO_CURR, chan->channel_num); - - if (ret != RIG_OK) - { - return ret; - } - } + int ret; // Get rid of possible prompt sent by the rig - rig_flush(&rs->rigport); + rig_flush(rigport); /* [E] = Show system state */ - ret = write_block(&rs->rigport, "E", 1); + ret = write_block(rigport, "E", 1); if (ret < 0) { @@ -585,7 +571,7 @@ int prm80_get_channel(RIG *rig, vfo_t vfo, channel_t *chan, int read_only) } // The response length is fixed - ret = read_block(&rs->rigport, statebuf, 20); + ret = read_block(rigport, statebuf, 20); if (ret < 0) { @@ -610,9 +596,13 @@ int prm80_get_channel(RIG *rig, vfo_t vfo, channel_t *chan, int read_only) { int left_to_read = (p - statebuf) + 1; memmove(statebuf, p + 1, 20 - left_to_read); - ret = read_block(&rs->rigport, statebuf + 20 - left_to_read, left_to_read); + ret = read_block(rigport, statebuf + 20 - left_to_read, left_to_read); - if (ret >= 0) + if (ret < 0) + { + return ret; + } + else if (ret >= 0) { statebuf[20] = '\0'; } @@ -621,6 +611,38 @@ int prm80_get_channel(RIG *rig, vfo_t vfo, channel_t *chan, int read_only) statebuf); } + return RIG_OK; +} + + +/* + * prm80_get_channel + * Assumes rig!=NULL + */ +int prm80_get_channel(RIG *rig, vfo_t vfo, channel_t *chan, int read_only) +{ + struct prm80_priv_data *priv = (struct prm80_priv_data *)rig->state.priv; + struct rig_state *rs = &rig->state; + char statebuf[BUFSZ]; + int ret, chanstate, mode_byte, lock_byte; + + if (chan->vfo == RIG_VFO_MEM) + { + ret = prm80_set_mem(rig, RIG_VFO_CURR, chan->channel_num); + + if (ret != RIG_OK) + { + return ret; + } + } + + ret = prm80_read_system_state(&rs->rigport, statebuf); + + if (ret != RIG_OK) + { + return ret; + } + /* (Mode-Chan-Chanstate-Sql-Vol-Lock-RX freq-TX freq). */ /* Examples: 1240080AFF0033F02D40 or 14000C00FD0079708020 */ @@ -654,10 +676,12 @@ int prm80_get_channel(RIG *rig, vfo_t vfo, channel_t *chan, int read_only) chan->levels[LVL_AF].f = ((float)(hhtoi(statebuf + 8) >> 4)) / 15.; chan->levels[LVL_RFPOWER].f = (mode_byte & 0x02) ? 1.0 : 0.0; + chan->funcs = 0; chan->funcs |= (chanstate & 0x02) ? RIG_FUNC_REV : 0; lock_byte = hhtoi(statebuf + 10) & 0x0f; - chan->funcs = (lock_byte != 0) ? RIG_FUNC_LOCK : 0; + chan->funcs |= (lock_byte & 0x05) ? RIG_FUNC_LOCK : 0; + chan->funcs |= (lock_byte & 0x08) ? RIG_FUNC_MUTE : 0; chan->freq = ((hhtoi(statebuf + 12) << 8) + hhtoi(statebuf + 14)) * FREQ_DIV + RX_IF_OFFSET; @@ -805,7 +829,8 @@ int prm80_set_channel(RIG *rig, vfo_t vfo, const channel_t *chan) #endif - ret = prm80_set_func(rig, vfo, RIG_FUNC_LOCK, chan->funcs & RIG_FUNC_LOCK); + ret = prm80_set_func(rig, vfo, RIG_FUNC_LOCK, + !!(chan->funcs & RIG_FUNC_LOCK)); if (ret != RIG_OK) { @@ -817,15 +842,21 @@ int prm80_set_channel(RIG *rig, vfo_t vfo, const channel_t *chan) } -// TODO FUNC_REV ? +// TODO FUNC_REV through Channel state byte ? +// TODO "Read-Modify-Write" (or shadowing in priv area) of the lock bits int prm80_set_func(RIG *rig, vfo_t vfo, setting_t func, int status) { int ret; if (func & RIG_FUNC_LOCK) { - /* Lock keys/TX/Vol */ - ret = prm80_transaction(rig, "K", (status != 0) ? "03" : "00", 1); + /* Lock keys(b0)/Vol(b2) */ + ret = prm80_transaction(rig, "K", (status != 0) ? "05" : "00", 1); + } + else if (func & RIG_FUNC_MUTE) + { + /* Lock RX(b3) */ + ret = prm80_transaction(rig, "K", (status != 0) ? "08" : "00", 1); } else { @@ -850,7 +881,7 @@ int prm80_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) return ret; } - *status = (chan.funcs & func); + *status = !!(chan.funcs & func); return RIG_OK; } @@ -862,6 +893,7 @@ int prm80_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status) int prm80_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) { char buf[BUFSZ]; + int ret, mode_byte; // do some clamping, all levels are float values. if (val.f < 0.0) @@ -886,19 +918,28 @@ int prm80_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) return prm80_transaction(rig, "F", buf, 1); case RIG_LEVEL_RFPOWER: - // TODO : modify the Mode byte b1 ? -#if 0 /* Current mode: ; b0: Squelch b1: power ; b2: Squelch open b3: TX ; b4: PLL locked b5: Long press memorize ; b6: Debouncing in effect b7: LCD refresh */ - // TODO perform a "Read-Modify-Write" of the mode_byte - mode_byte = 0x10; - mode_byte |= (chan->levels[LVL_RFPOWER].f == 0.) ? 0 : 0x02; -#endif - return -RIG_ENIMPL; + // Perform a "Read-Modify-Write" of the mode_byte + ret = prm80_read_system_state(&rig->state.rigport, buf); + + if (ret != RIG_OK) + { + return ret; + } + + prm80_wait_for_prompt(&rig->state.rigport); + + mode_byte = hhtoi(buf); + mode_byte &= ~0x02; + mode_byte |= (val.f == 0.) ? 0 : 0x02; + sprintf(buf, "%02X", (unsigned)mode_byte); + + return prm80_transaction(rig, "D", buf, 1); default: rig_debug(RIG_DEBUG_ERR, "%s: unsupported set_level %s\n", __func__, @@ -909,6 +950,106 @@ int prm80_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val) return RIG_OK; } +/* + * get_level RIG_LEVEL_RAWSTR + */ +static int prm80_get_rawstr_RAM(RIG *rig, value_t *val) +{ + char buf[BUFSZ]; + struct rig_state *rs = &rig->state; + int ret, i; + + /* [U] = Print 80c552 internal RAM. */ + + // Send cmd, Wait for colon prompt, but then send nothing + ret = prm80_transaction(rig, "U", "", 0); + + if (ret < 0) + { + return ret; + } + + // Read CRLF + ret = read_string(&rs->rigport, buf, BUFSZ, "\n", 1); + + if (ret < 0) + { + return ret; + } + + // (16 lines of 16 bytes each) + + // According to prm.a51, the rssi_hold variable is in RAM at RAM+35. + // The RAM base is at 030h. + +#define RSSI_HOLD_ADDR (0x30 + 35) // = 0x53 + + for (i = 0; i < (RSSI_HOLD_ADDR / 16) + 1; i++) + { + ret = read_string(&rs->rigport, buf, BUFSZ, "\n", 1); + + if (ret < 0) + { + return ret; + } + } + + // A line looks like this + // "$50 : 00 01 02 53 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\r\n" + + val->i = hhtoi(buf + 6 + 3 * (RSSI_HOLD_ADDR % 16)); + + // discard the remaining content of RAM print + for (i = 0; i < (16 - RSSI_HOLD_ADDR / 16) - 1; i++) + { + ret = read_string(&rs->rigport, buf, BUFSZ, "\n", 1); + } + + prm80_wait_for_prompt(&rs->rigport); + + return RIG_OK; +} + +/* + * get_level RIG_LEVEL_RAWSTR + */ +static int prm80_get_rawstr(RIG *rig, value_t *val) +{ + char buf[BUFSZ]; + struct rig_state *rs = &rig->state; + int ret, i; + + // Get rid of possible prompt sent by the rig + rig_flush(&rs->rigport); + + /* [A] = RSSI */ + ret = write_block(&rs->rigport, "A", 1); + + if (ret < 0) + { + RETURNFUNC(ret); + } + + // The response length is fixed + ret = read_block(&rs->rigport, buf, 4); + + if (ret < 0) + { + return ret; + } + + if (ret >= 0) + { + buf[ret] = '\0'; + } + + val->i = hhtoi(buf); + + prm80_wait_for_prompt(&rs->rigport); + + return RIG_OK; +} + /* * prm80_get_level * Assumes rig!=NULL @@ -918,6 +1059,12 @@ int prm80_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) int ret; channel_t chan; + // Get rawstr apart, it is not read from system state + if (level == RIG_LEVEL_RAWSTR) + { + return prm80_get_rawstr(rig, val); + } + memset(&chan, 0, sizeof(chan)); chan.vfo = RIG_VFO_CURR; @@ -954,6 +1101,50 @@ int prm80_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val) return RIG_OK; } +int prm80_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt) +{ + char statebuf[BUFSZ]; + int ret, mode_byte; + + ret = prm80_read_system_state(&rig->state.rigport, statebuf); + + if (ret != RIG_OK) + { + return ret; + } + + mode_byte = hhtoi(statebuf); + + // TX mode on? + *ptt = (mode_byte & 0x08) ? RIG_PTT_ON : RIG_PTT_OFF; + + prm80_wait_for_prompt(&rig->state.rigport); + + return RIG_OK; +} + +int prm80_get_dcd(RIG *rig, vfo_t vfo, dcd_t *dcd) +{ + char statebuf[BUFSZ]; + int ret, mode_byte; + + ret = prm80_read_system_state(&rig->state.rigport, statebuf); + + if (ret != RIG_OK) + { + return ret; + } + + mode_byte = hhtoi(statebuf); + + // Squelch open? + *dcd = (mode_byte & 0x04) ? RIG_DCD_ON : RIG_DCD_OFF; + + prm80_wait_for_prompt(&rig->state.rigport); + + return RIG_OK; +} + // TODO vfo_op : MCL FROM_VFO .. /* diff --git a/rigs/prm80/prm80.h b/rigs/prm80/prm80.h index fbaf50fbb..cdf3467c9 100644 --- a/rigs/prm80/prm80.h +++ b/rigs/prm80/prm80.h @@ -24,7 +24,7 @@ #include -#define BACKEND_VER "20210217" +#define BACKEND_VER "20210220" #define PRM80_MEM_CAP { \ .freq = 1, \ @@ -57,6 +57,8 @@ int prm80_set_mem(RIG *rig, vfo_t vfo, int ch); int prm80_get_mem(RIG *rig, vfo_t vfo, int *ch); int prm80_set_channel(RIG *rig, vfo_t vfo, const channel_t *chan); int prm80_get_channel(RIG *rig, vfo_t vfo, channel_t *chan, int read_only); +int prm80_get_dcd(RIG *rig, vfo_t vfo, dcd_t *dcd); +int prm80_get_ptt(RIG *rig, vfo_t vfo, ptt_t *ptt); const char *prm80_get_info(RIG *rig); diff --git a/rigs/prm80/prm8060.c b/rigs/prm80/prm8060.c index ff690e883..41f265c5e 100644 --- a/rigs/prm80/prm8060.c +++ b/rigs/prm80/prm8060.c @@ -33,9 +33,9 @@ #define PRM8060_ALL_MODES (RIG_MODE_FM) -#define PRM8060_FUNC (RIG_FUNC_REV|RIG_FUNC_LOCK) +#define PRM8060_FUNC (RIG_FUNC_REV|RIG_FUNC_LOCK|RIG_FUNC_MUTE) -#define PRM8060_LEVEL_ALL (RIG_LEVEL_AF|RIG_LEVEL_SQL /* |RIG_LEVEL_RFPOWER */) +#define PRM8060_LEVEL_ALL (RIG_LEVEL_AF|RIG_LEVEL_SQL|RIG_LEVEL_RFPOWER) #define PRM8060_PARM_ALL (RIG_PARM_NONE) @@ -44,6 +44,26 @@ #define PRM8060_VFO (RIG_VFO_MEM) +// Calibration done on PRM8070 +#define PRM8060_STR_CAL { 15, \ + { \ + { 0x14, -54 }, /* S0 */ \ + { 0x1D, -48 }, /* S1 */ \ + { 0x26, -42 }, /* S2 */ \ + { 0x33, -36 }, /* S3 */ \ + { 0x3F, -30 }, /* S4 */ \ + { 0x4D, -24 }, /* S5 */ \ + { 0x55, -18 }, /* S6 */ \ + { 0x61, -12 }, /* S7 */ \ + { 0x68, -6 }, /* S8 */ \ + { 0x6C, 0 }, /* S9 */ \ + { 0x81, 10 }, /* +10 */ \ + { 0x8B, 20 }, /* +20 */ \ + { 0x8C, 40 }, /* +40 */ \ + { 0x8C, 50 }, /* +50 */ \ + { 0xFF, 60 } /* +60 */ \ + } } + /* * PRM 8060 rig capabilities. * http://prm80.sourceforge.net/ @@ -58,8 +78,8 @@ const struct rig_caps prm8060_caps = .copyright = "LGPL", .status = RIG_STATUS_BETA, .rig_type = RIG_TYPE_TRANSCEIVER, - .ptt_type = RIG_PTT_NONE, - .dcd_type = RIG_DCD_NONE, + .ptt_type = RIG_PTT_RIG, + .dcd_type = RIG_DCD_RIG, .port_type = RIG_PORT_SERIAL, .serial_rate_min = 4800, .serial_rate_max = 4800, @@ -74,7 +94,7 @@ const struct rig_caps prm8060_caps = .has_get_func = PRM8060_FUNC, .has_set_func = PRM8060_FUNC, - .has_get_level = PRM8060_LEVEL_ALL | RIG_LEVEL_RFPOWER, + .has_get_level = PRM8060_LEVEL_ALL | RIG_LEVEL_RAWSTR, .has_set_level = RIG_LEVEL_SET(PRM8060_LEVEL_ALL), .has_get_parm = PRM8060_PARM_ALL, .has_set_parm = RIG_PARM_SET(PRM8060_PARM_ALL), @@ -120,6 +140,8 @@ const struct rig_caps prm8060_caps = RIG_FLT_END, }, + .str_cal = PRM8060_STR_CAL, + .rig_init = prm80_init, .rig_cleanup = prm80_cleanup, .get_mode = prm80_get_mode, @@ -138,6 +160,8 @@ const struct rig_caps prm8060_caps = .set_level = prm80_set_level, .get_level = prm80_get_level, .reset = prm80_reset, + .get_dcd = prm80_get_dcd, + .get_ptt = prm80_get_ptt, .get_info = prm80_get_info, };