# HG changeset patch # User DanClemmensen DanClemmensen@gmail.com # Date 1553788333 25200 # Thu Mar 28 08:52:13 2019 -0700 # Node ID 7e1511f8e3b8aee9b6061033bb4cecde8c4c51f6 # Parent 1b1928be7a68878c54965e1fcc6e196e17db776d [ft4] allow RO frequencies [#6651] Fixes: #6615 After this patch is applied, the code will function as before if using only TX frequencies. The code requires the earlier patch to memedit.py to actually enable the use of the RO frequencies.
diff -r 1b1928be7a68 -r 7e1511f8e3b8 chirp/drivers/ft4.py --- a/chirp/drivers/ft4.py Tue Mar 19 20:28:00 2019 -0700 +++ b/chirp/drivers/ft4.py Thu Mar 28 08:52:13 2019 -0700 @@ -464,10 +464,11 @@ banks.append(bank) return banks
-# the values in these lists must also be in the canonical UI list -# we can re-arrange the order, and we don't need to have all -# the values, but we cannot add our own values here. -DUPLEX = ["+", "", "-", "", "off", "", "split"] # (0,2,4,5)= (+,-,0, auto) +# list used by the UI. These exact values are set and tested. +VALID_DUPLEXES = ["", "+", "-", "split", "off"] +ENCODE_DUPLEXES = {"": 4, "+": 0, "-": 2, "split": 4, "off": 4} +# DUPLEX maps radio's duplex field to the duplex names +DUPLEX = ["+", "", "-", "", "off", ""] # (0,2,4,5)= (+,-,0, auto) # the radio implements duplex "auto" as 5. we map to "" It appears to be # a convienience function in the radio that affects the offset, but I do not # understand it. @@ -628,6 +629,11 @@ BAUD_RATE = 9600 MAX_MEM_SLOT = 200 NEEDS_COMPAT_SERIAL = False + valid_rx_bands = [ + (65000000, 108000000), # broadcast FM + (136000000, 174000000), # VHF + (400000000, 480000000) # UHF + ]
@classmethod def get_prompts(cls): @@ -653,7 +659,7 @@ specials = [name for s in self.class_specials for name in s[1]] rf.valid_special_chans = specials rf.memory_bounds = (1, self.MAX_MEM_SLOT) - rf.valid_duplexes = DUPLEX + rf.valid_duplexes = VALID_DUPLEXES # displaylist != DUPLEX rf.valid_tmodes = VALID_TONE_MODES rf.valid_cross_modes = VALID_CROSS_MODES rf.valid_power_levels = POWER_LEVELS @@ -662,7 +668,7 @@ rf.valid_characters = CHARSET rf.valid_name_length = self.namelen rf.valid_modes = ["FM", "NFM"] - rf.valid_bands = self.valid_bands + rf.valid_bands = self.valid_rx_bands rf.can_odd_split = True rf.has_ctone = True rf.has_rx_dtcs = True @@ -1003,6 +1009,57 @@ return (memloc, ndx, num, array, sname) # end of slotloc
+ def tx_allowed(self, mem): + """ + Given a mem, see if the tx frequency is within a valid tx band. + returns allowed (True or False), and the computed TX freq. + For FM broadcast, we allow duplex == "" also: the user doesn't + really expect the radio to Tx there anyway. + """ + freq = mem.freq + dup = mem.duplex + if dup == "off": + return (True, freq) + if (dup == "") and freq <= self.valid_rx_bands[0][1]: + return (True, freq) # hack: don't complain about FM bands + offset = mem.offset + if dup == "split": + freq = offset + elif dup == "-": + freq -= offset + elif dup == "+": + freq += offset + for lo, hi in self.valid_tx_bands: + if lo <= freq <= hi: + return (True, freq) + + return (False, freq) + + def validate_memory(self, mem): + """ + Called by UI when a mem is changed. Invoke the superclass' method to + get any generic error messages, then add any error msgs for our class. + returns a list of error messages for this channel's config + """ + msgs = chirp_common.CloneModeRadio.validate_memory(self, mem) + memloc, ndx, num, regtype, sname = self.slotloc(mem.number) + + def addmsg(msg): + msgs.append(chirp_common.ValidationError(msg)) + allowed, freq = self.tx_allowed(mem) + if not allowed: + freqstr = chirp_common.format_freq(freq) + addmsg("Tx freq %s is not in supported Tx range" % freqstr) + if regtype in ["vfo", "home"]: + first_vfo_num = self.MAX_MEM_SLOT + len(PMSNAMES) + 1 + band = BAND_ASSIGNMENTS[num - first_vfo_num] + freq = mem.freq + lo, hi = self.valid_rx_bands[band] + if not (lo <= freq < hi): + freqstr = chirp_common.format_freq(freq) + addmsg("freq %s is in wrong band for %s" % (freqstr, sname)) + return msgs + # return the raw info for a memory channel def get_raw_memory(self, memref): memloc, ndx, num, regtype, sname = self.slotloc(memref) @@ -1043,9 +1100,11 @@ mem.empty = not retrieve_bit(self._memobj.enable, ndx) mem.skip = SKIPS[retrieve_bit(self._memobj.scan, ndx)] txfreq = int(self._memobj.txfreqs[ndx].freq) * 10 - if (txfreq != 0) and (txfreq != mem.freq): - mem.duplex = "split" - mem.offset = txfreq + if (txfreq == 0): + mem.duplex = "off" + elif (txfreq != mem.freq): + mem.duplex = "split" + mem.offset = txfreq else: mem.empty = False mem.extd_number = sname @@ -1053,21 +1112,6 @@
return mem
- def enforce_band(self, memloc, freq, mem_num, sname): - """ - vfo and home channels are each restricted to a particular band. - If the frequency is not in the band, use the lower bound - Raise an exception to cause UI to pop up an error message - """ - first_vfo_num = self.MAX_MEM_SLOT + len(PMSNAMES) + 1 - band = BAND_ASSIGNMENTS[mem_num - first_vfo_num] - frange = self.valid_bands[band] - if freq >= frange[0] and freq <= frange[1]: - memloc.freq = freq / 10 - return freq - memloc.freq = frange[0] / 10 - raise Exception("freq out of range for %s" % sname) - # modify a radio channel in memobj based on info in CHIRP canonical form def set_memory(self, mem): _mem, ndx, num, regtype, sname = self.slotloc(mem.number) @@ -1076,9 +1120,14 @@ if regtype in ["memory", "pms"]: store_bit(self._memobj.enable, ndx, False) return - - txfreq = mem.freq / 10 # really. RX freq is used for TX base - _mem.freq = txfreq + txfreq = mem.freq # really. RX freq is used for TX base + _mem.freq = txfreq / 10 + duplex = mem.duplex + allowed, freq = self.tx_allowed(mem) + if not allowed: + mem.offset = 0 + mem.duplex = "off" + txfreq = 0 self.encode_sql(mem, _mem) if mem.power: _mem.tx_pwr = POWER_LEVELS.index(mem.power) @@ -1086,7 +1135,6 @@ _mem.step = STEP_CODE.index(mem.tuning_step)
_mem.offset = mem.offset / self.freq_offset_scale - duplex = mem.duplex if regtype in ["memory", "pms"]: ndx = num - 1 store_bit(self._memobj.enable, ndx, True) @@ -1094,13 +1142,9 @@ nametrim = (mem.name + " ")[:8] self._memobj.names[ndx].chrs = bytearray(nametrim, "ascii") if mem.duplex == "split": - txfreq = mem.offset / 10 - duplex = "off" # radio ignores when tx != rx - self._memobj.txfreqs[num-1].freq = txfreq - _mem.duplex = DUPLEX.index(duplex) - if regtype in ["vfo", "home"]: - self.enforce_band(_mem, mem.freq, num, sname) - + txfreq = mem.offset + self._memobj.txfreqs[num-1].freq = txfreq / 10 + _mem.duplex = ENCODE_DUPLEXES[duplex] return
@@ -1108,13 +1152,7 @@ class YaesuFT4Radio(YaesuSC35GenericRadio): MODEL = "FT-4XR" _basetype = BASETYPE_FT4 - valid_bands = [ - (65000000, 108000000), # broadcast FM, receive only - (144000000, 148000000), # VHF, US version, TX and RX - (430000000, 450000000) # UHF, US version, TX and RX - # VHF, RX (136000000, 174000000) - # UHF, RX (400000000, 480000000) - ] + valid_tx_bands = [(144000000, 148000000), (430000000, 450000000)] _valid_chars = chirp_common.CHARSET_ASCII numblocks = 0x215 # number of 16-byte blocks in the radio _memsize = 16 * numblocks # used by CHIRP file loader to guess radio type @@ -1146,13 +1184,7 @@ class YaesuFT65Radio(YaesuSC35GenericRadio): MODEL = "FT-65R" _basetype = BASETYPE_FT65 - valid_bands = [ - (65000000, 108000000), # broadcast FM, receive only - (144000000, 148000000), # VHF, US version, TX and RX - (430000000, 450000000) # UHF, US version, TX and RX - # VHF, RX (136000000, 174000000) - # UHF, RX (400000000, 480000000) - ] + valid_tx_bands = [(144000000, 148000000), (430000000, 450000000)] _valid_chars = chirp_common.CHARSET_ASCII numblocks = 0x215 # number of 16-byte blocks in the radio _memsize = 16 * numblocks # used by CHIRP file loader to guess radio type