# HG changeset patch # User Brad Schuler # Date 1605903117 25200 # Fri Nov 20 13:11:57 2020 -0700 # Node ID 8850feaa93dfccf293223a10a8f7799dc925651e # Parent d834c8115a243fa6eacf5e6647607289fd0b1ea6 [AnyTone 5888UV] Add simple squelch mode & additional file identifier and add extra channel attributes Related to issues 1491, 2989, 3653, 6633 and 8407 (1491, 2989, 3653, 6633) Set the radio's squelch mode to CTCSS/DCS Tones instead of Carrier when the receive tone mode is set. Recognize a file image from this radio when no metadata is present. (8407) Add the following channel attributes - Tuning steps - Duplex: off - Busy channel lockout - Optional signal selection (DTMF, 2-tone, 5-tone) - Reverse - Compander - Talkaround - PTT ID - Squelch with optional signal - Use custom CTCSS for Tx and/or Rx diff -r d834c8115a24 -r 8850feaa93df chirp/drivers/anytone.py --- a/chirp/drivers/anytone.py Fri Nov 20 12:45:13 2020 -0700 +++ b/chirp/drivers/anytone.py Fri Nov 20 13:11:57 2020 -0700 @@ -53,12 +53,15 @@ rxinv:1, txinv:1, channel_width:2, - unknownB:2; - u8 unknown8:3, + rev:1, + txoff:1; + u8 talkaround:1, + compander:1, + unknown8:1, is_am:1, power:2, duplex:2; - u8 unknown4:4, + u8 dtmfSlotNum:4, rxtmode:2, txtmode:2; u8 unknown5:2, @@ -67,10 +70,23 @@ rxtone:6; u8 txcode; u8 rxcode; - u8 unknown7[2]; - u8 unknown2[5]; + u8 unknown10:2, + pttid:2, + unknown11:2, + bclo:2; + u8 unknown7; + u8 unknown9:5, + sqlMode:3; // [Carrier, CTCSS/DCS Tones, Opt Sig Only, Tones & Opt Sig, Tones or Opt Sig] + u8 unknown21:6, + optsig:2; + u8 unknown22:3, + twotone:5; + u8 unknown23:1, + fivetone:7; + u8 unknown24:4, + scramble:4; char name[7]; - u8 unknownZ[2]; + ul16 custtone; }; #seekto 0x0030; @@ -318,12 +334,22 @@ TONES = [62.5] + list(chirp_common.TONES) TMODES = ['', 'Tone', 'DTCS', ''] -DUPLEXES = ['', '-', '+', ''] +DUPLEXES = ['', '-', '+', 'off'] MODES = ["FM", "FM", "NFM"] POWER_LEVELS = [chirp_common.PowerLevel("High", watts=50), chirp_common.PowerLevel("Mid1", watts=25), chirp_common.PowerLevel("Mid2", watts=10), chirp_common.PowerLevel("Low", watts=5)] +BCLO = ['Off', 'Repeater', 'Busy'] +DTMF_SLOTS = ['M%d' % x for x in range(1, 17)] +# Chose not to expose SCRAMBLE_CODES = ['Off'] + ['%d' % x for x in range(1, 10)] + ['Define 1', 'Define 2'] +TONE2_SLOTS = ['%d' % x for x in range(0, 24)] +TONE5_SLOTS = ['%d' % x for x in range(0, 100)] +SQL_MODES = ["Carrier", "CTCSS/DCS", "Opt Sig Only", "Tones AND Sig", "Tones OR Sig"] +OPT_SIG_SQL = ["Off"] + SQL_MODES[2:] +OPT_SIGS = ['Off', 'DTMF', '2Tone', '5Tone'] +PTT_IDS = ['Off', 'Begin', 'End', 'Begin & End'] +TUNING_STEPS = [2.5, 5, 6.25, 10, 12.5, 15, 20, 25, 30, 50] @directory.register @@ -333,7 +359,7 @@ VENDOR = "AnyTone" MODEL = "5888UV" BAUD_RATE = 9600 - _file_ident = "QX588UV" + _file_ident = ["QX588UV", "588UVN"] # May try to mirror the OEM behavior later _ranges = [ @@ -353,8 +379,8 @@ rf.has_settings = True rf.has_bank = False rf.has_cross = True - rf.valid_tuning_steps = [2.5, 5, 6.25, 10, 12.5, 15, 20, 25, 30, 50] - rf.has_tuning_step = False + rf.valid_duplexes = DUPLEXES + rf.valid_tuning_steps = TUNING_STEPS rf.has_rx_dtcs = True rf.valid_skips = ["", "S", "P"] rf.valid_modes = ["FM", "NFM", "AM"] @@ -421,17 +447,33 @@ mem.name = str(_mem.name).rstrip() mem.duplex = DUPLEXES[_mem.duplex] mem.mode = _mem.is_am and "AM" or MODES[_mem.channel_width] + mem.tuning_step = TUNING_STEPS[_mem.tune_step] + + if _mem.txoff: + mem.duplex = DUPLEXES[3] rxtone = txtone = None rxmode = TMODES[_mem.rxtmode] + if _mem.sqlMode == SQL_MODES.index("Carrier") or _mem.sqlMode == SQL_MODES.index("Opt Sig Only"): + rxmode = TMODES.index('') txmode = TMODES[_mem.txtmode] if txmode == "Tone": - txtone = TONES[_mem.txtone] + # If custom tone is being used, show as 88.5 (and set checkbox in extras) + # Future: Improve chirp_common, so I can add "CUSTOM" into TONES + if _mem.txtone == len(TONES): + txtone = 88.5 + else: + txtone = TONES[_mem.txtone] elif txmode == "DTCS": txtone = chirp_common.ALL_DTCS_CODES[self._get_dcs_index(_mem, 'tx')] if rxmode == "Tone": - rxtone = TONES[_mem.rxtone] + # If custom tone is being used, show as 88.5 (and set checkbox in extras) + # Future: Improve chirp_common, so I can add "CUSTOM" into TONES + if _mem.rxtone == len(TONES): + rxtone = 88.5 + else: + rxtone = TONES[_mem.rxtone] elif rxmode == "DTCS": rxtone = chirp_common.ALL_DTCS_CODES[self._get_dcs_index(_mem, 'rx')] @@ -446,6 +488,53 @@ mem.skip = _flg.get_skip() and "S" or _flg.get_pskip() and "P" or "" mem.power = POWER_LEVELS[_mem.power] + mem.extra = RadioSettingGroup("Extra", "extra") + + rs = RadioSetting("rev", "Reverse", RadioSettingValueBoolean(_mem.rev)) + mem.extra.append(rs) + + rs = RadioSetting("compander", "Compander", RadioSettingValueBoolean(_mem.compander)) + mem.extra.append(rs) + + rs = RadioSetting("talkaround", "Talkaround", RadioSettingValueBoolean(_mem.talkaround)) + mem.extra.append(rs) + + rs = RadioSetting("pttid", "PTT ID", RadioSettingValueList(PTT_IDS, PTT_IDS[_mem.pttid])) + mem.extra.append(rs) + + rs = RadioSetting("bclo", "Busy Channel Lockout", RadioSettingValueList(BCLO, BCLO[_mem.bclo])) + mem.extra.append(rs) + + rs = RadioSetting("optsig", "Optional Signaling", RadioSettingValueList(OPT_SIGS, OPT_SIGS[_mem.optsig])) + mem.extra.append(rs) + + rs = RadioSetting("OPTSIGSQL", "Squelch w/Opt Signaling", RadioSettingValueList(OPT_SIG_SQL, SQL_MODES[_mem.sqlMode] if SQL_MODES[_mem.sqlMode] in OPT_SIG_SQL else "Off")) + mem.extra.append(rs) + + rs = RadioSetting("dtmfSlotNum", "DTMF", RadioSettingValueList(DTMF_SLOTS, DTMF_SLOTS[_mem.dtmfSlotNum])) + mem.extra.append(rs) + + rs = RadioSetting("twotone", "2-Tone", RadioSettingValueList(TONE2_SLOTS, TONE2_SLOTS[_mem.twotone])) + mem.extra.append(rs) + + rs = RadioSetting("fivetone", "5-Tone", RadioSettingValueList(TONE5_SLOTS, TONE5_SLOTS[_mem.fivetone])) + mem.extra.append(rs) + + # Chose not to expose scramble + # rs = RadioSetting("scramble", "Scrambler Switch", RadioSettingValueList(SCRAMBLE_CODES, SCRAMBLE_CODES[_mem.scramble])) + # mem.extra.append(rs) + + # Memory properties dialog is only capable of Boolean and List RadioSettingValue classes, so cannot configure it + # rs = RadioSetting("custtone", "Custom CTCSS", RadioSettingValueFloat(min(TONES), max(TONES), _mem.custtone and _mem.custtone / 10 or 151.1, 0.1, 1)) + # mem.extra.append(rs) + custToneStr = chirp_common.format_freq(_mem.custtone) + + rs = RadioSetting("CUSTTONETX", "Use Custom CTCSS (%s) for Tx" % custToneStr, RadioSettingValueBoolean(_mem.txtone == len(TONES))) + mem.extra.append(rs) + + rs = RadioSetting("CUSTTONERX", "Use Custom CTCSS (%s) for Rx" % custToneStr, RadioSettingValueBoolean(_mem.rxtone == len(TONES))) + mem.extra.append(rs) + return mem def set_memory(self, mem): @@ -460,7 +549,13 @@ _mem.offset = mem.offset / 100 _mem.name = mem.name.ljust(7) _mem.is_am = mem.mode == "AM" - _mem.duplex = DUPLEXES.index(mem.duplex) + _mem.tune_step = TUNING_STEPS.index(mem.tuning_step) + if mem.duplex == "off": + _mem.duplex = DUPLEXES.index("") + _mem.txoff = 1 + else: + _mem.duplex = DUPLEXES.index(mem.duplex) + _mem.txoff = 0 try: _mem.channel_width = MODES.index(mem.mode) @@ -472,6 +567,10 @@ _mem.txtmode = TMODES.index(txmode) _mem.rxtmode = TMODES.index(rxmode) + if rxmode != '': + _mem.sqlMode = SQL_MODES.index("CTCSS/DCS") + else: + _mem.sqlMode = SQL_MODES.index("Carrier") if txmode == "Tone": _mem.txtone = TONES.index(txtone) elif txmode == "DTCS": @@ -494,6 +593,25 @@ else: _mem.power = 0 + for setting in mem.extra: + if setting.get_name() == "ignore": + LOG.debug("*** ignore: %s" % str(setting.value)) + # Future: elif setting.get_name() == "custtone": + # Future: setattr(_mem, "custtone", setting.value.get_value() * 10) + elif setting.get_name() == "OPTSIGSQL": + if str(setting.value) != "Off": + _mem.sqlMode = SQL_MODES.index(str(setting.value)) + elif setting.get_name() == "CUSTTONETX": + if setting.value: + _mem.txtone = len(TONES) + elif setting.get_name() == "CUSTTONERX": + if setting.value: + _mem.rxtone = len(TONES) + else: + setattr(_mem, setting.get_name(), setting.value) + + return mem + def get_settings(self): _settings = self._memobj.settings basic = RadioSettingGroup("basic", "Basic") @@ -546,7 +664,10 @@ @classmethod def match_model(cls, filedata, filename): - return cls._file_ident in filedata[0x20:0x40] + for _ident in cls._file_ident: + if _ident in filedata[0x20:0x40]: + return True + return False @directory.register @@ -554,7 +675,7 @@ """Intek HR-2040""" VENDOR = "Intek" MODEL = "HR-2040" - _file_ident = "HR-2040" + _file_ident = ["HR-2040"] @directory.register @@ -562,7 +683,7 @@ """Polmar DB-50M""" VENDOR = "Polmar" MODEL = "DB-50M" - _file_ident = "DB-50M" + _file_ident = ["DB-50M"] @directory.register @@ -570,7 +691,7 @@ """Powerwerx DB-750X""" VENDOR = "Powerwerx" MODEL = "DB-750X" - _file_ident = "DB-750X" + _file_ident = ["DB-750X"] def get_settings(self): return {}