# HG changeset patch
# User DanClemmensen <DanClemmensen(a)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"]))
-