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:
|
# Derives loosely from two sources released under GPLv2:
|
||||||
# ./template.py, Copyright 2012 Dan Smith <dsmith@danplanet.com>
|
# ./template.py, Copyright 2012 Dan Smith <dsmith@danplanet.com>
|
||||||
# ./ft60.py, Copyright 2011 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
|
# 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
|
# 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
|
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
|
least the FT-4X, FT-4V, FT-65, and FT-25. This driver will not work with older
|
||||||
older Yaesu models.
|
Yaesu models.
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
import struct
|
import struct
|
||||||
@ -261,7 +262,8 @@ def sendcmd(pipe, cmd, response_len):
|
|||||||
msg = "Bad echo. Sent:" + util.hexprint(cmd) + ", "
|
msg = "Bad echo. Sent:" + util.hexprint(cmd) + ", "
|
||||||
msg += "Received:" + util.hexprint(echo)
|
msg += "Received:" + util.hexprint(echo)
|
||||||
LOG.debug(msg)
|
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:
|
if response_len is None:
|
||||||
return variable_len_resp(pipe)
|
return variable_len_resp(pipe)
|
||||||
if response_len > 0:
|
if response_len > 0:
|
||||||
@ -474,8 +476,6 @@ DUPLEX = ["+", "", "-", "", "off", "", "split"] # (0,2,4,5)= (+,-,0, auto)
|
|||||||
|
|
||||||
SKIPS = ["", "S"]
|
SKIPS = ["", "S"]
|
||||||
|
|
||||||
BASETYPE_FT4 = ["FT-4XR", "FT-4XE"]
|
|
||||||
BASETYPE_FT65 = ["FT-65R"]
|
|
||||||
POWER_LEVELS = [chirp_common.PowerLevel("Low", watts=0.5),
|
POWER_LEVELS = [chirp_common.PowerLevel("Low", watts=0.5),
|
||||||
chirp_common.PowerLevel("Mid", watts=2.5),
|
chirp_common.PowerLevel("Mid", watts=2.5),
|
||||||
chirp_common.PowerLevel("High", watts=5.0)]
|
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
|
# 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 FT-65 class replaces the "prog" entry in this list.
|
||||||
# The name field must be the name of a slot array in MEM_FORMAT
|
# The name field must be the name of a slot array in MEM_FORMAT
|
||||||
SPECIALS = [
|
SPECIALS_FT4 = [
|
||||||
("pms", PMSNAMES),
|
("pms", PMSNAMES),
|
||||||
("vfo", ["VFO A UHF", "VFO A VHF", "VFO B FM", "VFO B VHF", "VFO B UHF"]),
|
("vfo", ["VFO A UHF", "VFO A VHF", "VFO B FM", "VFO B VHF", "VFO B UHF"]),
|
||||||
("home", ["HOME FM", "HOME VHF", "HOME UHF"]),
|
("home", ["HOME FM", "HOME VHF", "HOME UHF"]),
|
||||||
("prog", ["P1", "P2"])
|
("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_PROGS = ("prog", ["P1", "P2", "P3", "P4"])
|
||||||
FT65_SPECIALS = list(SPECIALS) # a shallow copy works here
|
SPECIALS_FT65[-1] = FT65_PROGS # replace the last entry (P key names)
|
||||||
FT65_SPECIALS[-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
|
# None, and 50 Tones. Use this explicit array because the
|
||||||
@ -620,8 +657,8 @@ class YaesuSC35GenericRadio(chirp_common.CloneModeRadio,
|
|||||||
chirp_common.ExperimentalRadio):
|
chirp_common.ExperimentalRadio):
|
||||||
"""
|
"""
|
||||||
Base class for all Yaesu radios using the SCU-35 programming cable
|
Base class for all Yaesu radios using the SCU-35 programming cable
|
||||||
and its protocol. Classes for specific radios extend this class and
|
and its protocol. Classes for sub families extend this class and
|
||||||
are found at the end of this file.
|
are found towards the end of this file.
|
||||||
"""
|
"""
|
||||||
VENDOR = "Yaesu"
|
VENDOR = "Yaesu"
|
||||||
MODEL = "SCU-35Generic" # No radio directly uses the base class
|
MODEL = "SCU-35Generic" # No radio directly uses the base class
|
||||||
@ -629,6 +666,12 @@ class YaesuSC35GenericRadio(chirp_common.CloneModeRadio,
|
|||||||
MAX_MEM_SLOT = 200
|
MAX_MEM_SLOT = 200
|
||||||
NEEDS_COMPAT_SERIAL = False
|
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
|
@classmethod
|
||||||
def get_prompts(cls):
|
def get_prompts(cls):
|
||||||
rp = chirp_common.RadioPrompts()
|
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_dtcs_polarity = False # REV TN reverses the tone, not the dcs
|
||||||
rf.has_cross = True
|
rf.has_cross = True
|
||||||
rf.has_settings = True
|
rf.has_settings = True
|
||||||
rf.valid_tuning_steps = self.legal_steps
|
|
||||||
|
|
||||||
return rf
|
return rf
|
||||||
|
|
||||||
@ -1027,14 +1069,11 @@ class YaesuSC35GenericRadio(chirp_common.CloneModeRadio,
|
|||||||
mem = chirp_common.Memory()
|
mem = chirp_common.Memory()
|
||||||
_mem, ndx, num, regtype, sname = self.slotloc(memref)
|
_mem, ndx, num, regtype, sname = self.slotloc(memref)
|
||||||
mem.number = num
|
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)
|
# First, we need to know whether a channel is enabled,
|
||||||
mem.power = POWER_LEVELS[_mem.tx_pwr]
|
# then we can process any channel parameters.
|
||||||
mem.mode = ["FM", "NFM"][_mem.tx_width]
|
# It was found (at least on an FT-25) that channels might be
|
||||||
mem.tuning_step = STEP_CODE[_mem.step]
|
# uninitialized and memory is just completely filled with 0xFF.
|
||||||
|
|
||||||
if regtype == "pms":
|
if regtype == "pms":
|
||||||
mem.extd_number = sname
|
mem.extd_number = sname
|
||||||
@ -1043,15 +1082,34 @@ class YaesuSC35GenericRadio(chirp_common.CloneModeRadio,
|
|||||||
mem.name = clean_name(self._memobj.names[ndx].chrs)
|
mem.name = clean_name(self._memobj.names[ndx].chrs)
|
||||||
mem.empty = not retrieve_bit(self._memobj.enable, ndx)
|
mem.empty = not retrieve_bit(self._memobj.enable, ndx)
|
||||||
mem.skip = SKIPS[retrieve_bit(self._memobj.scan, 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:
|
else:
|
||||||
mem.empty = False
|
mem.empty = False
|
||||||
mem.extd_number = sname
|
mem.extd_number = sname
|
||||||
mem.immutable = ["number", "extd_number", "name", "skip"]
|
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
|
return mem
|
||||||
|
|
||||||
def enforce_band(self, memloc, freq, mem_num, sname):
|
def enforce_band(self, memloc, freq, mem_num, sname):
|
||||||
@ -1105,28 +1163,16 @@ class YaesuSC35GenericRadio(chirp_common.CloneModeRadio,
|
|||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
@directory.register
|
class YaesuFT4GenericRadio(YaesuSC35GenericRadio):
|
||||||
class YaesuFT4Radio(YaesuSC35GenericRadio):
|
"""
|
||||||
MODEL = "FT-4XR"
|
FT-4 sub family class. Classes for individual radios extend
|
||||||
_basetype = BASETYPE_FT4
|
these classes and are found at the end of this file.
|
||||||
valid_bands = [
|
"""
|
||||||
(65000000, 108000000), # broadcast FM, receive only
|
class_specials = SPECIALS_FT4
|
||||||
(144000000, 148000000), # VHF, US version, TX and RX
|
Pkeys = 2 # number of programmable keys
|
||||||
(430000000, 450000000) # UHF, US version, TX and RX
|
namelen = 6 # length of the mem name display on the front-panel
|
||||||
# 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'
|
|
||||||
freq_offset_scale = 25000
|
freq_offset_scale = 25000
|
||||||
legal_steps = US_LEGAL_STEPS
|
|
||||||
class_group_descs = YaesuSC35GenericRadio.group_descriptions
|
class_group_descs = YaesuSC35GenericRadio.group_descriptions
|
||||||
class_specials = SPECIALS
|
|
||||||
# names for the setmode function for the programmable keys. Mode zero means
|
# names for the setmode function for the programmable keys. Mode zero means
|
||||||
# that the key is programmed for a memory not a setmode.
|
# that the key is programmed for a memory not a setmode.
|
||||||
SETMODES = [
|
SETMODES = [
|
||||||
@ -1143,31 +1189,19 @@ class YaesuFT4Radio(YaesuSC35GenericRadio):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@directory.register
|
class YaesuFT65GenericRadio(YaesuSC35GenericRadio):
|
||||||
class YaesuFT65Radio(YaesuSC35GenericRadio):
|
"""
|
||||||
MODEL = "FT-65R"
|
FT-65 sub family class. Classes for individual radios extend
|
||||||
_basetype = BASETYPE_FT65
|
these classes and are found at the end of this file.
|
||||||
valid_bands = [
|
"""
|
||||||
(65000000, 108000000), # broadcast FM, receive only
|
class_specials = SPECIALS_FT65
|
||||||
(144000000, 148000000), # VHF, US version, TX and RX
|
Pkeys = 4 # number of programmable keys
|
||||||
(430000000, 450000000) # UHF, US version, TX and RX
|
namelen = 8 # length of the mem name display on the front-panel
|
||||||
# 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'
|
|
||||||
freq_offset_scale = 50000
|
freq_offset_scale = 50000
|
||||||
legal_steps = US_LEGAL_STEPS
|
|
||||||
# we need a deep copy here because we are adding deeper than the top level.
|
# we need a deep copy here because we are adding deeper than the top level.
|
||||||
class_group_descs = copy.deepcopy(YaesuSC35GenericRadio.group_descriptions)
|
class_group_descs = copy.deepcopy(YaesuSC35GenericRadio.group_descriptions)
|
||||||
add_paramdesc(
|
add_paramdesc(
|
||||||
class_group_descs, "misc", ("compander", "Compander", ["OFF", "ON"]))
|
class_group_descs, "misc", ("compander", "Compander", ["OFF", "ON"]))
|
||||||
class_specials = FT65_SPECIALS
|
|
||||||
# names for the setmode function for the programmable keys. Mode zero means
|
# names for the setmode function for the programmable keys. Mode zero means
|
||||||
# that the key is programmed for a memory not a setmode.
|
# that the key is programmed for a memory not a setmode.
|
||||||
SETMODES = [
|
SETMODES = [
|
||||||
@ -1180,3 +1214,31 @@ class YaesuFT65Radio(YaesuSC35GenericRadio):
|
|||||||
"step", "tot", "tx pwr", "tx save", "vfo.spl", # 30-34
|
"step", "tot", "tx pwr", "tx save", "vfo.spl", # 30-34
|
||||||
"vox", "wfm.rcv", "wide/nar", "wx alert", "scramble" # 35-39
|
"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