[chirp_devel] FT-450D new driver
Rick DeWitt
Wed Jun 13 06:26:24 PDT 2018
Attached is the revised FT-450D patch file. I think I finally got the
Mercurial header process down.
I would like to lobby for a new "Information" prompt to allow the
developer to notify the user of special tips and support.
--
Rick DeWitt
AA0RD
Sequim, Washington, USA
Grid CN88jc
Phone: 1-360-681-3494
-------------- next part --------------
# HG changeset patch
# User Rick DeWitt <aa0rd at yahoo.com>
# Date 1528895651 25200
# Wed Jun 13 06:14:11 2018 -0700
# Node ID b3518d29a65d16976deefddc5abeb099adb847f0
# Parent d617bc1a1d64800cc83c0af9f2ac852445c92031
[ft450d] Add new driver for Yaesu FT-450D. Fixes issue #0951
diff -r d617bc1a1d64 -r b3518d29a65d chirp/drivers/ft450d.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chirp/drivers/ft450d.py Wed Jun 13 06:14:11 2018 -0700
@@ -0,0 +1,1483 @@
+# Copyright 2018 by Rick DeWitt (aa0rd at yahoo.com>
+# Thanks to Filippi Marco <iz3gme.marco at gmail.com> for Yaesu processes
+#
+# 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
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""FT450D Yaesu Radio Driver"""
+
+from chirp.drivers import yaesu_clone
+from chirp import chirp_common, util, memmap, errors, directory, bitwise
+from chirp.settings import RadioSetting, RadioSettingGroup, \
+ RadioSettingValueInteger, RadioSettingValueList, \
+ RadioSettingValueBoolean, RadioSettingValueString, \
+ RadioSettingValueFloat, RadioSettings
+import time
+import logging
+from textwrap import dedent
+
+LOG = logging.getLogger(__name__)
+
+CMD_ACK = 0x06
+# TBD: Enable some form of generated UI field, for the memory tags
+# That field wiould not be stored in img file, but generated in get_memory
+MEM_GRP_LBL = False # To ignore Comment channel-tags for now
+EX_MODES = ["USER-L", "USER-U", "LSB+CW", "USB+CW", "RTTY-L", "RTTY-U", "N/A"]
+for i in EX_MODES:
+ chirp_common.MODES.append(i)
+T_STEPS = sorted(list(chirp_common.TUNING_STEPS))
+T_STEPS.remove(30.0)
+T_STEPS.remove(100.0)
+T_STEPS.remove(125.0)
+T_STEPS.remove(200.0)
+
+ at directory.register
+class FT450DRadio(yaesu_clone.YaesuCloneModeRadio):
+ """Yaesu FT-450D"""
+ BAUD_RATE = 38400
+ COM_BITS = 8 # number of data bits
+ COM_PRTY = 'N' # parity checking
+ COM_STOP = 1 # stop bits
+ MODEL = "FT-450D"
+
+ DUPLEX = ["", "-", "+"]
+ MODES = ["LSB", "USB", "CW", "AM", "FM", "RTTY-L",
+ "USER-L", "USER-U", "NFM", "CWR"]
+ TMODES = ["", "Tone", "TSQL"]
+ STEPSFM = [5.0, 6.25, 10.0, 12.5, 15.0, 20.0, 25.0, 50.0]
+ STEPSAM = [2.5, 5.0, 9.0, 10.0, 12.5, 25.0]
+ STEPSSSB = [1.0, 2.5, 5.0]
+ VALID_BANDS = [(100000, 33000000), (33000000, 56000000)]
+ FUNC_LIST = ['MONI', 'N/A', 'PBAK', 'PLAY1', 'PLAY2', 'PLAY3', 'QSPLIT',
+ 'SPOT', 'SQLOFF', 'SWR', 'TXW', 'VCC', 'VOICE2', 'VM1MONI',
+ 'VM1REC', 'VM1TX', 'VM2MONI', 'VM2REC', 'VM2TX', 'DOWN', 'FAST',
+ 'UP', 'DSP', 'IPO/ATT', 'NB', 'AGC' , 'MODEDN', 'MODEUP',
+ 'DSP/SEL', 'KEYER', 'CLAR' , 'BANDDN', 'BANDUP', 'A=B', 'A/B',
+ 'LOCK', 'TUNE', 'VOICE', 'MW', 'V/M', 'HOME', 'RCL', 'VOX', 'STO',
+ 'STEP', 'SPLIT', 'PMS', 'SCAN', 'MENU', 'DIMMER', 'MTR']
+ CHARSET = list(chirp_common.CHARSET_ASCII)
+ CHARSET.remove("\\")
+
+ MEM_SIZE = 15017
+ # block 9 (135 Bytes long) is to be repeated 101 times
+ _block_lengths = [4, 84, 135, 162, 135, 162, 151, 130, 135, 127, 189, 103]
+
+ MEM_FORMAT = """
+ struct mem_struct { // 27 bytes per channel
+ u8 tag_on_off:2, // @ Byte 0 1=Off, 2=On
+ unk0:2,
+ mode:4;
+ u8 duplex:2, // @ byte 1
+ att:1,
+ ipo:1,
+ unka1:1,
+ tunerbad:1, // ?? Possible tuner failed
+ unk1b:1, // @@@???
+ uprband:1;
+ u8 cnturpk:1, // @ Byte 2 Peak (clr), Null (set)
+ cnturmd:3, // Contour filter mode
+ cnturgn:1, // Contour filter gain Low/high
+ mode2:3; // When mode is data(5)
+ u8 ssb_step:2, // @ Byte 3
+ am_step:3,
+ fm_step:3;
+ u8 tunerok:1, // @ Byte 4 ?? Poss tuned ok
+ cnturon:1,
+ unk4b:1,
+ dnr_on:1
+ notch:1,
+ unk4c:1,
+ tmode:2; // Tone/Cross/etc as Off/Enc/Enc+Dec
+ u8 unk5a:4, // @ byte 5
+ dnr_val:4;
+ u8 cw_width:2, // # byte 6, Notch width indexes
+ fm_width:2,
+ am_width:2,
+ sb_width:2;
+ i8 notch_pos; // @ Byte 7 Signed: - 0 +
+ u8 tone; // @ Byte 8
+ u8 unk9; // @ Byte 9 Always set to 0
+ u8 unkA; // @ Byte A
+ u8 unkB; // @ Byte B
+ u32 freq; // @ C-F
+ u32 offset; // @ 10-13
+ u8 name[7]; // @ 14-1A
+ };
+
+ #seekto 0x04;
+ struct {
+ u8 set04; // ?Checksum / Clone counter?
+ u8 set05; // Current VFO?
+ u8 set06;
+ u8 fast:1,
+ lock:1, // Inverted: 1 = Off
+ nb:1,
+ agc:5;
+ u8 set08a:3,
+ keyer:1,
+ set08b:2,
+ mtr_mode:2;
+ u8 set09;
+ u8 set0A;
+ u8 set0B:2,
+ clk_sft:1,
+ cont:5; // 1:1
+ u8 beepvol_sgn:1, // @x0C: set : Link @0x41, clear: fix @ 0x40
+ set0Ca:3,
+ clar_btn:1, // 0 = Dial, 1= SEL
+ cwstone_sgn:1, // Set: Lnk @ x42, clear: Fixed at 0x43
+ beepton:2; // Index 0-3
+ u8 set0Da:1,
+ cw_key:1,
+ set0Db:3,
+ dialstp_mode:1,
+ dialstp:2;
+ u8 set0E:1,
+ keyhold:1,
+ lockmod:1,
+ set0ea:1,
+ amfmdial:1, // 0= Enabled. 1 = Disabled
+ cwpitch:3; // 0-based index
+ u8 sql_rfg:1
+ set0F:2,
+ cwweigt:5; // Index 1:2.5=0 -> 1:4.5=20
+ u8 cw_dly; // @x10 ms = val * 10
+ u8 set11;
+ u8 cwspeed; // val 4-60 is wpm, *5 is cpm
+ u8 vox_gain; // val 1:1
+ u8 set14:2,
+ emergen:1,
+ vox_dly:5; // ms = val * 100
+ u8 set15a:1,
+ stby_beep:1
+ set15b:1
+ mem_grp:1,
+ apo:4;
+ u8 tot; // Byte x16, 1:1
+ u8 micscan:1,
+ set17:5,
+ micgain:2;
+ u8 cwpaddl:1, // @x18 0=Key, 1=Mic
+ set18:7;
+ u8 set19;
+ u8 set1A;
+ u8 set1B;
+ u8 set1C;
+ u8 dig_vox; // 1:1
+ u8 set1E;
+ i16 d_disp; // @ x1F,x20 signed 16bit
+ u8 pnl_cs; // 0-based index
+ u8 pm_up;
+ u8 pm_fst;
+ u8 pm_dwn;
+ u8 set25;
+ u8 set26;
+ u8 set27;
+ u8 set28;
+ u8 beacon_time; // 1:1
+ u8 set2A;
+ u8 cat_rts:1, // @x2b: Enable=0, Disable=1
+ peakhold:1,
+ set2B:4,
+ cat_tot:2; // Index 0-3
+ u8 set2CA:2,
+ rtyrpol:1,
+ rtytpol:1
+ rty_sft:2,
+ rty_ton:1,
+ set2CC:1;
+ u8 dig_vox; // 1:1
+ u8 ext_mnu:1,
+ m_tune:1,
+ set2E:2,
+ scn_res:4;
+ u8 cw_auto:1, // Off=0, On=1
+ cwtrain:2, // Index
+ set2F:1,
+ cw_qsk:2, // Index
+ cw_bfo:2; // Index
+ u8 mic_eq; // @x30 1:1
+ u8 set31:5,
+ catrate:3; // Index 0-4
+ u8 set32;
+ u8 dimmer:4,
+ set33:4;
+ u8 set34;
+ u8 set35;
+ u8 set36;
+ u8 set37;
+ u8 set38a:1,
+ rfpower:7; // 1:1
+ u8 set39a:2,
+ tuner:3, // Index 0-4
+ seldial:3; // Index 0-5
+ u8 set3A;
+ u8 set3B;
+ u8 set3C;
+ i8 qspl_f; // Signed
+ u8 set3E;
+ u8 set3F;
+ u8 beepvol_fix; // 1:1
+ i8 beepvol_lnk; // SIGNED 2's compl byte
+ u8 cwstone_fix;
+ i8 cwstone_lnk; // signed byte
+ u8 set44:2,
+ mym_data:1, // My Mode: Data, set = OFF
+ mym_fm:1,
+ mym_am:1,
+ mym_cw:1,
+ mym_usb:1,
+ mym_lsb:1;
+ u8 myb_24:1, // My Band: 24Mhz set = OFF
+ myb_21:1,
+ myb_18:1,
+ myb_14:1,
+ myb_10:1,
+ myb_7:1,
+ myb_3_5:1,
+ myb_1_8:1;
+ u8 set46:6,
+ myb_28:1,
+ myb_50:1;
+ u8 set47;
+ u8 set48;
+ u8 set49;
+ u8 set4A;
+ u8 set4B;
+ u8 set4C;
+ u8 set4D;
+ u8 set4E;
+ u8 set4F;
+ u8 set50;
+ u8 set51;
+ u8 set52;
+ u8 set53;
+ u8 set54;
+ u8 set55;
+ u8 set56a:3,
+ split:1,
+ set56b:4;
+ u8 set57;
+ } settings;
+
+ #seekto 0x58;
+ struct mem_struct vfoa[11]; // The current cfgs for each vfo 'band'
+ struct mem_struct vfob[11];
+ struct mem_struct home[2]; // The 2 Home cfgs (HF and 6m)
+ struct mem_struct qmb; // The Quick Memory Bank STO/RCL
+ struct mem_struct mtqmb; // Last QMB-MemTune cfg (not displayed)
+ struct mem_struct mtune; // Last MemTune cfg (not displayed)
+
+ #seekto 0x343; // chan status
+ u8 visible[63]; // 1 bit per channel
+ u8 pmsvisible; // @ 0x382
+
+ #seekto 0x383;
+ u8 filled[63];
+ u8 pmsfilled; // @ 0x3c2
+
+ #seekto 0x3C3;
+ struct mem_struct memory[500];
+ struct mem_struct pms[4]; // Programed Scan limits @ x387F
+
+ #seekto 0x3906;
+ struct {
+ char t1[40]; // CW Beacon Text
+ char t2[40];
+ char t3[40];
+ } beacontext; // to 0x397E
+
+ #seekto 0x3985;
+ struct mem_struct m60[5]; // to 0x3A0B
+
+ #seekto 0x03a45;
+ struct mem_struct current;
+
+ """
+ _CALLSIGN_CHARSET = [chr(x) for x in range(ord("0"), ord("9") + 1) +
+ range(ord("A"), ord("Z") + 1) + [ord(" ")]]
+ _CALLSIGN_CHARSET_REV = dict(zip(_CALLSIGN_CHARSET,
+ range(0, len(_CALLSIGN_CHARSET))))
+
+ # WARNING Indecis are hard wired in get/set_memory code !!!
+ # Channels print in + increasing index order (PMS first)
+ SPECIAL_MEMORIES = {
+ "VFOa-1.8M": -27,
+ "VFOa-3.5M": -26,
+ "VFOa-7M": -25,
+ "VFOa-10M": -24,
+ "VFOa-14M": -23,
+ "VFOa-18M": -22,
+ "VFOa-21M": -21,
+ "VFOa-24M": -20,
+ "VFOa-28M": -19,
+ "VFOa-50M": -18,
+ "VFOa-HF": -17,
+ "VFOb-1.8M": -16,
+ "VFOb-3.5M": -15,
+ "VFOb-7M": -14,
+ "VFOb-10M": -13,
+ "VFOb-14M": -12,
+ "VFOb-18M": -11,
+ "VFOb-21M": - 10,
+ "VFOb-24M": -9,
+ "VFOb-28M": -8,
+ "VFOb-50M": -7,
+ "VFOb-HF": -6,
+ "HOME-HF": -5,
+ "HOME-50M": -4,
+ "QMB": -3,
+ "QMB-MTune": -2,
+ "Mem-Tune": -1,
+ }
+ FIRST_VFOB_INDEX = -6
+ LAST_VFOB_INDEX = -16
+ FIRST_VFOA_INDEX = -17
+ LAST_VFOA_INDEX = -27
+
+ SPECIAL_PMS = {
+ "PMS1-L": -36,
+ "PMS1-U": -35,
+ "PMS2-L": -34,
+ "PMS2-U": -33,
+ }
+ LAST_PMS_INDEX = -36
+ SPECIAL_MEMORIES.update(SPECIAL_PMS)
+
+ SPECIAL_60M = {
+ "60m-Ch1": -32,
+ "60m-Ch2": -31,
+ "60m-Ch3": -30,
+ "60m-Ch4": -29,
+ "60m-Ch5": -28,
+ }
+ LAST_60M_INDEX = -32
+ SPECIAL_MEMORIES.update(SPECIAL_60M)
+
+ SPECIAL_MEMORIES_REV = dict(zip(SPECIAL_MEMORIES.values(),
+ SPECIAL_MEMORIES.keys()))
+
+ @classmethod
+ def get_prompts(cls):
+ rp = chirp_common.RadioPrompts()
+ rp.pre_download = _(dedent("""\
+ Note that this radio has 'Special Channels' and generates an
+ 'Other' tab in the channel memory Properties window...
+ 1. Turn radio off.
+ 2. Connect cable to ACC jack.
+ 3. Press and hold in the [MODE <] and [MODE >] keys while
+ turning the radio on ("CLONE MODE" will appear on the
+ display).
+ 4. <b>After clicking OK</b> here, press the [C.S.] key to
+ send image."""))
+ rp.pre_upload = _(dedent("""\
+ 1. Turn radio off.
+ 2. Connect cable to ACC jack.
+ 3. Press and hold in the [MODE <] and [MODE >] keys while
+ turning the radio on ("CLONE MODE" will appear on the
+ display).
+ 4. Click OK here.
+ ("Receiving" will appear on the LCD)."""))
+ return rp
+
+ def _read(self, block, blocknum):
+ # be very patient at first block
+ if blocknum == 0:
+ attempts = 60
+ else:
+ attempts = 5
+ for _i in range(0, attempts):
+ data = self.pipe.read(block + 2) # Blocknum, data,checksum
+ if data:
+ break
+ time.sleep(0.5)
+ if len(data) == block + 2 and data[0] == chr(blocknum):
+ checksum = yaesu_clone.YaesuChecksum(1, block)
+ if checksum.get_existing(data) != \
+ checksum.get_calculated(data):
+ raise Exception("Checksum Failed [%02X<>%02X] block %02X" %
+ (checksum.get_existing(data),
+ checksum.get_calculated(data), blocknum))
+ # Remove the block number and checksum
+ data = data[1:block + 1]
+ else: # Use this info to decode a new Yaesu model
+ raise Exception("Unable to read block %i expected %i got %i"
+ % (blocknum, block + 2, len(data)))
+ return data
+
+ def _clone_in(self):
+ # Be very patient with the radio
+ self.pipe.timeout = 2
+ self.pipe.baudrate = self.BAUD_RATE
+ self.pipe.bytesize = self.COM_BITS
+ self.pipe.parity = self.COM_PRTY
+ self.pipe.stopbits = self.COM_STOP
+ self.pipe.rtscts = False
+
+ start = time.time()
+
+ data = ""
+ blocks = 0
+ status = chirp_common.Status()
+ status.msg = _("Cloning from radio")
+ nblocks = len(self._block_lengths) + 100 # Block 8 repeats
+ status.max = nblocks
+ for block in self._block_lengths:
+ if blocks == 8:
+ # repeated read of block 8 same size (chan memory area)
+ repeat = 101
+ else:
+ repeat = 1
+ for _i in range(0, repeat):
+ data += self._read(block, blocks)
+ self.pipe.write(chr(CMD_ACK))
+ blocks += 1
+ status.cur = blocks
+ self.status_fn(status)
+ data += self.MODEL # Append ID
+ return memmap.MemoryMap(data)
+
+ def _clone_out(self):
+ self.pipe.baudrate = self.BAUD_RATE
+ self.pipe.bytesize = self.COM_BITS
+ self.pipe.parity = self.COM_PRTY
+ self.pipe.stopbits = self.COM_STOP
+ self.pipe.rtscts = False
+ delay = 0.5
+ start = time.time()
+ blocks = 0
+ pos = 0
+ status = chirp_common.Status()
+ status.msg = _("Cloning to radio")
+ status.max = len(self._block_lengths) + 100
+ for block in self._block_lengths:
+ if blocks == 8:
+ repeat = 101
+ else:
+ repeat = 1
+ for _i in range(0, repeat):
+ time.sleep(0.01)
+ checksum = yaesu_clone.YaesuChecksum(pos, pos + block - 1)
+ self.pipe.write(chr(blocks))
+ self.pipe.write(self.get_mmap()[pos:pos + block])
+ self.pipe.write(chr(checksum.get_calculated(self.get_mmap())))
+ buf = self.pipe.read(1)
+ if not buf or buf[0] != chr(CMD_ACK):
+ time.sleep(delay)
+ buf = self.pipe.read(1)
+ if not buf or buf[0] != chr(CMD_ACK):
+ raise Exception(_("Radio did not ack block %i") % blocks)
+ pos += block
+ blocks += 1
+ status.cur = blocks
+ self.status_fn(status)
+
+
+ def sync_in(self):
+ try:
+ self._mmap = self._clone_in()
+ except errors.RadioError:
+ raise
+ except Exception, e:
+ raise errors.RadioError("Failed to communicate with radio: %s"
+ % e)
+ self.process_mmap()
+
+ def sync_out(self):
+ try:
+ self._clone_out()
+ except errors.RadioError:
+ raise
+ except Exception, e:
+ raise errors.RadioError("Failed to communicate with radio: %s"
+ % e)
+
+ def process_mmap(self):
+ self._memobj = bitwise.parse(self.MEM_FORMAT, self._mmap)
+
+ def get_features(self):
+ rf = chirp_common.RadioFeatures()
+ rf.has_bank = False
+ rf.has_dtcs= False
+ if MEM_GRP_LBL:
+ rf.has_comment = True # Used for Mem-Grp number
+ rf.valid_modes = list(set(self.MODES))
+ rf.valid_tmodes = list(self.TMODES)
+ rf.valid_duplexes = list(self.DUPLEX)
+ rf.valid_tuning_steps = list(T_STEPS)
+ rf.valid_bands = self.VALID_BANDS
+ rf.valid_power_levels = []
+ rf.valid_characters = "".join(self.CHARSET)
+ rf.valid_name_length = 7
+ rf.valid_skips = []
+ rf.valid_special_chans = sorted(self.SPECIAL_MEMORIES.keys())
+ rf.memory_bounds = (1, 500)
+ rf.has_ctone = True
+ rf.has_settings = True
+ rf.has_cross = True
+ return rf
+
+ def get_raw_memory(self, number):
+ return repr(self._memobj.memory[number - 1])
+
+ def _get_tmode(self, mem, _mem):
+ mem.tmode = self.TMODES[_mem.tmode]
+ mem.rtone = chirp_common.TONES[_mem.tone]
+ mem.ctone = mem.rtone
+
+ def _set_duplex(self, mem, _mem):
+ _mem.duplex = self.DUPLEX.index(mem.duplex)
+
+ def get_memory(self, number):
+ if isinstance(number, str):
+ return self._get_special(number)
+ elif number < 0:
+ # I can't stop delete operation from loosing extd_number but
+ # I know how to get it back
+ return self._get_special(self.SPECIAL_MEMORIES_REV[number])
+ else:
+ return self._get_normal(number)
+
+ def set_memory(self, memory):
+ if memory.number < 0:
+ return self._set_special(memory)
+ else:
+ return self._set_normal(memory)
+
+ def _get_special(self, number):
+ mem = chirp_common.Memory()
+ mem.number = self.SPECIAL_MEMORIES[number]
+ mem.extd_number = number
+
+ if mem.number in range(self.FIRST_VFOA_INDEX,
+ self.LAST_VFOA_INDEX - 1, -1):
+ _mem = self._memobj.vfoa[-self.LAST_VFOA_INDEX + mem.number]
+ immutable = ["number", "extd_number", "name", "power"]
+ elif mem.number in range(self.FIRST_VFOB_INDEX,
+ self.LAST_VFOB_INDEX - 1, -1):
+ _mem = self._memobj.vfob[-self.LAST_VFOB_INDEX + mem.number]
+ immutable = ["number", "extd_number", "name", "power"]
+ elif mem.number in range(-4, -6, -1): # 2 Home Chans
+ _mem = self._memobj.home[5 + mem.number]
+ immutable = ["number", "extd_number", "name", "power"]
+ elif mem.number == -3:
+ _mem = self._memobj.qmb
+ immutable = ["number", "extd_number", "name", "power"]
+ elif mem.number == -2:
+ _mem = self._memobj.mtqmb
+ immutable = ["number", "extd_number", "name", "power"]
+ elif mem.number == -1:
+ _mem = self._memobj.mtune
+ immutable = ["number", "extd_number", "name", "power"]
+ elif mem.number in self.SPECIAL_PMS.values():
+ bitindex = (-self.LAST_PMS_INDEX) + mem.number
+ used = (self._memobj.pmsvisible >> bitindex) & 0x01
+ valid = (self._memobj.pmsfilled >> bitindex) & 0x01
+ if not used:
+ mem.empty = True
+ if not valid:
+ mem.empty = True
+ return mem
+ mx = (-self.LAST_PMS_INDEX) + mem.number
+ _mem = self._memobj.pms[mx]
+ mx = mx + 1
+ if MEM_GRP_LBL:
+ mem.comment = "M-11-%02i" % mx
+ immutable = ["number", "rtone", "ctone", "extd_number",
+ "tmode", "cross_mode",
+ "power", "duplex", "offset"]
+ elif mem.number in self.SPECIAL_60M.values():
+ mx = (-self.LAST_60M_INDEX) + mem.number
+ _mem = self._memobj.m60[mx]
+ mx = mx + 1
+ if MEM_GRP_LBL:
+ mem.comment = "M-12-%02i" % mx
+ immutable = ["number", "rtone", "ctone", "extd_number",
+ "tmode", "cross_mode",
+ "frequency", "power", "duplex", "offset"]
+ else:
+ raise Exception("Sorry, you can't edit that special"
+ " memory channel %i." % mem.number)
+
+ mem = self._get_memory(mem, _mem)
+ mem.immutable = immutable
+
+ return mem
+
+ def _set_special(self, mem):
+ if mem.empty and mem.number not in self.SPECIAL_PMS.values():
+ # can't delete special memories!
+ raise Exception("Sorry, special memory can't be deleted")
+
+ cur_mem = self._get_special(self.SPECIAL_MEMORIES_REV[mem.number])
+
+ if mem.number in range(self.FIRST_VFOA_INDEX,
+ self.LAST_VFOA_INDEX - 1, -1):
+ _mem = self._memobj.vfoa[-self.LAST_VFOA_INDEX + mem.number]
+ elif mem.number in range(self.FIRST_VFOB_INDEX,
+ self.LAST_VFOB_INDEX - 1, -1):
+ _mem = self._memobj.vfob[-self.LAST_VFOB_INDEX + mem.number]
+ elif mem.number in range(-4, -6, -1):
+ _mem = self._memobj.home[5 + mem.number]
+ elif mem.number == -3:
+ _mem = self._memobj.qmb
+ elif mem.number == -2:
+ _mem = self._memobj.mtqmb
+ elif mem.number == -1:
+ _mem = self._memobj.mtune
+ elif mem.number in self.SPECIAL_PMS.values():
+ bitindex = (-self.LAST_PMS_INDEX) + mem.number
+ wasused = (self._memobj.pmsvisible >> bitindex) & 0x01
+ wasvalid = (self._memobj.pmsfilled >> bitindex) & 0x01
+ if mem.empty:
+ if wasvalid and not wasused:
+ # pylint get confused by &= operator
+ self._memobj.pmsfilled = self._memobj.pmsfilled & \
+ ~ (1 << bitindex)
+ # pylint get confused by &= operator
+ self._memobj.pmsvisible = self._memobj.pmsvisible & \
+ ~ (1 << bitindex)
+ return
+ # pylint get confused by |= operator
+ self._memobj.pmsvisible = self._memobj.pmsvisible | 1 << bitindex
+ self._memobj.pmsfilled = self._memobj.pmsfilled | 1 << bitindex
+ _mem = self._memobj.pms[-self.LAST_PMS_INDEX + mem.number]
+ else:
+ raise Exception("Sorry, you can't edit"
+ " that special memory.")
+
+ for key in cur_mem.immutable:
+ if key != "extd_number":
+ if cur_mem.__dict__[key] != mem.__dict__[key]:
+ raise errors.RadioError("Editing field `%s' " % key +
+ "is not supported on this channel")
+
+ self._set_memory(mem, _mem)
+
+ def _get_normal(self, number):
+ _mem = self._memobj.memory[number - 1]
+ used = (self._memobj.visible[(number - 1) / 8] >> (number - 1) % 8) \
+ & 0x01
+ valid = (self._memobj.filled[(number - 1) / 8] >> (number - 1) % 8) \
+ & 0x01
+
+ mem = chirp_common.Memory()
+ mem.number = number
+ if not used:
+ mem.empty = True
+ if not valid or _mem.freq == 0xffffffff:
+ return mem
+ if MEM_GRP_LBL:
+ mgrp = int((number - 1) / 50)
+ mem.comment = "M-%02i-%02i" % (mgrp + 1, number - (mgrp * 50))
+ return self._get_memory(mem, _mem)
+
+ def _set_normal(self, mem):
+ _mem = self._memobj.memory[mem.number - 1]
+ wasused = (self._memobj.visible[(mem.number - 1) / 8] >>
+ (mem.number - 1) % 8) & 0x01
+ wasvalid = (self._memobj.filled[(mem.number - 1) / 8] >>
+ (mem.number - 1) % 8) & 0x01
+
+ if mem.empty:
+ if mem.number == 1:
+ raise Exception("Sorry, can't delete first memory")
+ if wasvalid and not wasused:
+ self._memobj.filled[(mem.number - 1) / 8] &= \
+ ~(1 << (mem.number - 1) % 8)
+ _mem.set_raw("\xFF" * (_mem.size() / 8)) # clean up
+ self._memobj.visible[(mem.number - 1) / 8] &= \
+ ~(1 << (mem.number - 1) % 8)
+ return
+ if not wasvalid:
+ _mem.set_raw("\x00" * (_mem.size() / 8)) # clean up
+
+ self._memobj.visible[(mem.number - 1) / 8] |= 1 << (mem.number - 1) \
+ % 8
+ self._memobj.filled[(mem.number - 1) / 8] |= 1 << (mem.number - 1) \
+ % 8
+ self._set_memory(mem, _mem)
+
+ def _get_memory(self, mem, _mem):
+ mem.freq = int(_mem.freq)
+ mem.offset = int(_mem.offset)
+ mem.duplex = self.DUPLEX[_mem.duplex]
+ # Mode gets tricky with dual (USB+DATA) options
+ vx = _mem.mode
+ if vx == 4: # FM or NFM
+ if _mem.mode2 == 2:
+ vx = 4 # FM
+ else:
+ vx = 8 # NFM
+ if vx == 10: # CWR
+ vx = 9
+ if vx == 5: # Data/Dual mode
+ if _mem.mode2 == 0: # RTTY-L
+ vx = 5
+ if _mem.mode2 == 1: # USER-L
+ vx = 6
+ if _mem.mode2 == 2: # USER-U
+ vx = 7
+ mem.mode = self.MODES[vx]
+ if mem.mode == "FM" or mem.mode == "NFM":
+ mem.tuning_step = self.STEPSFM[_mem.fm_step]
+ elif mem.mode == "AM":
+ mem.tuning_step = self.STEPSAM[_mem.am_step]
+ elif mem.mode[:2] == "CW":
+ mem.tuning_step = self.STEPSSSB[_mem.ssb_step]
+ else:
+ try:
+ mem.tuning_step = self.STEPSSSB[_mem.ssb_step]
+ except IndexError:
+ pass
+ self._get_tmode(mem, _mem)
+
+ if _mem.tag_on_off == 2:
+ for i in _mem.name:
+ if i == 0xFF:
+ break
+ if chr(i) in self.CHARSET:
+ mem.name += chr(i)
+ else:
+ # radio has some graphical chars that are not supported
+ # we replace those with a *
+ LOG.info("Replacing char %x with *" % i)
+ mem.name += "*"
+ mem.name = mem.name.rstrip()
+ else:
+ mem.name = ""
+
+ mem.extra = RadioSettingGroup("extra", "Extra")
+
+ rs = RadioSetting("ipo", "IPO",
+ RadioSettingValueBoolean(bool(_mem.ipo)))
+ rs.set_doc("Bypass preamp")
+ mem.extra.append(rs)
+
+ rs = RadioSetting("att", "ATT",
+ RadioSettingValueBoolean(bool(_mem.att)))
+ rs.set_doc("10dB front end attenuator")
+ mem.extra.append(rs)
+
+ rs = RadioSetting("cnturon", "Contour Filter",
+ RadioSettingValueBoolean(_mem.cnturon ))
+ rs.set_doc("Contour filter on/off")
+ mem.extra.append(rs)
+
+ options = ["Peak", "Null"]
+ rs = RadioSetting("cnturpk", "Contour Filter Mode",
+ RadioSettingValueList(options,
+ options[_mem.cnturpk]))
+ mem.extra.append(rs)
+
+ options = ["Low", "High"]
+ rs = RadioSetting("cnturgn", "Contour Filter Gain",
+ RadioSettingValueList(options,
+ options[_mem.cnturgn]))
+ rs.set_doc("Filter gain/attenuation")
+ mem.extra.append(rs)
+
+ options = ["-2", "-1", "Center", "+1", "+2"]
+ rs = RadioSetting("cnturmd", "Contour Filter Notch",
+ RadioSettingValueList(options,
+ options[_mem.cnturmd]))
+ rs.set_doc("Filter notch offset")
+ mem.extra.append(rs)
+
+ rs = RadioSetting("notch", "Notch Filter",
+ RadioSettingValueBoolean(_mem.notch ))
+ rs.set_doc("IF bandpass filter")
+ mem.extra.append(rs)
+
+ vx = 1
+ options = ["<-", "Center", "+>"]
+ if _mem.notch_pos < 0:
+ vx = 0
+ if _mem.notch_pos > 0:
+ vx = 2
+ rs = RadioSetting("notch_pos", "Notch Position",
+ RadioSettingValueList(options, options[vx]))
+ rs.set_doc("IF bandpass filter shift")
+ mem.extra.append(rs)
+
+ vx = 0
+ if mem.mode[1:] == "SB":
+ options = ["1.8kHz", "2.4kHz", "3.0kHz"]
+ vx = _mem.sb_width
+ stx = "sb_width"
+ elif mem.mode[:1] == "CW":
+ options = ["300Hz", "500 kHz", "2.4kHz"]
+ vx = _mem.cw_width
+ stx = "cw_width"
+ elif mem.mode[:4] == "USER" or mem.mode[:4] == "RTTY":
+ options = ["300Hz", "2.4kHz", "3.0kHz"]
+ vx = _mem.sb_width
+ stx = "sb_width"
+ elif mem.mode == "AM":
+ options = ["3.0kHz", "6.0kHz", "9.0 kHz"]
+ vx = _mem.am_width
+ stx = "am_width"
+ else:
+ options = ["2.5kHz", "5.0kHz"]
+ vx = _mem.fm_width
+ stx = "fm_width"
+ rs = RadioSetting(stx, "IF Bandpass Filter Width",
+ RadioSettingValueList(options, options[vx]))
+ rs.set_doc("DSP IF bandpass Notch width (Hz)")
+ mem.extra.append(rs)
+
+ rs = RadioSetting("dnr_on", "DSP Noise Reduction",
+ RadioSettingValueBoolean(bool(_mem.dnr_on)))
+ rs.set_doc("Digital noise processing")
+ mem.extra.append(rs)
+
+ options = ["Off", "1", "2", "3", "4", "5", "6", "7",
+ "8", "9", "10", "11"]
+ rs = RadioSetting("dnr_val", "DSP Noise Reduction Alg",
+ RadioSettingValueList(options,
+ options[ _mem.dnr_val]))
+ rs.set_doc("Digital noise reduction algorithm number (1-11)")
+ mem.extra.append(rs)
+
+ return mem # end get_memory
+
+ def _set_memory(self, mem, _mem):
+ if len(mem.name) > 0:
+ _mem.tag_on_off = 2
+ else:
+ _mem.tag_on_off = 1
+ self._set_duplex(mem, _mem)
+ _mem.mode2 = 0
+ if mem.mode == "USER-L":
+ _mem.mode = 5
+ _mem.mode2 = 1
+ elif mem.mode == "USER-U":
+ _mem.mode = 5
+ _mem.mode2 = 2
+ elif mem.mode == "RTTY-L":
+ _mem.mode = 5
+ _mem.mode2 = 0
+ elif mem.mode == "CWR":
+ _mem.mode = 10
+ _mem.mode2 = 0
+ elif mem.mode == "CW":
+ _mem.mode = 2
+ _mem.mode2 = 0
+ elif mem.mode == "NFM":
+ _mem.mode = 4
+ _mem.mode2 = 1
+ elif mem.mode == "FM":
+ _mem.mode = 4
+ _mem.mode2 = 2
+ else: # LSB, USB, AM
+ _mem.mode = self.MODES.index(mem.mode)
+ _mem.mode2 = 0
+ try:
+ _mem.ssb_step = self.STEPSSSB.index(mem.tuning_step)
+ except ValueError:
+ pass
+ try:
+ _mem.am_step = self.STEPSAM.index(mem.tuning_step)
+ except ValueError:
+ pass
+ try:
+ _mem.fm_step = self.STEPSFM.index(mem.tuning_step)
+ except ValueError:
+ pass
+ _mem.freq = mem.freq
+ _mem.uprband = 0
+ if mem.freq >= 33000000:
+ _mem.uprband = 1
+ _mem.offset = mem.offset
+ _mem.tmode = self.TMODES.index(mem.tmode)
+ _mem.tone = chirp_common.TONES.index(mem.rtone)
+ _mem.tunerok = 0 # Dont know what these two do...
+ _mem.tunerbad = 0
+
+ for i in range(0, 7):
+ _mem.name[i] = ord(mem.name.ljust(7)[i])
+
+ for setting in mem.extra:
+ if setting.get_name() == "notch_pos":
+ vx = 0 # Overide list string with signed value
+ stx = str(setting.value)
+ if stx == "<-":
+ vx = -13
+ if stx == "+>":
+ vx = 12
+ setattr(_mem, "notch_pos", vx)
+ elif setting.get_name() == "dnr_val":
+ stx = str(setting.value) # Convert string to int
+ vx = 0
+ if stx != "Off":
+ vx = int(stx)
+ else:
+ setattr(_mem, "dnr_on", 0)
+ setattr(_mem, setting.get_name(), vx)
+ else:
+ setattr(_mem, setting.get_name(), setting.value)
+
+
+ @classmethod
+ def match_model(cls, filedata, filename):
+ """Match the opened/downloaded image to the correct version"""
+ if len(filedata) == cls.MEM_SIZE + 7: # +7 bytes of model name
+ rid = filedata[cls.MEM_SIZE:cls.MEM_SIZE + 7]
+ if rid.startswith(cls.MODEL):
+ return True
+ else:
+ return False
+
+ def _invert_me(self, setting, obj, atrb):
+ """Callback: from inverted logic 1-bit booleans"""
+ invb = not setting.value
+ setattr(obj, atrb, invb)
+ return
+
+ def _chars2str(self, cary, knt):
+ """Convert raw memory char array to a string: NOT a callback."""
+ stx = ""
+ for char in cary[:knt]:
+ stx += chr(char)
+ return stx
+
+ def _my_str2ary(self, setting, obj, atrba, knt):
+ """Callback: convert string to fixed-length char array.."""
+ ary = ""
+ for j in range(0, knt, 1):
+ chx = ord(str(setting.value)[j])
+ if chx < 32 or chx > 125: # strip non-printing
+ ary += " "
+ else:
+ ary += str(setting.value)[j]
+ setattr(obj, atrba, ary)
+ return
+
+ def get_settings(self):
+ _settings = self._memobj.settings
+ _beacon = self._memobj.beacontext
+ gen = RadioSettingGroup("gen", "General")
+ cw = RadioSettingGroup("cw", "CW")
+ pnlcfg = RadioSettingGroup("pnlcfg", "Panel buttons")
+ pnlset = RadioSettingGroup("pnlset", "Panel settings")
+ voxdat = RadioSettingGroup("voxdat", "VOX and Data")
+ mic = RadioSettingGroup("mic", "Microphone")
+ mybands = RadioSettingGroup("mybands", "My Bands")
+ mymodes = RadioSettingGroup("mymodes", "My Modes")
+
+ top = RadioSettings(gen, cw, pnlcfg, pnlset, voxdat, mic,
+ mymodes, mybands)
+
+ self._do_general_settings(gen)
+ self._do_cw_settings(cw)
+ self._do_panel_buttons(pnlcfg)
+ self._do_panel_settings(pnlset)
+ self._do_vox_settings(voxdat)
+ self._do_mic_settings(mic)
+ self._do_mymodes_settings(mymodes)
+ self._do_mybands_settings(mybands)
+
+ return top
+
+ def _do_general_settings(self, tab):
+ _settings = self._memobj.settings
+
+ rs = RadioSetting("ext_mnu", "Extended menu",
+ RadioSettingValueBoolean(_settings.ext_mnu))
+ rs.set_doc("Enables access to extended settings in the radio")
+ tab.append(rs)
+
+ rs = RadioSetting("apo", "APO time (Hrs)",
+ RadioSettingValueInteger(1, 12, _settings.apo))
+ tab.append(rs)
+
+ options = ["%i" % i for i in range(0, 21)]
+ options[0] = "Off"
+ rs = RadioSetting("tot", "TX 'TOT' time-out (mins)",
+ RadioSettingValueList(options,
+ options[_settings.tot]))
+ tab.append(rs)
+
+ bx = not _settings.cat_rts # Convert from Enable=0
+ rs = RadioSetting("cat_rts", "CAT RTS flow control",
+ RadioSettingValueBoolean(bx))
+ rs.set_apply_callback(self._invert_me, _settings, "cat_rts")
+ tab.append(rs)
+
+ options = ["0", "100ms", "1000ms", "3000ms"]
+ rs = RadioSetting("cat_tot", "CAT Timeout",
+ RadioSettingValueList(options,
+ options[_settings.cat_tot]))
+ tab.append(rs)
+
+ options = ["4800", "9600", "19200", "38400", "Data"]
+ rs = RadioSetting("catrate", "CAT rate",
+ RadioSettingValueList(options,
+ options[_settings.catrate]))
+ tab.append(rs)
+
+ rs = RadioSetting("mem_grp", "Mem groups",
+ RadioSettingValueBoolean(_settings.mem_grp))
+ tab.append(rs)
+
+ rs = RadioSetting("scn_res", "Resume scan (secs)",
+ RadioSettingValueInteger(0, 10, _settings.scn_res))
+ tab.append(rs)
+
+ rs = RadioSetting("clk_sft", "CPU clock shift",
+ RadioSettingValueBoolean(_settings.clk_sft))
+ tab.append(rs)
+
+ rs = RadioSetting("split", "TX/RX Frequency Split",
+ RadioSettingValueBoolean(_settings.split))
+ tab.append(rs)
+
+ rs = RadioSetting("qspl_f", "Quick-Split freq offset (KHz)",
+ RadioSettingValueInteger(-20, 20, _settings.qspl_f))
+ tab.append(rs)
+
+ rs = RadioSetting("emergen", "Alaska Emergency Mem 5167.5KHz",
+ RadioSettingValueBoolean(_settings.emergen))
+ tab.append(rs)
+
+ rs = RadioSetting("stby_beep", "PTT release 'Standby' beep",
+ RadioSettingValueBoolean(_settings.stby_beep))
+ tab.append(rs)
+
+ options = ["ATAS", "EXT ATU", "INT ATU", "INTRATU", "F-TRANS"]
+ rs = RadioSetting("tuner", "Antenna Tuner",
+ RadioSettingValueList(options,
+ options[_settings.tuner]))
+ tab.append(rs)
+
+ rs = RadioSetting("rfpower", "RF power (watts)",
+ RadioSettingValueInteger(5, 100, _settings.rfpower))
+ tab.append(rs) # End of _do_general_settings
+
+
+ def _do_cw_settings(self, cw): # - - - CW - - -
+ _settings = self._memobj.settings
+ _beacon = self._memobj.beacontext
+
+ rs = RadioSetting("cw_dly", "CW break-in delay (ms * 10)",
+ RadioSettingValueInteger(0, 300, _settings.cw_dly))
+ cw.append(rs)
+
+ options = ["%i Hz" % i for i in range(400, 801, 100)]
+ rs = RadioSetting("cwpitch", "CW pitch",
+ RadioSettingValueList(options,
+ options[_settings.cwpitch]))
+ cw.append(rs)
+
+ rs = RadioSetting("cwspeed", "CW speed (wpm)",
+ RadioSettingValueInteger(4, 60, _settings.cwspeed))
+ rs.set_doc("Cpm is Wpm * 5")
+ cw.append(rs)
+
+ options = ["1:%1.1f" % (i / 10) for i in range(25, 46, 1)]
+ rs = RadioSetting("cwweigt", "CW weight",
+ RadioSettingValueList(options,
+ options[_settings.cwweigt]))
+ cw.append(rs)
+
+ options = ["15ms", "20ms", "25ms", "30ms"]
+ rs = RadioSetting("cw_qsk", "CW delay before TX in QSK mode",
+ RadioSettingValueList(options,
+ options[_settings.cw_qsk]))
+ cw.append(rs)
+
+ rs = RadioSetting("cwstone_sgn", "CW sidetone volume Linked",
+ RadioSettingValueBoolean(_settings.cwstone_sgn))
+ rs.set_doc("If set; volume is relative to AF Gain knob.")
+ cw.append(rs)
+
+ rs = RadioSetting("cwstone_lnk", "CW sidetone linked volume",
+ RadioSettingValueInteger(-50, 50,
+ _settings.cwstone_lnk))
+ cw.append(rs)
+
+ rs = RadioSetting("cwstone_fix", "CW sidetone fixed volume",
+ RadioSettingValueInteger(0, 100,
+ _settings.cwstone_fix))
+ cw.append(rs)
+
+ options = [ "Numeric", "Alpha", "Mixed"]
+ rs = RadioSetting("cwtrain", "CW Training mode",
+ RadioSettingValueList(options,
+ options[_settings.cwtrain]))
+ cw.append(rs)
+
+ rs = RadioSetting("cw_auto", "CW key jack- auto CW mode",
+ RadioSettingValueBoolean(_settings.cw_auto))
+ rs.set_doc("Enable for CW mode auto-set when keyer pluuged in.")
+ cw.append(rs)
+
+ options = ["Normal", "Reverse"]
+ rs = RadioSetting("cw_key", "CW paddle wiring",
+ RadioSettingValueList(options,
+ options[_settings.cw_key]))
+ cw.append(rs)
+
+ rs = RadioSetting("beacon_time", "CW beacon Tx interval (secs)",
+ RadioSettingValueInteger(0, 255,
+ _settings.beacon_time))
+ cw.append(rs)
+
+ tmp = self._chars2str(_beacon.t1, 40)
+ rs=RadioSetting("t1", "CW Beacon Line 1",
+ RadioSettingValueString(0, 40, tmp))
+ rs.set_apply_callback(self._my_str2ary, _beacon, "t1", 40)
+ cw.append(rs)
+
+ tmp = self._chars2str(_beacon.t2, 40)
+ rs=RadioSetting("t2", "CW Beacon Line 2",
+ RadioSettingValueString(0, 40, tmp))
+ rs.set_apply_callback(self._my_str2ary, _beacon, "t2", 40)
+ cw.append(rs)
+
+ tmp = self._chars2str(_beacon.t3, 40)
+ rs=RadioSetting("t3", "CW Beacon Line 3",
+ RadioSettingValueString(0, 40, tmp))
+ rs.set_apply_callback(self._my_str2ary, _beacon, "t3", 40)
+ cw.append(rs) # END _do_cw_settings
+
+
+ def _do_panel_settings(self, pnlset): # - - - Panel settings
+ _settings = self._memobj.settings
+
+ bx = not _settings.amfmdial # Convert from Enable=0
+ rs = RadioSetting("amfmdial", "AM&FM Dial",
+ RadioSettingValueBoolean(bx))
+ rs.set_apply_callback(self._invert_me, _settings, "amfmdial")
+ pnlset.append(rs)
+
+ options = ["440Hz", "880Hz", "1760Hz"]
+ rs = RadioSetting("beepton", "Beep frequency",
+ RadioSettingValueList(options,
+ options[_settings.beepton]))
+ pnlset.append(rs)
+
+ rs = RadioSetting("beepvol_sgn", "Beep volume Linked",
+ RadioSettingValueBoolean(_settings.beepvol_sgn))
+ rs.set_doc("If set; volume is relative to AF Gain knob.")
+ pnlset.append(rs)
+
+ rs = RadioSetting("beepvol_lnk", "Linked beep volume",
+ RadioSettingValueInteger(-50, 50,
+ _settings.beepvol_lnk))
+ rs.set_doc("Relative to AF-Gain setting.")
+ pnlset.append(rs)
+
+ rs = RadioSetting("beepvol_fix", "Fixed beep volume",
+ RadioSettingValueInteger(0, 100,
+ _settings.beepvol_fix))
+ rs.set_doc("When Linked setting is unchecked.")
+ pnlset.append(rs)
+
+ rs = RadioSetting("cont", "LCD Contrast",
+ RadioSettingValueInteger(1, 24, _settings.cont ))
+ rs.set_doc("This setting does not appear to do anything...")
+ pnlset.append(rs)
+
+ rs = RadioSetting("dimmer", "LCD Dimmer",
+ RadioSettingValueInteger(1, 8, _settings.dimmer ))
+ pnlset.append(rs)
+
+ options = ["RF-Gain", "Squelch"]
+ rs = RadioSetting("sql_rfg", "Squelch/RF-Gain",
+ RadioSettingValueList(options,
+ options[_settings.sql_rfg]))
+ pnlset.append(rs)
+
+ options = ["Frequencies", "Panel", "All"]
+ rs = RadioSetting("lockmod", "Lock Mode",
+ RadioSettingValueList(options,
+ options[_settings.lockmod]))
+ pnlset.append(rs)
+
+ options = ["Dial", "SEL"]
+ rs = RadioSetting("clar_btn", "CLAR button control",
+ RadioSettingValueList(options,
+ options[_settings.clar_btn]))
+ pnlset.append(rs)
+
+ if _settings.dialstp_mode == 0: # AM/FM
+ options = ["SSB/CW:1Hz", "SSB/CW:10Hz", "SSB/CW:20Hz"]
+ else:
+ options = ["AM/FM:100Hz", "AM/FM:200Hz"]
+ rs = RadioSetting("dialstp", "Dial tuning step",
+ RadioSettingValueList(options,
+ options[_settings.dialstp]))
+ pnlset.append(rs)
+
+ options = ["0.5secs", "1.0secs", "1.5secs", "2.0secs"]
+ rs = RadioSetting("keyhold", "Buttons hold-to-activate time",
+ RadioSettingValueList(options,
+ options[_settings.keyhold]))
+ pnlset.append(rs)
+
+ rs = RadioSetting("m_tune", "Memory tune",
+ RadioSettingValueBoolean(_settings.m_tune))
+ pnlset.append(rs)
+
+ rs = RadioSetting("peakhold", "S-Meter display hold (1sec)",
+ RadioSettingValueBoolean(_settings.peakhold))
+ pnlset.append(rs)
+
+ options = ["CW Sidetone", "CW Speed", "100KHz step", "1MHz Step",
+ "Mic Gain", "RF Power"]
+ rs = RadioSetting("seldial", "SEL dial 2nd function (push)",
+ RadioSettingValueList(options,
+ options[_settings.seldial]))
+ pnlset.append(rs)
+ # End _do_panel_settings
+
+ def _do_panel_buttons(self, pnlcfg): #- - - Current Panel Config
+ _settings = self._memobj.settings
+
+ rs = RadioSetting("pnl_cs", "C.S. Function",
+ RadioSettingValueList(self.FUNC_LIST,
+ self.FUNC_LIST[_settings.pnl_cs]))
+ pnlcfg.append(rs)
+
+ rs = RadioSetting("nb", "Noise blanker",
+ RadioSettingValueBoolean(_settings.nb))
+ pnlcfg.append(rs)
+
+ options = ["Auto", "Fast", "Slow", "Auto/Fast", "Auto/Slow", "?5?"]
+ rs = RadioSetting("agc", "AGC",
+ RadioSettingValueList(options,
+ options[_settings.agc]))
+ pnlcfg.append(rs)
+
+ rs = RadioSetting("keyer", "Keyer",
+ RadioSettingValueBoolean(_settings.keyer))
+ pnlcfg.append(rs)
+
+ rs = RadioSetting("fast", "Fast step",
+ RadioSettingValueBoolean(_settings.fast))
+ pnlcfg.append(rs)
+
+ rs = RadioSetting("lock", "Lock (per Lock Mode)",
+ RadioSettingValueBoolean(_settings.lock))
+ pnlcfg.append(rs)
+
+ options = ["PO", "ALC", "SWR"]
+ rs = RadioSetting("mtr_mode", "S-Meter mode",
+ RadioSettingValueList(options,
+ options[_settings.mtr_mode]))
+ pnlcfg.append(rs)
+ # End _do_panel_Buttons
+
+ def _do_vox_settings(self, voxdat): # - - VOX and DATA Settings
+ _settings = self._memobj.settings
+
+ rs = RadioSetting("vox_dly", "VOX delay (x 100 ms)",
+ RadioSettingValueInteger(1, 30, _settings.vox_dly))
+ voxdat.append(rs)
+
+ rs = RadioSetting("vox_gain", "VOX Gain",
+ RadioSettingValueInteger(0, 100,
+ _settings.vox_gain))
+ voxdat.append(rs)
+
+ rs = RadioSetting("dig_vox", "Digital VOX Gain",
+ RadioSettingValueInteger(0, 100,
+ _settings.dig_vox))
+ voxdat.append(rs)
+
+ rs = RadioSetting("d_disp", "User-L/U freq offset (Hz)",
+ RadioSettingValueInteger(-3000, 30000,
+ _settings.d_disp, 10))
+ voxdat.append(rs)
+
+ options = ["170Hz", "200Hz", "425Hz", "850Hz"]
+ rs = RadioSetting("rty_sft", "RTTY FSK Freq Shift",
+ RadioSettingValueList(options,
+ options[_settings.rty_sft]))
+ voxdat.append(rs)
+
+ options = ["1275Hz", "2125Hz"]
+ rs = RadioSetting("rty_ton", "RTTY FSK Mark tone",
+ RadioSettingValueList(options,
+ options[_settings.rty_ton]))
+ voxdat.append(rs)
+
+ options = ["Normal", "Reverse"]
+ rs = RadioSetting("rtyrpol", "RTTY Mark/Space RX polarity",
+ RadioSettingValueList(options,
+ options[_settings.rtyrpol]))
+ voxdat.append(rs)
+
+ rs = RadioSetting("rtytpol", "RTTY Mark/Space TX polarity",
+ RadioSettingValueList(options,
+ options[_settings.rtytpol]))
+ voxdat.append(rs)
+ # End _do_vox_settings
+
+ def _do_mic_settings(self, mic): # - - MIC Settings
+ _settings = self._memobj.settings
+
+ rs = RadioSetting("mic_eq", "Mic Equalizer",
+ RadioSettingValueInteger(0, 9, _settings.mic_eq))
+ mic.append(rs)
+
+ options = ["Low", "Normal", "High"]
+ rs = RadioSetting("micgain", "Mic Gain",
+ RadioSettingValueList(options,
+ options[_settings.micgain]))
+ mic.append(rs)
+
+ rs = RadioSetting("micscan", "Mic scan enabled",
+ RadioSettingValueBoolean(_settings.micscan))
+ rs.set_doc("Enables channel scanning via mic up/down buttons.")
+ mic.append(rs)
+
+ rs = RadioSetting("pm_dwn", "Mic Down button function",
+ RadioSettingValueList(self.FUNC_LIST,
+ self.FUNC_LIST[_settings.pm_dwn]))
+ mic.append(rs)
+
+ rs = RadioSetting("pm_fst", "Mic Fast button function",
+ RadioSettingValueList(self.FUNC_LIST,
+ self.FUNC_LIST[_settings.pm_fst]))
+ mic.append(rs)
+
+ rs = RadioSetting("pm_up", "Mic Up button function",
+ RadioSettingValueList(self.FUNC_LIST,
+ self.FUNC_LIST[_settings.pm_up]))
+ mic.append(rs)
+ # End _do_mic_settings
+
+ def _do_mymodes_settings(self, mymodes): # - - MYMODES
+ _settings = self._memobj.settings # Inverted Logic requires callback
+
+ bx = not _settings.mym_lsb
+ rs = RadioSetting("mym_lsb", "LSB", RadioSettingValueBoolean(bx))
+ rs.set_apply_callback(self._invert_me, _settings, "mym_lsb")
+ mymodes.append(rs)
+
+ bx = not _settings.mym_usb
+ rs = RadioSetting("mym_usb", "USB", RadioSettingValueBoolean(bx))
+ rs.set_apply_callback(self._invert_me, _settings, "mym_usb")
+ mymodes.append(rs)
+
+ bx = not _settings.mym_cw
+ rs = RadioSetting("mym_cw", "CW", RadioSettingValueBoolean(bx))
+ rs.set_apply_callback(self._invert_me, _settings, "mym_cw")
+ mymodes.append(rs)
+
+ bx = not _settings.mym_am
+ rs = RadioSetting("mym_am", "AM", RadioSettingValueBoolean(bx))
+ rs.set_apply_callback(self._invert_me, _settings, "mym_am")
+ mymodes.append(rs)
+
+ bx = not _settings.mym_fm
+ rs = RadioSetting("mym_fm", "FM", RadioSettingValueBoolean(bx))
+ rs.set_apply_callback(self._invert_me, _settings, "mym_fm")
+ mymodes.append(rs)
+
+ bx = not _settings.mym_data
+ rs = RadioSetting("mym_data", "DATA", RadioSettingValueBoolean(bx))
+ rs.set_apply_callback(self._invert_me, _settings, "mym_data")
+ mymodes.append(rs)
+ # End _do_mymodes_settings
+
+ def _do_mybands_settings(self, mybands): # - - MYBANDS Settings
+ _settings = self._memobj.settings # Inverted Logic requires callback
+
+ bx = not _settings.myb_1_8
+ rs = RadioSetting("myb_1_8", "1.8 MHz", RadioSettingValueBoolean(bx))
+ rs.set_apply_callback(self._invert_me, _settings, "myb_1_8")
+ mybands.append(rs)
+
+ bx = not _settings.myb_3_5
+ rs = RadioSetting("myb_3_5", "3.5 MHz", RadioSettingValueBoolean(bx))
+ rs.set_apply_callback(self._invert_me, _settings, "myb_3_5")
+ mybands.append(rs)
+
+ bx = not _settings.myb_7
+ rs = RadioSetting("myb_7", "7 MHz", RadioSettingValueBoolean(bx))
+ rs.set_apply_callback(self._invert_me, _settings, "myb_7")
+ mybands.append(rs)
+
+ bx = not _settings.myb_10
+ rs = RadioSetting("myb_10", "10 MHz", RadioSettingValueBoolean(bx))
+ rs.set_apply_callback(self._invert_me, _settings, "myb_10")
+ mybands.append(rs)
+
+ bx = not _settings.myb_14
+ rs = RadioSetting("myb_14", "14 MHz", RadioSettingValueBoolean(bx))
+ rs.set_apply_callback(self._invert_me, _settings, "myb_14")
+ mybands.append(rs)
+
+ bx = not _settings.myb_18
+ rs = RadioSetting("myb_18", "18 MHz", RadioSettingValueBoolean(bx))
+ rs.set_apply_callback(self._invert_me, _settings, "myb_18")
+ mybands.append(rs)
+
+ bx = not _settings.myb_21
+ rs = RadioSetting("myb_21", "21 MHz", RadioSettingValueBoolean(bx))
+ rs.set_apply_callback(self._invert_me, _settings, "myb_21")
+ mybands.append(rs)
+
+ bx = not _settings.myb_24
+ rs = RadioSetting("myb_24", "24 MHz", RadioSettingValueBoolean(bx))
+ rs.set_apply_callback(self._invert_me, _settings, "myb_24")
+ mybands.append(rs)
+
+ bx = not _settings.myb_28
+ rs = RadioSetting("myb_28", "28 MHz", RadioSettingValueBoolean(bx))
+ rs.set_apply_callback(self._invert_me, _settings, "myb_28")
+ mybands.append(rs)
+
+ bx = not _settings.myb_50
+ rs = RadioSetting("myb_50", "50 MHz", RadioSettingValueBoolean(bx))
+ rs.set_apply_callback(self._invert_me, _settings, "myb_50")
+ mybands.append(rs)
+ # End _do_mybands_settings
+
+ def set_settings(self, settings):
+ _settings = self._memobj.settings
+ _mem = self._memobj
+ for element in settings:
+ if not isinstance(element, RadioSetting):
+ self.set_settings(element)
+ continue
+ else:
+ try:
+ name = element.get_name()
+ if "." in name:
+ bits = name.split(".")
+ obj = self._memobj
+ for bit in bits[: -1]:
+ if "/" in bit:
+ bit, index = bit.split("/", 1)
+ index = int(index)
+ obj = getattr(obj, bit)[index]
+ else:
+ obj = getattr(obj, bit)
+ setting = bits[-1]
+ else:
+ obj = _settings
+ setting = element.get_name()
+
+ if element.has_apply_callback():
+ LOG.debug("Using apply callback")
+ element.run_apply_callback()
+ elif element.value.get_mutable():
+ LOG.debug("Setting %s = %s" % (setting, element.value))
+ setattr(obj, setting, element.value)
+ except Exception, e:
+ LOG.debug(element.get_name())
+ raise
More information about the chirp_devel
mailing list