# HG changeset patch # User DanClemmensen DanClemmensen@gmail.com # Date 1551482056 28800 # Fri Mar 01 15:14:16 2019 -0800 # Node ID 79bb67ff2044d1b274df2e5daf1c4104fadaeeae # Parent 6cc8c100a1e6732b1a69cae478c48dcbdb85b40b [ft4] make the tone code less ugly [#4787] Tone encode and decode both now derive from A single shared mapping table.
This also patch includes whitespace changes, but only to pass cpep8. Another patch follows to fix other whitespace and minor cleanups.
diff -r 6cc8c100a1e6 -r 79bb67ff2044 chirp/drivers/ft4.py --- a/chirp/drivers/ft4.py Thu Feb 28 18:03:54 2019 -0500 +++ b/chirp/drivers/ft4.py Fri Mar 01 15:14:16 2019 -0800 @@ -282,7 +282,7 @@ raise errors.RadioError("expected QX from radio.") id_response = sendcmd(radio.pipe, b'\x02', None) if id_response != radio.id_str: - substr0=radio.id_str[:radio.id_str.find('\x00')] + substr0 = radio.id_str[:radio.id_str.find('\x00')] if id_response[:id_response.find('\x00')] != substr0: msg = "ID mismatch. Expected" + util.hexprint(radio.id_str) msg += ", Received:" + util.hexprint(id_response) @@ -447,8 +447,62 @@ # 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]
-TONE_MODES = ["", "Tone", "TSQL", "DTCS", "DTCS-R", "TSQL-R", "Cross"] -CROSS_MODES = ["DTCS->", "DTCS->DTCS"] # only the extras we need +# Map the radio image sql_type (0-6) to the CHIRP mem values. +# Types "TSQL" and "DCS" each map to different CHIRP values depending +# on the radio values on the tx and rx tone codes. +# This is a list of rows, one per Yaesu sql_type (0-5). 6 is separate. +# Each row is a tuple. Its first member is a list of [tmode,cross] or +# [tmode, cross, suppress]. "Suppress" is used only when encoding UI-->radio. +# When decoding radio-->UI, two of the sql_types each result in 5 possibible +# UI decodings depending on the tx and rx codes, and the list in each of these +# rows has five members. These two row tuples each have two additional members +# to specify which of the radio fields to examine. +# The map from CHIRP UI to radio image types is also built from this table. +RADIO_TMODES = [ + ([["", None], ], ), # sql_type= 0. off + ([["Cross", "->Tone"], ], ), # sql_type= 1. R-TONE + ([["Tone", None], ], ), # sql_type= 2. T-TONE + ([ # sql_type= 3. TSQL: + ["", None], # tx==0, rx==0 : invalid + ["TSQL", None], # tx==0 + ["Tone", None], # rx==0 + ["Cross", "Tone->Tone"], # tx!=rx + ["TSQL", None] # tx==rx + ], "tx_ctcss", "rx_ctcss"), # tx and rx fields to check + ([["TSQL-R", None], ], ), # sql_type= 4. REV TN + ([ # sql_type= 5.DCS: + ["", None], # tx==0, rx==0 : invalid + ["Cross", "->DTCS", "tx_dcs"], # tx==0. suppress tx + ["Cross", "DTCS->", "rx_dcs"], # rx==0. suppress rx + ["Cross", "DTCS->DTCS"], # tx!=rx + ["DTCS", None] # tx==rx + ], "tx_dcs", "rx_dcs"), # tx and rx fields to check + # # sql_type= 6. PAGER is a CHIRP "extra" + ] + + +# Find all legal values for the tmode and cross fields for the UI. +# We build a list of two dictionaries to do the lookups when encoding. +# The reversed range is a Kludge: by happenstance, earlier duplicates +# in the above table are the preferred mapping, they override the +# later ones when we process the table backwards. +# The keys will be passed to RadioFeatures as lists +def build_modedicts(): + tone_dict = {} + cross_dict = {} + for sql_type in reversed(range(0, len(RADIO_TMODES))): + sql_type_row = RADIO_TMODES[sql_type] + for decode_row in sql_type_row[0]: + suppress = None + if len(decode_row) == 3: + suppress = decode_row[2] + tone_dict[decode_row[0]] = (sql_type, suppress) + if decode_row[1]: + cross_dict[decode_row[1]] = (sql_type, suppress) + return tone_dict, cross_dict + +TONE_DICT, CROSS_DICT = build_modedicts() +
DTMF_CHARS = "0123456789ABCD*#- " CW_ID_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ " @@ -534,8 +588,8 @@ rf.valid_special_chans = specials rf.memory_bounds = (1, self.MAX_MEM_SLOT) rf.valid_duplexes = DUPLEX - rf.valid_tmodes = TONE_MODES - rf.valid_cross_modes = CROSS_MODES + rf.valid_tmodes = list(TONE_DICT.keys()) + rf.valid_cross_modes = list(CROSS_DICT.keys()) rf.valid_power_levels = POWER_LEVELS rf.valid_tuning_steps = self.legal_steps rf.valid_skips = SKIPS @@ -707,7 +761,7 @@ # ----------------end of group_descriptions
# allow a child class to add a param. - def add_paramdesc(self,group, param): + def add_paramdesc(self, group, param): for description in self.group_descriptions: groupname, title, parms = description if group == groupname: @@ -770,44 +824,31 @@ LOG.debug(element.get_name()) raise
- RADIO_TMODES = [ - ("(None)", ["", ""]), # off - ("(None)", ["TSQL-R", ""]), # R-TONE - ("(None)", ["Tone", ""]), # T-TONE - ("(None)", None, "tx_ctcss", "rx_ctcss", [ # TSQL - ["", None], # x==0, r==0 : not valid - ["TSQL-R", ""], # x==0 - ["Tone", ""], # r==0 - ["TSQL", ""], # x!=r - ["TSQL", ""] # x==r - ]), - ("REV-TN", ["TSQL-R", ""]), - ("(None)", None, "tx_dcs", "rx_dcs", [ # DCS - ["", None], # x==0, r==0 : not valid - ["DTCS-R", ""], # x==0 - ["Cross", "DTCS->"], # r==0 - ["Cross", "DTCS->DTCS"], # x!=r - ["DTCS", ""] # x==r - ]), - ("PAGER", ["", None]) # handled as a CHIRP "extra" - ] LOOKUP = [[True, True], [True, False], [False, True], [False, False]]
def decode_sql(self, mem, chan): """ examine the radio channel fields and determine the correct - CHIRP CSV values for tmode, cross_mode, and dcts_polarity + CHIRP CSV values for tmode, cross_mode, and sql_override """ - mode = self.RADIO_TMODES[chan.sql_type] - chirpvals = mode[1] - if not chirpvals: - x = getattr(chan, mode[2]) - r = getattr(chan, mode[3]) + mem.extra = RadioSettingGroup("Extra", "extra") + extra_modes = ["(None)", "PAGER"] + value = extra_modes[chan.sql_type == 6] + valuelist = RadioSettingValueList(extra_modes, value) + rs = RadioSetting("sql_override", "Squelch override", valuelist) + mem.extra.append(rs) + if chan.sql_type == 6: + return + sql_map = RADIO_TMODES[chan.sql_type] + ndx = 0 + if len(sql_map[0]) > 1: + x = getattr(chan, sql_map[1]) + r = getattr(chan, sql_map[2]) ndx = self.LOOKUP.index([x == 0, r == 0]) if ndx == 3 and x == r: ndx = 4 - chirpvals = mode[4][ndx] - mem.tmode, cross = chirpvals + mem.tmode = sql_map[0][ndx][0] + cross = sql_map[0][ndx][1] if cross: mem.cross_mode = cross if chan.rx_ctcss: @@ -818,62 +859,35 @@ mem.dtcs = DTCS_MAP[chan.tx_dcs] if chan.rx_dcs: mem.rx_dtcs = DTCS_MAP[chan.rx_dcs] - LOG.debug(" setting sql_override to <%s>" % mode[0]) - mem.extra = RadioSettingGroup("Extra", "extra") - extra_modes = ["(None)", "REV-TN", "PAGER"] - valuelist = RadioSettingValueList(extra_modes, mode[0]) - rs = RadioSetting("sql_override", "Squelch override", valuelist) - mem.extra.append(rs) - # Yaesu sql_type field codes - SQL_TYPE = ["off", "R-TONE", "T-TONE", "TSQL", "REV-TN", "DCS", "PAGER"] - # map a CHIRP tone mode to a FT-4 sql and which if any code to set to 0. - MODE_TONE = { - "": ("off", None), - "Tone": ("T-TONE", "rx_ctcss"), - "TSQL": ("TSQL", None), - "DTCS": ("DCS", None), # must set rx_dcs to tx_dcs? - "DTCS-R": ("DCS", "tx_dcs"), - "TSQL-R": ("R-TONE", "tx_ctcss"), # not documented on wiki - "Cross": () # not used in lookup - } - - # map a CHIRP Cross type if the CHIRP sql type is "cross" - MODE_CROSS = { - "DTCS->": ("DCS", "rx_dcs"), - "DTCS->DTCS": ("DCS", None) - # "Tone->Tone": ("TSQL", None), - # "->DTCS": ("DCS", "tx_dcs"), - # "->Tone": ("R-TONE", None), - # "Tone->": ("T-Tone", None) - }
def encode_sql(self, mem, chan): """ - examine CHIRP CSV columns tmode and cross_mode - and set the correct values for the radio sql_type, dcs codes, - and ctcss codes. We set all four codes, and then zero out - a code if needed when Tone or DCS is one-way + examine CHIRP's mem.tmode and mem.cross_mode and set the values + for the radio sql_type, dcs codes, and ctcss codes. We set all four + codes, and then zero out a code if needed when Tone or DCS is one-way """ chan.tx_ctcss = TONE_MAP.index(mem.rtone) chan.tx_dcs = DTCS_MAP.index(mem.dtcs) chan.rx_ctcss = TONE_MAP.index(mem.ctone) chan.rx_dcs = DTCS_MAP.index(mem.rx_dtcs) - tbl, ndx = [ - (self.MODE_TONE, mem.tmode), - (self.MODE_CROSS, mem.cross_mode) + if mem.tmode == "TSQL": + chan.tx_ctcss = chan.rx_ctcss # CHIRP uses ctone for TSQL + if mem.tmode == "DTCS": + chan.tx_dcs = chan.rx_dcs # CHIRP uses rx_dtcs for DTCS + # select the correct internal dictionary and key + mode_dict, key = [ + (TONE_DICT, mem.tmode), + (CROSS_DICT, mem.cross_mode) ][mem.tmode == "Cross"] - row = tbl[ndx] - if ndx == "DTCS": - chan.rx_dcs = chan.tx_dcs - chan.sql_type = self.SQL_TYPE.index(row[0]) - if row[1]: - setattr(chan, row[1], 0) + # now look up that key in that dictionary. + chan.sql_type, suppress = mode_dict[key] + if suppress: + setattr(chan, suppress, 0) for setting in mem.extra: if (setting.get_name() == 'sql_override'): value = str(setting.value) - if value != "(None)": - chan.sql_type = self.SQL_TYPE.index(value) - + if value == "PAGER": + chan.sql_type = 6 return
# given a CHIRP memory ref, get the radio memobj for it. @@ -1018,22 +1032,23 @@ namelen = 6 # length of the mem name display on the FT-4 front-panel id_str = b'IFT-35R\x00\x00V100\x00\x00' legal_steps = list(STEP_CODE) - legal_steps.remove(6.25) #should not remove if euro version + legal_steps.remove(6.25) # should not remove if euro version # names for the setmode function for the programmable keys. Mode zero means # that the key is programmed for a memory not a setmode. SETMODES = [ - "mem", "apo", "ar bep", "ar int", "beclo", #00-04 - "beep", "bell", "cw id", "cw wrt", "dc vlt", #05-09 - "dcs cod", "dt dly", "dt set", "dtc spd", "edg.bep", #10-14 - "lamp", "led.bsy", "led.tx", "lock", "m/t-cl", #15-19 - "mem.del", "mem.tag", "pag.abk", "pag.cdr", "pag.cdt", #20-24 - "pri.rvt", "pswd", "pswdwt", "rf sql", "rpt.ars", #25-29 - "rpt.frq", "rpt.sft", "rxsave", "scn.lmp", "scn.rsm", #30-34 - "skip", "sql.typ", "step", "tn frq", "tot", #35-39 - "tx pwr", "tx save", "vfo.spl", "vox", "wfm.rcv", #40-44 - "w/n.dev", "wx.alert" #45-46 + "mem", "apo", "ar bep", "ar int", "beclo", # 00-04 + "beep", "bell", "cw id", "cw wrt", "dc vlt", # 05-09 + "dcs cod", "dt dly", "dt set", "dtc spd", "edg.bep", # 10-14 + "lamp", "led.bsy", "led.tx", "lock", "m/t-cl", # 15-19 + "mem.del", "mem.tag", "pag.abk", "pag.cdr", "pag.cdt", # 20-24 + "pri.rvt", "pswd", "pswdwt", "rf sql", "rpt.ars", # 25-29 + "rpt.frq", "rpt.sft", "rxsave", "scn.lmp", "scn.rsm", # 30-34 + "skip", "sql.typ", "step", "tn frq", "tot", # 35-39 + "tx pwr", "tx save", "vfo.spl", "vox", "wfm.rcv", # 40-44 + "w/n.dev", "wx.alert" # 45-46 ]
+ # don't register the FT-65 in the production version until it is tested # @directory.register class YaesuFT65Radio(YaesuSC35GenericRadio): @@ -1052,9 +1067,9 @@ MAX_MEM_SLOT = 200 Pkeys = 4 # number of programmable keys on the FT-65 namelen = 8 # length of the mem name display on the FT-65 front panel - id_str=b'IH-420\x00\x00\x00V100\x00\x00' + id_str = b'IH-420\x00\x00\x00V100\x00\x00' legal_steps = list(STEP_CODE) - legal_steps.remove(6.25) #should not remove if euro version + legal_steps.remove(6.25) # should not remove if euro version # names for the setmode function for the programmable keys. Mode zero means # that the key is programmed for a memory not a setmode. SETMODES = [ @@ -1063,10 +1078,10 @@ "dc volt", "dcs code", "dtmf set", "dtmf wrt", "edg bep", # 10-14 "key lock", "lamp", "ledbsy", "mem del", "mon/t-cl", # 15-19 "name tag", "pager", "password", "pri.rvt", "repeater", # 20-24 - "resume", "rf.sql", "scn.lamp", "skip", "sql type", # 25-29 + "resume", "rf.sql", "scn.lamp", "skip", "sql type", # 25-29 "step", "tot", "tx pwr", "tx save", "vfo.spl", # 30-34 "vox", "wfm.rcv", "wide/nar", "wx alert", "scramble" # 35-39 ] + def __init__(self): self.add_paramdesc("misc", ("compander", "Compander", ["ON", "OFF"])) -