From fe0db30659353611656a4f15ef4c8c366dc0c915 Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Mon, 9 Sep 2024 18:30:11 -0700 Subject: [PATCH 1/3] Fix several drivers with zero tuning steps The valid_tuning_steps must be ... valid. --- chirp/drivers/ft1d.py | 2 +- chirp/drivers/ft4.py | 9 +++++---- chirp/drivers/ft70.py | 2 +- chirp/drivers/ftm3200d.py | 2 +- chirp/drivers/ftm7250d.py | 2 +- chirp/drivers/icp7.py | 2 +- chirp/drivers/id31.py | 2 +- 7 files changed, 11 insertions(+), 10 deletions(-) diff --git a/chirp/drivers/ft1d.py b/chirp/drivers/ft1d.py index c0b5ad444..3f7f52bd9 100644 --- a/chirp/drivers/ft1d.py +++ b/chirp/drivers/ft1d.py @@ -916,7 +916,7 @@ def get_features(self): rf.valid_modes = list(MODES) + ['NFM', 'DN'] rf.valid_tmodes = list(TMODES) rf.valid_duplexes = list(DUPLEX) - rf.valid_tuning_steps = list(STEPS) + rf.valid_tuning_steps = [x for x in STEPS if x] rf.valid_bands = [(500000, 999900000)] rf.valid_skips = SKIPS rf.valid_power_levels = POWER_LEVELS diff --git a/chirp/drivers/ft4.py b/chirp/drivers/ft4.py index ec0a63f7e..7fd92b643 100644 --- a/chirp/drivers/ft4.py +++ b/chirp/drivers/ft4.py @@ -534,7 +534,8 @@ def get_memory_mappings(self, memory): # these steps encode to 0-9 on all radios, but encoding #2 is disallowed # on the US versions (FT-4XR) STEP_CODE = [0, 5.0, 6.25, 10.0, 12.5, 15.0, 20.0, 25.0, 50.0, 100.0] -US_LEGAL_STEPS = list(STEP_CODE) # copy to pass to UI on US radios +VALID_STEPS = [x for x in STEP_CODE if x] +US_LEGAL_STEPS = list(VALID_STEPS) # copy to pass to UI on US radios US_LEGAL_STEPS.remove(6.25) # euro radios just use STEP_CODE # Map the radio image sql_type (0-6) to the CHIRP mem values. @@ -1333,7 +1334,7 @@ class YaesuFT4XERadio(YaesuFT4GenericRadio): id_str = b'IFT-35R\x00\x00V100\x00\x00' valid_bands = VALID_BANDS_DUAL DUPLEX_AUTO = DUPLEX_AUTO_EU - legal_steps = STEP_CODE + legal_steps = VALID_STEPS BAND_ASSIGNMENTS = BAND_ASSIGNMENTS_DUALBAND @@ -1373,7 +1374,7 @@ class YaesuFT65RRadio(YaesuFT65GenericRadio): id_str = b'IH-420\x00\x00\x00V100\x00\x00' valid_bands = VALID_BANDS_DUAL DUPLEX_AUTO = DUPLEX_AUTO_US - legal_steps = STEP_CODE + legal_steps = VALID_STEPS BAND_ASSIGNMENTS = BAND_ASSIGNMENTS_DUALBAND DUPLEX_OFF_VIA_OFFSET = [ # matches the order of valid_bands None, # Don't modify broadcast FM memories @@ -1391,7 +1392,7 @@ class YaesuFT65ERadio(YaesuFT65GenericRadio): id_str = b'IH-420\x00\x00\x00V100\x00\x00' valid_bands = VALID_BANDS_DUAL DUPLEX_AUTO = DUPLEX_AUTO_EU - legal_steps = STEP_CODE + legal_steps = VALID_STEPS BAND_ASSIGNMENTS = BAND_ASSIGNMENTS_DUALBAND diff --git a/chirp/drivers/ft70.py b/chirp/drivers/ft70.py index b1b54d0a4..fbe5b5555 100644 --- a/chirp/drivers/ft70.py +++ b/chirp/drivers/ft70.py @@ -565,7 +565,7 @@ def get_features(self): rf.valid_modes = list(MODES) rf.valid_tmodes = list(TMODES) rf.valid_duplexes = list(DUPLEX) - rf.valid_tuning_steps = list(STEPS) + rf.valid_tuning_steps = [x for x in STEPS if x] rf.valid_bands = [(500000, 999900000)] rf.valid_skips = SKIPS rf.valid_power_levels = POWER_LEVELS diff --git a/chirp/drivers/ftm3200d.py b/chirp/drivers/ftm3200d.py index 92f9d1320..0c54f42ea 100644 --- a/chirp/drivers/ftm3200d.py +++ b/chirp/drivers/ftm3200d.py @@ -109,7 +109,7 @@ def get_features(self): rf.valid_tmodes = [x for x in TMODES if x is not None] rf.valid_cross_modes = [x for x in CROSS_MODES if x is not None] rf.valid_duplexes = list(ft1d.DUPLEX) - rf.valid_tuning_steps = list(STEPS) + rf.valid_tuning_steps = [x for x in STEPS if x] rf.valid_bands = [(136000000, 174000000)] # rf.valid_skips = SKIPS rf.valid_power_levels = POWER_LEVELS diff --git a/chirp/drivers/ftm7250d.py b/chirp/drivers/ftm7250d.py index 1ede2cd57..85a369469 100644 --- a/chirp/drivers/ftm7250d.py +++ b/chirp/drivers/ftm7250d.py @@ -109,7 +109,7 @@ def get_features(self): rf.valid_tmodes = [x for x in TMODES if x is not None] rf.valid_cross_modes = [x for x in CROSS_MODES if x is not None] rf.valid_duplexes = list(ft1d.DUPLEX) - rf.valid_tuning_steps = list(STEPS) + rf.valid_tuning_steps = [x for x in STEPS if x] rf.valid_bands = [(108000000, 580000000)] # rf.valid_skips = SKIPS rf.valid_power_levels = POWER_LEVELS diff --git a/chirp/drivers/icp7.py b/chirp/drivers/icp7.py index 651133346..287419145 100644 --- a/chirp/drivers/icp7.py +++ b/chirp/drivers/icp7.py @@ -130,7 +130,7 @@ def get_features(self): rf.valid_modes = MODES rf.valid_bands = [(495000, 999990000)] rf.valid_skips = ["", "S", "P"] - rf.valid_tuning_steps = TUNING_STEPS + rf.valid_tuning_steps = [x for x in TUNING_STEPS if x] rf.valid_name_length = 6 rf.has_settings = True rf.has_ctone = True diff --git a/chirp/drivers/id31.py b/chirp/drivers/id31.py index a10e0a753..8aa988ab4 100644 --- a/chirp/drivers/id31.py +++ b/chirp/drivers/id31.py @@ -198,7 +198,7 @@ def get_features(self): rf.has_bank_index = True rf.has_bank_names = True rf.valid_tmodes = list(TMODES) - rf.valid_tuning_steps = sorted(list(TUNING_STEPS)) + rf.valid_tuning_steps = sorted([x for x in TUNING_STEPS if x]) rf.valid_modes = list(self.MODES.values()) rf.valid_skips = ["", "S", "P"] rf.valid_characters = chirp_common.CHARSET_ASCII From 68458f807622a2b59034a732e4a055c922b8953d Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Mon, 9 Sep 2024 20:27:38 -0700 Subject: [PATCH 2/3] ftXd: Fix tuning step handling The ft1d driver has seemingly had incorrect tuning step handling since the beginning. As a result, stricter handling of tuning steps provided by the radio started to break down. This fixes them to work according to the OEM software for all the available steps. --- chirp/drivers/ft1d.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/chirp/drivers/ft1d.py b/chirp/drivers/ft1d.py index 3f7f52bd9..d0e96325f 100644 --- a/chirp/drivers/ft1d.py +++ b/chirp/drivers/ft1d.py @@ -514,10 +514,7 @@ TMODES = ["", "Tone", "TSQL", "DTCS"] DUPLEX = ["", "-", "+", "split"] MODES = ["FM", "AM", "WFM"] -STEPS = list(chirp_common.TUNING_STEPS) -STEPS.remove(30.0) -STEPS.append(100.0) -STEPS.insert(2, 0.0) # There is a skipped tuning step at index 2 (?) +STEPS = [5.0, 6.25, 8.33, 10.0, 12.5, 15.0, 20.0, 25.0, 50.0, 100.0, 9.0] SKIPS = ["", "S", "P"] FT1_DTMF_CHARS = list("0123456789ABCD*#-") @@ -1042,7 +1039,7 @@ def get_memory(self, number): mem.duplex = "" mem.power = POWER_LEVELS[0] mem.mode = "FM" - mem.tuning_step = 0 + mem.tuning_step = STEPS[0] else: mem.freq = chirp_common.fix_rounded_step(int(_mem.freq) * 1000) mem.offset = int(_mem.offset) * 1000 From 99cfeae3d99812994d8788e61fc7fd4bbda9b8af Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Mon, 9 Sep 2024 18:38:40 -0700 Subject: [PATCH 3/3] Prioritize radio-supplied tuning steps This makes the UI consider the radio's tuning steps, if defined as the first course of action. The existing code tried the standard set followed by the radio's set, assuming the radio's would be a subset, which is of course not always true. This also makes required_step() consider the radio-specific steps after the standard ones, if there are any strange ones to allow the radio to define ones that are not in the standard list. Related to #10968 --- chirp/chirp_common.py | 17 ++++++++++++++++- chirp/wxui/memedit.py | 14 ++++---------- tests/unit/test_chirp_common.py | 5 +++++ 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/chirp/chirp_common.py b/chirp/chirp_common.py index 3ec4f3710..49a21988d 100644 --- a/chirp/chirp_common.py +++ b/chirp/chirp_common.py @@ -814,6 +814,10 @@ def LIST(v): assert hasattr(v, '__iter__') +def LIST_NONZERO_INT(v): + assert all(x > 0 for x in v) + + def INT(min=0, max=None): def checkint(v): assert isinstance(v, int) @@ -865,7 +869,7 @@ class RadioFeatures: "valid_modes": LIST, "valid_tmodes": LIST, "valid_duplexes": LIST, - "valid_tuning_steps": LIST, + "valid_tuning_steps": LIST_NONZERO_INT, "valid_bands": LIST, "valid_skips": LIST, "valid_power_levels": LIST, @@ -1736,10 +1740,21 @@ def required_step(freq, allowed=None): 8.33: is_8_33, } + # Try the above "standard" steps first in order for step, validate in steps.items(): if step in allowed and validate(freq): return step + # Try any additional steps in the allowed list + for step in allowed: + if step in steps: + # Already tried + continue + if make_is(int(step * 1000))(freq): + LOG.debug('Chose non-standard step %s for %s' % ( + step, format_freq(freq))) + return step + raise errors.InvalidDataError("Unable to find a supported " + "tuning step for %s" % format_freq(freq)) diff --git a/chirp/wxui/memedit.py b/chirp/wxui/memedit.py index fcebc0dac..50503a10b 100644 --- a/chirp/wxui/memedit.py +++ b/chirp/wxui/memedit.py @@ -1337,18 +1337,12 @@ def _set_memory_defaults(self, mem, *only): else: want_tuning_step = 5.0 try: - # First calculate the needed step in case it is not supported - # by the radio. If we fail to find one the radio supports, - # we will use this one and then the error message about it - # being unsupported will be accurate. - want_tuning_step = chirp_common.required_step(mem.freq) - - # Now try to find a suitable one that the radio supports. + # Try to find a tuning step for the frequency that the radio + # supports, or with the default set want_tuning_step = chirp_common.required_step( - mem.freq, features.valid_tuning_steps) - LOG.debug('Chose radio-supported step %s' % want_tuning_step) + mem.freq, features.valid_tuning_steps or None) except errors.InvalidDataError as e: - LOG.warning(e) + LOG.warning('Failed to find step: %s' % e) if 'tuning_step' in only and want_tuning_step: mem.tuning_step = want_tuning_step diff --git a/tests/unit/test_chirp_common.py b/tests/unit/test_chirp_common.py index 458a1268f..92f062f41 100644 --- a/tests/unit/test_chirp_common.py +++ b/tests/unit/test_chirp_common.py @@ -503,6 +503,11 @@ def test_required_step_finds_suitable(self): self.assertEqual(2.5, chirp_common.required_step(self._005[0], allowed=[2.5])) + def test_required_step_finds_radio_specific(self): + # Make sure we find a radio-specific step, 10Hz in this case + self.assertEqual(0.01, chirp_common.required_step( + 146000010, allowed=[5.0, 10.0, 0.01, 20.0])) + def test_required_step_fail(self): self.assertRaises(errors.InvalidDataError, chirp_common.required_step,