diff --git a/chirp/chirp_common.py b/chirp/chirp_common.py index 3ec4f371..49a21988 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/drivers/ft1d.py b/chirp/drivers/ft1d.py index c0b5ad44..d0e96325 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*#-") @@ -916,7 +913,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 @@ -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 diff --git a/chirp/drivers/ft4.py b/chirp/drivers/ft4.py index ec0a63f7..7fd92b64 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 b1b54d0a..fbe5b555 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 92f9d132..0c54f42e 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 1ede2cd5..85a36946 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 65113334..28741914 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 a10e0a75..8aa988ab 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 diff --git a/chirp/wxui/memedit.py b/chirp/wxui/memedit.py index fcebc0da..50503a10 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 458a1268..92f062f4 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,