mirror of
https://github.com/kk7ds/chirp.git
synced 2024-09-21 18:47:18 +00:00
[ft4] driver restructure (#7615)
While implementing two more radios of the Yaesu FT-4 family (the FT-25, see #7543, and the FT-4V, see #7387), I found that with some moderate reorganization, implementation of new radios will become easier. The proposed reorganization implements one more interstitial layer of inheritance to support the sub families of FT-4 (containing the FT-4X and FT-4V) and FT-65 (containing FT-65 and FT-25). Also, some variable assignments have been moved from the individual radio classes to the SCU-35 base class and to the interstitial classes named above. This change also adds the infrastructure for adding European or Asian models, and as such prepare for addressing a number of currently open issues (6.25kHz tune step issues on EU models, frequency limitations; see #6619, #6651, #6677, #6761, #6869). It will also make it easier for a few additional fixes for issues which were found during my work on this driver (#7601, #7603, #7605). I will submit these fixes in additional patches. Fixes: #7615
This commit is contained in:
parent
be114d0d5a
commit
a77699ff8c
@ -2,6 +2,7 @@
|
||||
# Derives loosely from two sources released under GPLv2:
|
||||
# ./template.py, Copyright 2012 Dan Smith <dsmith@danplanet.com>
|
||||
# ./ft60.py, Copyright 2011 Dan Smith <dsmith@danplanet.com>
|
||||
# Edited 2020 Bernhard Hailer AE6YN <ham73tux@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@ -18,8 +19,8 @@
|
||||
|
||||
"""
|
||||
CHIRP driver for Yaesu radios that use the SCU-35 cable. This includes at
|
||||
least the FT-4, FT-25, FT-35, and FT-65. This driver will not work with
|
||||
older Yaesu models.
|
||||
least the FT-4X, FT-4V, FT-65, and FT-25. This driver will not work with older
|
||||
Yaesu models.
|
||||
"""
|
||||
import logging
|
||||
import struct
|
||||
@ -261,7 +262,8 @@ def sendcmd(pipe, cmd, response_len):
|
||||
msg = "Bad echo. Sent:" + util.hexprint(cmd) + ", "
|
||||
msg += "Received:" + util.hexprint(echo)
|
||||
LOG.debug(msg)
|
||||
raise errors.RadioError("Incorrect echo on serial port. Bad cable?")
|
||||
raise errors.RadioError(
|
||||
"Incorrect echo on serial port. Radio off? Bad cable?")
|
||||
if response_len is None:
|
||||
return variable_len_resp(pipe)
|
||||
if response_len > 0:
|
||||
@ -474,8 +476,6 @@ DUPLEX = ["+", "", "-", "", "off", "", "split"] # (0,2,4,5)= (+,-,0, auto)
|
||||
|
||||
SKIPS = ["", "S"]
|
||||
|
||||
BASETYPE_FT4 = ["FT-4XR", "FT-4XE"]
|
||||
BASETYPE_FT65 = ["FT-65R"]
|
||||
POWER_LEVELS = [chirp_common.PowerLevel("Low", watts=0.5),
|
||||
chirp_common.PowerLevel("Mid", watts=2.5),
|
||||
chirp_common.PowerLevel("High", watts=5.0)]
|
||||
@ -560,16 +560,53 @@ PMSNAMES = ["%s%02d" % (c, i) for i in range(1, 11) for c in ('L', 'U')]
|
||||
# Each special has unique constrants: band, name yes/no, and pms L/U
|
||||
# The FT-65 class replaces the "prog" entry in this list.
|
||||
# The name field must be the name of a slot array in MEM_FORMAT
|
||||
SPECIALS = [
|
||||
SPECIALS_FT4 = [
|
||||
("pms", PMSNAMES),
|
||||
("vfo", ["VFO A UHF", "VFO A VHF", "VFO B FM", "VFO B VHF", "VFO B UHF"]),
|
||||
("home", ["HOME FM", "HOME VHF", "HOME UHF"]),
|
||||
("prog", ["P1", "P2"])
|
||||
]
|
||||
BAND_ASSIGNMENTS = [2, 1, 0, 1, 2, 0, 1, 2] # bands for the vfos and homes
|
||||
SPECIALS_FT65 = SPECIALS_FT4
|
||||
FT65_PROGS = ("prog", ["P1", "P2", "P3", "P4"])
|
||||
FT65_SPECIALS = list(SPECIALS) # a shallow copy works here
|
||||
FT65_SPECIALS[-1] = FT65_PROGS # replace the last entry (P key names)
|
||||
SPECIALS_FT65[-1] = FT65_PROGS # replace the last entry (P key names)
|
||||
|
||||
# I wonder whether we should simply open the bands to what the radios allow
|
||||
# for RX? The radios do take care of allowing or prohibiting TX on their own.
|
||||
# In that case, the ASIA settings can be used for any region model.
|
||||
# To be discussed with Dan Clemmensen. [AE6YN]
|
||||
|
||||
VALID_BANDS_US_DUAL = [
|
||||
(65000000, 108000000), # broadcast FM, receive only
|
||||
(144000000, 148000000), # VHF, US version, TX and RX
|
||||
(430000000, 450000000) # UHF, US version, TX and RX
|
||||
]
|
||||
VALID_BANDS_EU_DUAL = [
|
||||
(65000000, 108000000), # broadcast FM, receive only
|
||||
(144000000, 146000000), # VHF, EU version, TX and RX
|
||||
(430000000, 440000000) # UHF, EU version, TX and RX
|
||||
]
|
||||
VALID_BANDS_ASIA_DUAL = [
|
||||
(65000000, 108000000), # broadcast FM, receive only
|
||||
(136000000, 174000000), # VHF, Asia version, TX and RX
|
||||
(400000000, 480000000) # UHF, Asia version, TX and RX
|
||||
]
|
||||
|
||||
VALID_BANDS_US_VHF = [
|
||||
(65000000, 108000000), # broadcast FM, receive only
|
||||
(144000000, 148000000), # VHF, US version, TX and RX
|
||||
]
|
||||
VALID_BANDS_EU_VHF = [
|
||||
(65000000, 108000000), # broadcast FM, receive only
|
||||
(144000000, 146000000), # VHF, EU version, TX and RX
|
||||
]
|
||||
VALID_BANDS_ASIA_VHF = [
|
||||
(65000000, 108000000), # broadcast FM, receive only
|
||||
(136000000, 174000000), # VHF, Asia version, TX and RX
|
||||
]
|
||||
|
||||
# bands for the five VFO and three home channel memories
|
||||
BAND_ASSIGNMENTS_DUALBAND = [2, 1, 0, 1, 2, 0, 1, 2] # all locations used
|
||||
BAND_ASSIGNMENTS_MONO_VHF = [1, 1, 0, 1, 1, 0, 1, 1] # UHF locations unused
|
||||
|
||||
|
||||
# None, and 50 Tones. Use this explicit array because the
|
||||
@ -620,8 +657,8 @@ class YaesuSC35GenericRadio(chirp_common.CloneModeRadio,
|
||||
chirp_common.ExperimentalRadio):
|
||||
"""
|
||||
Base class for all Yaesu radios using the SCU-35 programming cable
|
||||
and its protocol. Classes for specific radios extend this class and
|
||||
are found at the end of this file.
|
||||
and its protocol. Classes for sub families extend this class and
|
||||
are found towards the end of this file.
|
||||
"""
|
||||
VENDOR = "Yaesu"
|
||||
MODEL = "SCU-35Generic" # No radio directly uses the base class
|
||||
@ -629,6 +666,12 @@ class YaesuSC35GenericRadio(chirp_common.CloneModeRadio,
|
||||
MAX_MEM_SLOT = 200
|
||||
NEEDS_COMPAT_SERIAL = False
|
||||
|
||||
# These settings are common to all radios in this family.
|
||||
_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
|
||||
MAX_MEM_SLOT = 200
|
||||
|
||||
@classmethod
|
||||
def get_prompts(cls):
|
||||
rp = chirp_common.RadioPrompts()
|
||||
@ -669,7 +712,6 @@ class YaesuSC35GenericRadio(chirp_common.CloneModeRadio,
|
||||
rf.has_dtcs_polarity = False # REV TN reverses the tone, not the dcs
|
||||
rf.has_cross = True
|
||||
rf.has_settings = True
|
||||
rf.valid_tuning_steps = self.legal_steps
|
||||
|
||||
return rf
|
||||
|
||||
@ -1027,14 +1069,11 @@ class YaesuSC35GenericRadio(chirp_common.CloneModeRadio,
|
||||
mem = chirp_common.Memory()
|
||||
_mem, ndx, num, regtype, sname = self.slotloc(memref)
|
||||
mem.number = num
|
||||
mem.freq = int(_mem.freq) * 10
|
||||
mem.offset = int(_mem.offset) * self.freq_offset_scale
|
||||
mem.duplex = DUPLEX[_mem.duplex]
|
||||
|
||||
self.decode_sql(mem, _mem)
|
||||
mem.power = POWER_LEVELS[_mem.tx_pwr]
|
||||
mem.mode = ["FM", "NFM"][_mem.tx_width]
|
||||
mem.tuning_step = STEP_CODE[_mem.step]
|
||||
# First, we need to know whether a channel is enabled,
|
||||
# then we can process any channel parameters.
|
||||
# It was found (at least on an FT-25) that channels might be
|
||||
# uninitialized and memory is just completely filled with 0xFF.
|
||||
|
||||
if regtype == "pms":
|
||||
mem.extd_number = sname
|
||||
@ -1043,15 +1082,34 @@ class YaesuSC35GenericRadio(chirp_common.CloneModeRadio,
|
||||
mem.name = clean_name(self._memobj.names[ndx].chrs)
|
||||
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
|
||||
else:
|
||||
mem.empty = False
|
||||
mem.extd_number = sname
|
||||
mem.immutable = ["number", "extd_number", "name", "skip"]
|
||||
|
||||
# So, now if channel is not empty, we can do the evaluation of
|
||||
# all parameters. Otherwise we set them to defaults.
|
||||
|
||||
if mem.empty:
|
||||
mem.freq = 0
|
||||
mem.offset = 0
|
||||
mem.duplex = "off"
|
||||
mem.power = POWER_LEVELS[0] # "High"
|
||||
mem.mode = "FM"
|
||||
mem.tuning_step = 0
|
||||
else:
|
||||
mem.freq = int(_mem.freq) * 10
|
||||
txfreq = int(self._memobj.txfreqs[ndx].freq) * 10
|
||||
if (txfreq != 0) and (txfreq != mem.freq):
|
||||
mem.duplex = "split"
|
||||
mem.offset = txfreq
|
||||
else:
|
||||
mem.offset = int(_mem.offset) * self.freq_offset_scale
|
||||
mem.duplex = DUPLEX[_mem.duplex]
|
||||
self.decode_sql(mem, _mem)
|
||||
mem.power = POWER_LEVELS[2 - _mem.tx_pwr]
|
||||
mem.mode = ["FM", "NFM"][_mem.tx_width]
|
||||
mem.tuning_step = STEP_CODE[_mem.step]
|
||||
return mem
|
||||
|
||||
def enforce_band(self, memloc, freq, mem_num, sname):
|
||||
@ -1105,28 +1163,16 @@ class YaesuSC35GenericRadio(chirp_common.CloneModeRadio,
|
||||
return
|
||||
|
||||
|
||||
@directory.register
|
||||
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_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
|
||||
MAX_MEM_SLOT = 200
|
||||
Pkeys = 2 # number of programmable keys on the FT-4
|
||||
namelen = 6 # length of the mem name display on the FT-4 front-panel
|
||||
id_str = b'IFT-35R\x00\x00V100\x00\x00'
|
||||
class YaesuFT4GenericRadio(YaesuSC35GenericRadio):
|
||||
"""
|
||||
FT-4 sub family class. Classes for individual radios extend
|
||||
these classes and are found at the end of this file.
|
||||
"""
|
||||
class_specials = SPECIALS_FT4
|
||||
Pkeys = 2 # number of programmable keys
|
||||
namelen = 6 # length of the mem name display on the front-panel
|
||||
freq_offset_scale = 25000
|
||||
legal_steps = US_LEGAL_STEPS
|
||||
class_group_descs = YaesuSC35GenericRadio.group_descriptions
|
||||
class_specials = SPECIALS
|
||||
# names for the setmode function for the programmable keys. Mode zero means
|
||||
# that the key is programmed for a memory not a setmode.
|
||||
SETMODES = [
|
||||
@ -1143,31 +1189,19 @@ class YaesuFT4Radio(YaesuSC35GenericRadio):
|
||||
]
|
||||
|
||||
|
||||
@directory.register
|
||||
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_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
|
||||
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'
|
||||
class YaesuFT65GenericRadio(YaesuSC35GenericRadio):
|
||||
"""
|
||||
FT-65 sub family class. Classes for individual radios extend
|
||||
these classes and are found at the end of this file.
|
||||
"""
|
||||
class_specials = SPECIALS_FT65
|
||||
Pkeys = 4 # number of programmable keys
|
||||
namelen = 8 # length of the mem name display on the front-panel
|
||||
freq_offset_scale = 50000
|
||||
legal_steps = US_LEGAL_STEPS
|
||||
# we need a deep copy here because we are adding deeper than the top level.
|
||||
class_group_descs = copy.deepcopy(YaesuSC35GenericRadio.group_descriptions)
|
||||
add_paramdesc(
|
||||
class_group_descs, "misc", ("compander", "Compander", ["OFF", "ON"]))
|
||||
class_specials = FT65_SPECIALS
|
||||
# names for the setmode function for the programmable keys. Mode zero means
|
||||
# that the key is programmed for a memory not a setmode.
|
||||
SETMODES = [
|
||||
@ -1180,3 +1214,31 @@ class YaesuFT65Radio(YaesuSC35GenericRadio):
|
||||
"step", "tot", "tx pwr", "tx save", "vfo.spl", # 30-34
|
||||
"vox", "wfm.rcv", "wide/nar", "wx alert", "scramble" # 35-39
|
||||
]
|
||||
|
||||
|
||||
# Classes for each individual radio.
|
||||
|
||||
|
||||
@directory.register
|
||||
class YaesuFT4XRRadio(YaesuFT4GenericRadio):
|
||||
"""
|
||||
FT-4X dual band, US version
|
||||
"""
|
||||
MODEL = "FT-4XR"
|
||||
id_str = b'IFT-35R\x00\x00V100\x00\x00'
|
||||
valid_bands = VALID_BANDS_US_DUAL
|
||||
legal_steps = US_LEGAL_STEPS
|
||||
BAND_ASSIGNMENTS = BAND_ASSIGNMENTS_DUALBAND
|
||||
|
||||
|
||||
@directory.register
|
||||
class YaesuFT65RRadio(YaesuFT65GenericRadio):
|
||||
"""
|
||||
FT-65 dual band, US version
|
||||
"""
|
||||
MODEL = "FT-65R"
|
||||
id_str = b'IH-420\x00\x00\x00V100\x00\x00'
|
||||
valid_bands = VALID_BANDS_US_DUAL
|
||||
legal_steps = US_LEGAL_STEPS
|
||||
BAND_ASSIGNMENTS = BAND_ASSIGNMENTS_DUALBAND
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user