[chirp_devel] TYT TH-UV8000 Driver Submission
Jim Unroe
Thu Jun 6 06:45:59 PDT 2019
Rick,
Thisis your original submission as received here on my gmail account.
Scroll down below and you can see what I am talking about.
Jim
On Tue, Jun 4, 2019 at 1:46 PM Rick DeWitt AA0RD via chirp_devel
<chirp_devel at intrepid.danplanet.com> wrote:
>
> New driver for the TYT TH-UV8000 D/ D/SE.
> Re-submitted because I had the wrong email address.
>
> # HG changeset patch
> # User Rick DeWitt <aa0rd at yahoo.com>
> # Date 1559226735 25200
> #?????????? Thu May 30 07:32:15 2019 -0700
> # Node ID 120e390016146e92f490619e4f7029ae60418d72
> # Parent?? 76c88493bd3f873d355d08e66c624c6acf201b4d
> [th-uv8000] New driver for TYT TH-UV8000 family, fixes issue #2837
>
> Submitting new driver in support of 11 issues 2837 ... 6183
>
> diff -r 76c88493bd3f -r 120e39001614 chirp/drivers/th_uv8000.py
> --- /dev/null?????? Thu Jan 01 00:00:00 1970 +0000
> +++ b/chirp/drivers/th_uv8000.py?????? Thu May 30 07:32:15 2019 -0700
> @@ -0,0 +1,1598 @@
> +# Copyright 2019: Rick DeWitt (RJD), <aa0rd at yahoo.com>
> +# Version 1.0 for TYT-UV8000D/E
> +# Thanks to Damon Schaefer (K9CQB)and the Loudoun County, VA ARES
> +#?????? club for the donated radio.
> +# And thanks to Ian Harris (W2OOT) for decoding the mamory map.
> +#
> +# 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 2 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/>.
> +
> +import time
> +import struct
> +import logging
> +import re
> +import math
> +from datetime import datetime
> +
> +LOG = logging.getLogger(__name__)
> +
> +from chirp import chirp_common, directory, memmap
> +from chirp import bitwise, errors, util
> +from chirp.settings import RadioSettingGroup, RadioSetting, \
> +?????? RadioSettingValueBoolean, RadioSettingValueList, \
> +?????? RadioSettingValueString, RadioSettingValueInteger, \
> +?????? RadioSettingValueFloat, RadioSettings,InvalidValueError
> +from textwrap import dedent
> +
> +MEM_FORMAT = """
> +struct chns {
> +?? ul32 rxfreq;
> +?? ul32 txfreq;
> +?? u8 rxtone[2];
> +?? u8 txtone[2];
> +?? u8?? wide:1???? // 0x0c
> +?????????? vox_on:1
> +?????????? chunk01:1
> +?????????? bcl:1?????? // inv bool
> +?????????? epilogue:1
> +?????????? power:1
> +?????????? chunk02:1
> +?????????? chunk03:1;
> +?? u8?? ani:1???????? // 0x0d inv
> +?????????? chunk08:1
> +?????????? ptt:2
> +?????????? chpad04:4;
> +?? u8?? chunk05;?? // 0x0e
> +?? u16 id_code; // 0x0f, 10
> +?? u8?? chunk06;
> +?? u8?? name[7];
> +?? ul32 chpad06; // Need 56 byte pad
> +?? ul16 chpad07;
> +?? u8?? chpad08;
> +};
> +
> +struct fm_chn {
> +?? ul16 rxfreq;
> +};
> +
> +struct frqx {
> +?? ul32 rxfreq;
> +?? ul24 ofst;
> +?? u8?? fqunk01:4?? // 0x07
> +?????????? funk10:2
> +?????????? duplx:2;
> +?? u8 rxtone[2]; // 0x08, 9
> +?? u8 txtone[2]; // 0x0a, b
> +?? u8?? wide:1?????? // 0x0c
> +?????????? vox_on:1
> +?????????? funk11:1
> +?????????? bcl:1???????? // inv bool
> +?????????? epilogue:1
> +?????????? power:1
> +?????????? fqunk02:2;
> +?? u8?? ani:1???????? // 0x0d inv bool
> +?????????? fqunk03:1
> +?????????? ptt:2
> +?????????? fqunk12:1
> +?????????? fqunk04:3;
> +?? u8?? fqunk07;?? // 0x0e
> +?? u16 id_code;?? // 0x0f, 0x10
> +?? u8?? name[7];?????? // dummy
> +?? u8 fqunk09[8];?? // empty bytes after 1st entry
> +};
> +
> +struct bitmap {
> +?? u8?? map[16];
> +};
> +
> +#seekto 0x0010;
> +struct chns chan_mem[128];
> +
> +#seekto 0x1010;
> +struct frqx frq[2];
> +
> +#seekto 0x1050;
> +struct fm_chn fm_stations[25];
> +
> +#seekto 0x1080;
> +struct {
> +?? u8?? fmunk01[14];
> +?? ul16 fmcur;
> +} fmfrqs;
> +
> +#seekto 0x1190;
> +struct bitmap chnmap;
> +
> +#seekto 0x11a0;
> +struct bitmap skpchns;
> +
> +#seekto 0x011b0;
> +struct {
> +?? u8?? fmset[4];
> +} fmmap;
> +
> +#seekto 0x011b4;
> +struct {
> +?? u8?? setunk01[4];
> +?? u8?? setunk02[3];
> +?? u8?? chs_name:1?????? // 0x11bb
> +?????????? txsel:1
> +?????????? dbw:1
> +?????????? setunk05:1
> +?????????? ponfmchs:2
> +?????????? ponchs:2;
> +?? u8?? voltx:2???????????? // 0x11bc
> +?????????? setunk04:1
> +?????????? keylok:1
> +?????????? setunk07:1
> +?????????? batsav:3;
> +?? u8?? setunk09:1?????? // 0x11bd
> +?????????? rxinhib:1
> +?????????? rgrbeep:1?????? // inv bool
> +?????????? lampon:2
> +?????????? voice:2
> +?????????? beepon:1;
> +?? u8?? setunk11:1?????? // 0x11be
> +?????????? manualset:1
> +?????????? xbandon:1???????? // inv
> +?????????? xbandenable:1
> +?????????? openmsg:2
> +?????????? ledclr:2;
> +?? u8?? tot:4???????????????? // 0x11bf
> +?????????? sql:4;
> +?? u8?? setunk27:1???? // 0x11c0
> +?????????? voxdelay:2
> +?????????? setunk28:1
> +?????????? voxgain:4;
> +?? u8?? fmstep:4?????????? // 0x11c1
> +?????????? freqstep:4;
> +?? u8?? scanspeed:4???? // 0x11c2
> +?????????? scanmode:4;
> +?? u8?? scantmo;?????????? // 0x11c3
> +?? u8?? prichan;?????????? // 0x11c4
> +?? u8?? setunk12:4?????? // 0x11c5
> +?????????? supersave:4;
> +?? u8?? setunk13;
> +?? u8?? fmsclo;???????????? // 0x11c7 ??? placeholder
> +?? u8?? radioname[7]; // hex char codes, not true ASCII
> +?? u8?? fmschi;???????????? // ??? placeholder
> +?? u8?? setunk14[3];?? // 0x11d0
> +?? u8 setunk17[2];???? // 0x011d3, 4
> +?? u8?? setunk18:4
> +?????????? dtmfspd:4;
> +?? u8?? dtmfdig1dly:4 // 0x11d6
> +?????????? dtmfdig1time:4;
> +?? u8?? stuntype:1
> +?????????? setunk19:1
> +?????????? dtmfspms:2
> +?????????? grpcode:4;
> +?? u8?? setunk20:1?????? // 0x11d8
> +?????????? txdecode:1
> +?????????? codeabcd:1
> +?????????? idedit:1
> +?????????? pttidon:2
> +?????????? setunk40:1,
> +?????????? dtmfside:1;
> +?? u8?? setunk50:4,
> +?????????? autoresettmo:4;
> +?? u8?? codespctim:4, // 0x11da
> +?????????? decodetmo:4;
> +?? u8?? pttecnt:4???????? // 0x11db
> +?????????? pttbcnt:4;
> +?? lbcd?? dtmfdecode[3];
> +?? u8?? setunk22;
> +?? u8?? stuncnt;?????????? // 0x11e0
> +?? u8?? stuncode[5];
> +?? u8?? setunk60;
> +?? u8?? setunk61;
> +?? u8?? pttbot[8];?????? // 0x11e8-f
> +?? u8?? ptteot[8];?????? // 0x11f0-7
> +?? u8?? setunk62;???????? // 0x11f8
> +?? u8?? setunk63;
> +?? u8?? setunk64;???????? // 0x11fa
> +?? u8?? setunk65;
> +?? u8?? setunk66;
> +?? u8?? manfrqyn;???????? // 0x11fd
> +?? u8?? setunk27:3
> +?????????? frqr3:1
> +?????????? setunk28:1
> +?????????? frqr2:1
> +?????????? setunk29:1
> +?????????? frqr1:1;
> +?? u8?? setunk25;
> +?? ul32 frqr1lo;?? // 0x1200
> +?? ul32 frqr1hi;
> +?? ul32 frqr2lo;
> +?? ul32 frqr2hi;
> +?? ul32 frqr3lo;?? // 0x1210
> +?? ul32 frqr3hi;
> +?? u8 setunk26[8];
> +} setstuf;
> +
> +#seekto 0x1260;
> +struct {
> +?? ul16 year;
> +?? u8?? month;
> +?? u8?? day;
> +?? u8?? hour;
> +?? u8?? min;
> +?? u8?? sec;
> +} moddate;
> +
> +#seekto 0x1300;
> +struct {
> +?? char?? mod_num[9];
> +} mod_id;
> +"""
> +
> +MEM_SIZE = 0x1300
> +BLOCK_SIZE = 0x10???? # can read 0x20, but must write 0x10
> +STIMEOUT = 2
> +BAUDRATE = 4800
> +# Channel power: 2 levels
> +POWER_LEVELS = [chirp_common.PowerLevel("Low", watts=5.00),
> +?????????????????????????????? chirp_common.PowerLevel("High", watts=10.00)]
> +
> +LIST_RECVMODE = ["QT/DQT", "QT/DQT + Signaling"]
> +LIST_COLOR = ["Off", "Orange", "Blue", "Purple"]
> +LIST_LEDSW = ["Auto", "On"]
> +LIST_TIMEOUT = ["Off"] + ["%s" % x for x in range(30, 390, 30)]
> +LIST_VFOMODE = ["Frequency Mode", "Channel Mode"]
> +# Tones are numeric, Defined in \chirp\chirp_common.py
> +TONES_CTCSS = sorted(chirp_common.TONES)
> +# Converted to strings
> +LIST_CTCSS = ["Off"] + [str(x) for x in TONES_CTCSS]
> +# Now append the DxxxN and DxxxI DTCS codes from chirp_common
> +for x in chirp_common.DTCS_CODES:
> +?????? LIST_CTCSS.append("D{:03d}N".format(x))
> +for x in chirp_common.DTCS_CODES:
> +?????? LIST_CTCSS.append("D{:03d}R".format(x))
> +LIST_BW = ["Narrow", "Wide"]
> +LIST_SHIFT = ["off", "+", "-"]
> +STEPS = [0.5, 2.5, 5.0, 6.25, 10.0, 12.5, 25.0, 37.5, 50.0, 100.0]
> +LIST_STEPS = [str(x) for x in STEPS]
> +LIST_VOXDLY = ["0.5", "1.0", "2.0", "3.0"]?????????? # LISTS must be strings
> +LIST_PTT = ["Both", "EoT", "BoT", "Off"]
> +
> +SETTING_LISTS = {
> +"tot": LIST_TIMEOUT,
> +"wtled": LIST_COLOR,
> +"rxled": LIST_COLOR,
> +"txled": LIST_COLOR,
> +"ledsw": LIST_LEDSW,
> +"frq_chn_mode": LIST_VFOMODE,
> +"rx_tone": LIST_CTCSS,
> +"tx_tone": LIST_CTCSS,
> +"rx_mode": LIST_RECVMODE,
> +"fm_bw": LIST_BW,
> +"shift": LIST_SHIFT,
> +"step": LIST_STEPS,
> +"vox_dly": LIST_VOXDLY,
> +"ptt": LIST_PTT
> +}
> +
> +def _clean_buffer(radio):
> +?????? radio.pipe.timeout = 0.005
> +?????? junk = radio.pipe.read(256)
> +?????? radio.pipe.timeout = STIMEOUT
> +?????? if junk:
> +?????????????? Log.debug("Got %i bytes of junk before starting" % len(junk))
> +
> +
> +def _rawrecv(radio, amount):
> +?????? """Raw read from the radio device"""
> +?????? data = ""
> +?????? try:
> +?????????????? data = radio.pipe.read(amount)
> +?????? except:
> +?????????????? _exit_program_mode(radio)
> +?????????????? msg = "Generic error reading data from radio; check your cable."
> +?????????????? raise errors.RadioError(msg)
> +
> +?????? if len(data) != amount:
> +?????????????? _exit_program_mode(radio)
> +?????????????? msg = "Error reading from radio: not the amount of data we want."
> +?????????????? raise errors.RadioError(msg)
> +
> +?????? return data
> +
> +
> +def _rawsend(radio, data):
> +?????? """Raw send to the radio device"""
> +?????? try:
> +?????????????? radio.pipe.write(data)
> +?????? except:
> +?????????????? raise errors.RadioError("Error sending data to radio")
> +
> +
> +def _make_frame(cmd, addr, length, data=""):
> +?????? """Pack the info in the headder format"""
> +?????? frame = struct.pack(">shB", cmd, addr, length)
> +?????? # Add the data if set
> +?????? if len(data) != 0:
> +?????????????? frame += data
> +?????? # Return the data
> +?????? return frame
> +
> +
> +def _recv(radio, addr, length):
> +?????? """Get data from the radio """
> +
> +?????? data = _rawrecv(radio, length)
> +
> +?????? # DEBUG
> +?????? LOG.info("Response:")
> +?????? LOG.debug(util.hexprint(data))
> +
> +?????? return data
> +
> +
> +def _do_ident(radio):
> +?????? """Put the radio in PROGRAM mode & identify it"""
> +?????? radio.pipe.baudrate = BAUDRATE
> +?????? radio.pipe.parity = "N"
> +?????? radio.pipe.timeout = STIMEOUT
> +
> +?????? # Flush input buffer
> +?????? _clean_buffer(radio)
> +
> +?????? magic = "PROGRAMa"
> +?????? _rawsend(radio, magic)
> +?????? ack = _rawrecv(radio, 1)
> +?????? # LOG.warning("PROGa Ack:" + util.hexprint(ack))
> +?????? if ack != "\x06":
> +?????????????? _exit_program_mode(radio)
> +?????????????? if ack:
> +?????????????????????? LOG.debug(repr(ack))
> +?????????????? raise errors.RadioError("Radio did not respond")
> +?????? magic = "PROGRAMb"
> +?????? _rawsend(radio, magic)
> +?????? ack = _rawrecv(radio, 1)
> +?????? if ack != "\x06":
> +?????????????? _exit_program_mode(radio)
> +?????????????? if ack:
> +?????????????????????? LOG.debug(repr(ack))
> +?????????????? raise errors.RadioError("Radio did not respond to B")
> +?????? magic = chr(0x02)
> +?????? _rawsend(radio, magic)
> +?????? ack = _rawrecv(radio, 1)?????? # s/b: 0x50
> +?????? magic = _rawrecv(radio, 7)?? # s/b TC88...
> +?????? magic = "MTC88CUMHS3E7BN-"
> +?????? _rawsend(radio, magic)
> +?????? ack = _rawrecv(radio, 1)?????? # s/b 0x80
> +?????? magic = chr(0x06)
> +?????? _rawsend(radio, magic)
> +?????? ack = _rawrecv(radio, 1)
> +
> +?????? return True
> +
> +
> +def _exit_program_mode(radio):
> +?????? endframe = "E"
> +?????? _rawsend(radio, endframe)
> +
> +
> +def _download(radio):
> +?????? """Get the memory map"""
> +
> +?????? # Put radio in program mode and identify it
> +?????? _do_ident(radio)
> +
> +?????? # UI progress
> +?????? status = chirp_common.Status()
> +?????? status.cur = 0
> +?????? status.max = MEM_SIZE / BLOCK_SIZE
> +?????? status.msg = "Cloning from radio..."
> +?????? radio.status_fn(status)
> +
> +?????? data = ""
> +?????? for addr in range(0, MEM_SIZE, BLOCK_SIZE):
> +?????????????? frame = _make_frame("R", addr, BLOCK_SIZE)
> +?????????????? # DEBUG
> +?????????????? LOG.info("Request sent:")
> +?????????????? LOG.debug("Frame=" + util.hexprint(frame))
> +
> +?????????????? # Sending the read request
> +?????????????? _rawsend(radio, frame)
> +?????????????? dx = _rawrecv(radio, 4)
> +
> +?????????????? # Now we read data
> +?????????????? d = _recv(radio, addr, BLOCK_SIZE)
> +?????????????? # LOG.warning("Data= " + util.hexprint(d))
> +
> +?????????????? # Aggregate the data
> +?????????????? data += d
> +
> +?????????????? # UI Update
> +?????????????? status.cur = addr / BLOCK_SIZE
> +?????????????? status.msg = "Cloning from radio..."
> +?????????????? radio.status_fn(status)
> +
> +?????? _exit_program_mode(radio)
> +?????? # Append the model number to the downloaded memory
> +?????? data += radio.MODEL.ljust(9)
> +
> +?????? return data
> +
> +def _upload(radio):
> +?????? """Upload procedure"""
> +?????? # Put radio in program mode and identify it
> +?????? _do_ident(radio)
> +
> +?????? # Generate upload time stamp; not used by Chirp
> +?????? dnow = datetime.now()
> +?????? _mem = radio._memobj.moddate
> +?????? _mem.year = dnow.year
> +?????? _mem.month = dnow.month
> +?????? _mem.day = dnow.day
> +?????? _mem.hour = dnow.hour
> +?????? _mem.min = dnow.minute
> +?????? _mem.sec = dnow.second
> +
> +?????? # UI progress
> +?????? status = chirp_common.Status()
> +?????? status.cur = 0
> +?????? status.max = MEM_SIZE / BLOCK_SIZE
> +?????? status.msg = "Cloning to radio..."
> +?????? radio.status_fn(status)
> +
> +?????? # The fun starts here
> +?????? for addr in range(0, MEM_SIZE, BLOCK_SIZE):
> +?????????????? # Sending the data
> +?????????????? data = radio.get_mmap()[addr:addr + BLOCK_SIZE]
> +
> +?????????????? frame = _make_frame("W", addr, BLOCK_SIZE, data)
> +?????????????? # LOG.warning("Frame:%s:" % util.hexprint(frame))
> +?????????????? _rawsend(radio, frame)
> +
> +?????????????? # Receiving the response
> +?????????????? ack = _rawrecv(radio, 1)
> +?????????????? if ack != "\x06":
> +?????????????????????? _exit_program_mode(radio)
> +?????????????????????? msg = "Bad ack writing block 0x%04x" % addr
> +?????????????????????? raise errors.RadioError(msg)
> +
> +?????????????? # UI Update
> +?????????????? status.cur = addr / BLOCK_SIZE
> +?????????????? status.msg = "Cloning to radio..."
> +?????????????? radio.status_fn(status)
> +
> +?????? _exit_program_mode(radio)
> +
> +def force_odd(fmfrq):
> +?????? """Force FM Broadcast Frequency to have odd KHz """
> +?????? oddfrq = int(fmfrq / 100000)?????? # remove 10Khz and lower
> +?????? if (oddfrq % 2) == 0:?????? # increment to odd
> +?????????????? oddfrq += 1
> +?????? return (oddfrq * 100000)
> +
> +def set_tone(_mem, txrx, ctdt, tval, pol):
> +?????? """Set rxtone[] or txtone[] word values as decimal bytes"""
> +?????? # txrx: Boolean T= set Rx tones, F= set Tx tones
> +?????? # ctdt: Boolean T = CTCSS, F= DTCS
> +?????? # tval = integer tone freq (*10) or DTCS code
> +?????? # pol = string for DTCS polarity "R" or "N"
> +?????? xv = int(str(tval), 16)
> +?????? if txrx:?????????????? # True = set rxtones
> +?????????????? _mem.rxtone[0] = xv & 0xFF?? # Low byte
> +?????????????? _mem.rxtone[1] = (xv >> 8)???? # Hi byte
> +?????????????? if not ctdt:?????? # dtcs,
> +?????????????????????? if pol == "R":
> +?????????????????????????????? _mem.rxtone[1] = _mem.rxtone[1] | 0xC0
> +?????????????????????? else:
> +?????????????????????????????? _mem.rxtone[1] = _mem.rxtone[1] | 0x80
> +?????? else:???????????????????? # txtones
> +?????????????? _mem.txtone[0] = xv & 0xFF?? # Low byte
> +?????????????? _mem.txtone[1] = (xv >> 8)
> +?????????????? if not ctdt:?????? # dtcs
> +?????????????????????? if pol == "R":
> +?????????????????????????????? _mem.txtone[1] = _mem.txtone[1] | 0xC0
> +?????????????????????? else:
> +?????????????????????????????? _mem.txtone[1] = _mem.txtone[1] | 0x80
> +
> +?????? return 0
> +
> +def model_match(cls, data):
> +?????? """Match the opened/downloaded image to the correct version"""
> +?????? if len(data) == 0x1307:
> +?????????????? rid = data[0x1300:0x1309]
> +?????????????? return rid.startswith(cls.MODEL)
> +?????? else:
> +?????????????? return False
> +
> +def _do_map(chn, sclr, mary):
> +?????? """Set or Clear the chn (1-128) bit in mary[] word array map"""
> +?????? # chn is 1-based channel, sclr:1 = set, 0= = clear, 2= return state
> +?????? # mary[] is u8 array, but the map is by nibbles
> +?????? ndx = int(math.floor((chn - 1) / 8))
> +?????? bv = (chn -1) % 8
> +?????? msk = 1 << bv
> +?????? mapbit = sclr
> +?????? if sclr == 1:?????? # Set the bit
> +?????????????? mary[ndx] = mary[ndx] | msk
> +?????? elif sclr == 0:?? # clear
> +?????????????? mary[ndx] = mary[ndx] & (~ msk)???????? # ~ is complement
> +?????? else:???????????? # return current bit state
> +?????????????? mapbit = 0
> +?????????????? if (mary[ndx] & msk) > 0: mapbit = 1
> +?????? # LOG.warning("-?? Do_Map chn %d, sclr= %d, ndx= %d" % (chn, sclr, ndx))
> +?????? # LOG.warning("-?? bv= %d, msk = %02x, mapbit= %d" % (bv, msk, mapbit))
> +?????? # LOG.warning("-?? mary[%d] = %02x" % (ndx, mary[ndx]))
> +?????? return mapbit
> +
> + at directory.register
> +class tyt_uv8000d(chirp_common.CloneModeRadio):
> +?????? """TYT UV8000D Radio"""
> +?????? VENDOR = "TYT"
> +?????? MODEL = "TH-UV8000"
> +?????? MODES = ["NFM", "FM"]
> +?????? TONES = chirp_common.TONES
> +?????? DTCS_CODES = sorted(chirp_common.DTCS_CODES + [645])
> +?????? NAME_LENGTH = 7
> +?????? DTMF_CHARS = list("0123456789ABCD*#")
> +?????? # NOTE: SE Model supports 220-260 MHz
> +?????? # The following bands are the the range the radio is capable of,
> +?????? #???? not the legal FCC amateur bands
> +?????? VALID_BANDS = [(87500000, 107900000), (136000000, 174000000),
> +???????????????????????????????????? (220000000, 260000000), (400000000, 520000000)]
> +
> +?????? # Valid chars on the LCD
> +?????? VALID_CHARS = chirp_common.CHARSET_ALPHANUMERIC + \
> +???????????????????? "`!\"#$%&'()*+,-./:;<=>?@[]^_"
> +
> +?????? # Special Channels Declaration
> +?????? # WARNING Indecis are hard wired in get/set_memory code !!!
> +?????? # Channels print in + increasing index order (most negative first)
> +?????? SPECIAL_MEMORIES = {
> +???????????? "FM 25": -3,
> +???????????? "FM 24": -4,
> +???????????? "FM 23": -5,
> +???????????? "FM 22": -6,
> +???????????? "FM 21": -7,
> +???????????? "FM 20": -8,
> +???????????? "FM 19": -9,
> +???????????? "FM 18": -10,
> +???????????? "FM 17": -11,
> +???????????? "FM 16": -12,
> +???????????? "FM 15": -13,
> +???????????? "FM 14": -14,
> +???????????? "FM 13": -15,
> +???????????? "FM 12": -16,
> +???????????? "FM 11": -17,
> +???????????? "FM 10": -18,
> +???????????? "FM 09": -19,
> +???????????? "FM 08": -20,
> +???????????? "FM 07": -21,
> +???????????? "FM 06": -22,
> +???????????? "FM 05": -23,
> +???????????? "FM 04": -24,
> +???????????? "FM 03": -25,
> +???????????? "FM 02": -26,
> +???????????? "FM 01": -27
> +?????? }
> +?????? FIRST_FM_INDEX = -3
> +?????? LAST_FM_INDEX = -27
> +
> +?????? SPECIAL_FREQ = {
> +???????????? "UpVFO": -2,
> +???????????? "LoVFO": -1
> +?????? }
> +?????? FIRST_FREQ_INDEX = -1
> +?????? LAST_FREQ_INDEX = -2
> +?????? SPECIAL_MEMORIES.update(SPECIAL_FREQ)
> +
> +?????? SPECIAL_MEMORIES_REV = dict(zip(SPECIAL_MEMORIES.values(),
> +?????????????????????????????????????????????????????????????????????? SPECIAL_MEMORIES.keys()))
> +
> +?????? @classmethod
> +?????? def get_prompts(cls):
> +?????????????? rp = chirp_common.RadioPrompts()
> +?????????????? rp.info = \
> +?????????????????????? ('NOTE 1: Some of these radios come shipped with the
> frequency '
> +???????????????????????? 'ranges locked to comply with FCC band limitations.\n'
> +???????????????????????? 'This driver allows the user to program frequencies outside '
> +???????????????????????? 'the legal amateur bands, so that they can receive on
> marine, '
> +???????????????????????? 'aviation, FRS/GMRS and NOAA weather bands.\n'
> +???????????????????????? 'If these frequencies are locked out on your radio, '
> +???????????????????????? 'you will receive an error beep when attempting to operate.\n'
> +???????????????????????? 'It is the users responsibility to only transmit on '
> +???????????????????????? 'authorized freqencies. \n\n'
> +???????????????????????? 'NOTE 2: Click on the "Special Channels" tab of the layout '
> +???????????????????????? 'screen to see/set the upper and lower frequency-mode
> values, '
> +???????????????????????? 'as well as the 25 FM broadcast radio station channels.\n\n'
> +???????????????????????? 'NOTE 3: The PTT ID codes are 1-16 characters of DTMF (0-9, '
> +???????????????????????? 'A-D,*,#). The per-channel ANI Id Codes are not
> implemented at '
> +???????????????????????? 'this time. However they may be set manually by using the '
> +???????????????????????? 'Browser developer tool. Contact Rick at AA0RD at Yahoo.com.\n\n'
> +???????????????????????? 'NOTE 4: To access the stored FM broadcast stations:
> activate '
> +???????????????????????? 'FM mode (F, MONI), then # and up/down.'
> +?????????????????????? )
> +
> +?????????????? rp.pre_download = _(dedent("""\
> +?????????????????????? Follow these instructions to download your config:
> +
> +?????????????????????? 1 - Turn off your radio
> +?????????????????????? 2 - Connect your interface cable
> +?????????????????????? 3 - Turn on your radio, volume @ 50%
> +?????????????????????? 4 - Radio > Download from radio
> +?????????????????????? """))
> +?????????????? rp.pre_upload = _(dedent("""\
> +?????????????????????? Follow this instructions to upload your config:
> +
> +?????????????????????? 1 - Turn off your radio
> +?????????????????????? 2 - Connect your interface cable
> +?????????????????????? 3 - Turn on your radio, volume @ 50%
> +?????????????????????? 4 - Radio > Upload to radio
> +?????????????????????? """))
> +?????????????? return rp
> +
> +?????? def get_features(self):
> +?????????????? rf = chirp_common.RadioFeatures()
> +?????????????? # .has. attributes are boolean, .valid. are lists
> +?????????????? rf.has_settings = True
> +?????????????? rf.has_bank = False
> +?????????????? rf.has_comment = False
> +?????????????? rf.has_tuning_step = False?? # Not as chan feature
> +?????????????? rf.can_odd_split = False
> +?????????????? rf.has_name = True
> +?????????????? rf.has_offset = True
> +?????????????? rf.has_mode = True
> +?????????????? rf.has_dtcs = True
> +?????????????? rf.has_rx_dtcs = True
> +?????????????? rf.has_dtcs_polarity = True
> +?????????????? rf.has_ctone = True
> +?????????????? rf.has_cross = True
> +?????????????? rf.has_sub_devices = False
> +?????????????? rf.valid_name_length = self.NAME_LENGTH
> +?????????????? rf.valid_modes = self.MODES
> +?????????????? rf.valid_characters = self.VALID_CHARS
> +?????????????? rf.valid_duplexes = ["-", "+", "off", ""]
> +?????????????? rf.valid_tmodes = ['', 'Tone', 'TSQL', 'DTCS', 'Cross']
> +?????????????? rf.valid_cross_modes = [
> +?????????????????????? "Tone->Tone",
> +?????????????????????? "DTCS->",
> +?????????????????????? "->DTCS",
> +?????????????????????? "Tone->DTCS",
> +?????????????????????? "DTCS->Tone",
> +?????????????????????? "->Tone",
> +?????????????????????? "DTCS->DTCS"]
> +?????????????? rf.valid_skips = []
> +?????????????? rf.valid_power_levels = POWER_LEVELS
> +?????????????? rf.valid_dtcs_codes = self.DTCS_CODES
> +?????????????? rf.valid_bands = self.VALID_BANDS
> +?????????????? rf.memory_bounds = (1, 128)
> +?????????????? rf.valid_skips = ["", "S"]
> +?????????????? rf.valid_special_chans = sorted(self.SPECIAL_MEMORIES.keys())
> +?????????????? return rf
> +
> +?????? def sync_in(self):
> +?????????????? """Download from radio"""
> +?????????????? try:
> +?????????????????????? data = _download(self)
> +?????????????? except errors.RadioError:
> +?????????????????????? # Pass through any real errors we raise
> +?????????????????????? raise
> +?????????????? except:
> +?????????????????????? # If anything unexpected happens, make sure we raise
> +?????????????????????? # a RadioError and log the problem
> +?????????????????????? LOG.exception('Unexpected error during download')
> +?????????????????????? raise errors.RadioError('Unexpected error communicating '
> +?????????????????????????????????????????????????????????????????????? 'with the radio')
> +?????????????? self._mmap = memmap.MemoryMap(data)
> +?????????????? self.process_mmap()
> +
> +?????? def sync_out(self):
> +?????????????? """Upload to radio"""
> +
> +?????????????? try:
> +?????????????????????? _upload(self)
> +?????????????? except:
> +?????????????????????? # If anything unexpected happens, make sure we raise
> +?????????????????????? # a RadioError and log the problem
> +?????????????????????? LOG.exception('Unexpected error during upload')
> +?????????????????????? raise errors.RadioError('Unexpected error communicating '
> +?????????????????????????????????????????????????????????????????????? 'with the radio')
> +
> +?????? def process_mmap(self):
> +?????????????? """Process the mem map into the mem object"""
> +?????????????? self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
> +
> +?????? def get_raw_memory(self, number):
> +?????????????? return repr(self._memobj.memory[number - 1])
> +
> +?????? 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):
> +?????????????? """A value in a UI column for chan 'number' has been modified."""
> +?????????????? # update all raw channel memory values (_mem) from UI (mem)
> +?????????????? if memory.number < 0:
> +?????????????????????? return self._set_special(memory)
> +?????????????? else:
> +?????????????????????? return self._set_normal(memory)
> +
> +?????? def _get_fm_memory(self, mem, _mem):
> +?????????????? mem.name = "----"
> +?????????????? rx = self._memobj.fm_stations[mem.number + 2].rxfreq
> +?????????????? if rx == 0xFFFF:
> +?????????????????????? mem.empty = True
> +?????????????????????? return mem
> +?????????????? else:
> +?????????????????????? mem.freq = (float(int(rx)) / 40) * 1000000
> +?????????????????????? mem.empty = False
> +
> +?????????????? mem.offset = 0.0
> +?????????????? mem.power = 0
> +?????????????? mem.duplex = "off"?????????? # inhibits tx
> +?????????????? mem.mode = self.MODES[1]
> +?????????????? dtcs_pol = ["N", "N"]
> +?????????????? mem.ctone = 88.5
> +?????????????? mem.rtone = 88.5
> +?????????????? mem.tmode = ""
> +?????????????? mem.cross_mode = "Tone->Tone"
> +?????????????? mem.skip = ""
> +?????????????? mem.comment = ""
> +
> +?????????????? return mem
> +
> +?????? def _get_normal(self, number):
> +?????????????? # radio first channel is 1, mem map is base 0
> +?????????????? _mem = self._memobj.chan_mem[number - 1]
> +?????????????? mem = chirp_common.Memory()
> +?????????????? mem.number = number
> +
> +?????????????? return self._get_memory(mem, _mem)
> +
> +?????? def _get_memory(self, mem, _mem):
> +?????????????? """Convert raw channel memory data into UI columns"""
> +?????????????? mem.extra = RadioSettingGroup("extra", "Extra")
> +
> +?????????????? if _mem.get_raw()[0] == "\xff":
> +?????????????????????? mem.empty = True
> +?????????????????????? return mem
> +
> +?????????????? mem.empty = False
> +?????????????? # This function process both 'normal' and Freq up/down' entries
> +?????????????? mem.freq = int(_mem.rxfreq) * 10
> +?????????????? mem.power = POWER_LEVELS[_mem.power]
> +?????????????? mem.mode = self.MODES[_mem.wide]
> +?????????????? dtcs_pol = ["N", "N"]
> +
> +?????????????? if _mem.rxtone[0] == 0xFF:
> +?????????????????????? rxmode = ""
> +?????????????? elif _mem.rxtone[1] < 0x26:
> +?????????????????????? # CTCSS
> +?????????????????????? rxmode = "Tone"
> +?????????????????????? tonehi = int(str(_mem.rxtone[1])[2:])
> +?????????????????????? tonelo = int(str(_mem.rxtone[0])[2:])
> +?????????????????????? mem.ctone = int(tonehi * 100 + tonelo) / 10.0
> +?????????????? else:
> +?????????????????????? # Digital
> +?????????????????????? rxmode = "DTCS"
> +?????????????????????? tonehi = int(str(_mem.rxtone[1] & 0x3f))
> +?????????????????????? tonelo = int(str(_mem.rxtone[0])[2:])
> +?????????????????????? mem.rx_dtcs = int(tonehi * 100 + tonelo)
> +?????????????????????? if (_mem.rxtone[1] & 0x40) != 0:
> +?????????????????????????????? dtcs_pol[1] = "R"
> +
> +?????????????? if _mem.txtone[0] == 0xFF:
> +?????????????????????? txmode = ""
> +?????????????? elif _mem.txtone[1] < 0x26:
> +?????????????????????? # CTCSS
> +?????????????????????? txmode = "Tone"
> +?????????????????????? tonehi = int(str(_mem.txtone[1])[2:])
> +?????????????????????? tonelo = int(str(_mem.txtone[0])[2:])
> +?????????????????????? mem.rtone = int(tonehi * 100 + tonelo) / 10.0
> +?????????????? else:
> +?????????????????????? # Digital
> +?????????????????????? txmode = "DTCS"
> +?????????????????????? tonehi = int(str(_mem.txtone[1] & 0x3f))
> +?????????????????????? tonelo = int(str(_mem.txtone[0])[2:])
> +?????????????????????? mem.dtcs = int(tonehi * 100 + tonelo)
> +?????????????????????? if (_mem.txtone[1] & 0x40) != 0:
> +?????????????????????????????? dtcs_pol[0] = "R"
> +
> +?????????????? mem.tmode = ""
> +?????????????? if txmode == "Tone" and not rxmode:
> +?????????????????????? mem.tmode = "Tone"
> +?????????????? elif txmode == rxmode and txmode == "Tone" and mem.rtone ==
> mem.ctone:
> +?????????????????????? mem.tmode = "TSQL"
> +?????????????? elif txmode == rxmode and txmode == "DTCS" and mem.dtcs ==
> mem.rx_dtcs:
> +?????????????????????? mem.tmode = "DTCS"
> +?????????????? elif rxmode or txmode:
> +?????????????????????? mem.tmode = "Cross"
> +?????????????????????? mem.cross_mode = "%s->%s" % (txmode, rxmode)
> +
> +?????????????? mem.dtcs_polarity = "".join(dtcs_pol)
> +
> +?????????????? # Now test the mem.number to process special vs normal
> +?????????????? if mem.number >=0:?????????? # Normal
> +?????????????????????? mem.name = ""
> +?????????????????????? for i in range(self.NAME_LENGTH):???? # 0 - 6
> +?????????????????????????????? mem.name += chr(_mem.name[i] + 32)
> +?????????????????????? mem.name = mem.name.rstrip()?????? # remove trailing spaces
> +
> +?????????????????????? if _mem.txfreq == 0xFFFFFFFF:
> +?????????????????????????????? # TX freq not set
> +?????????????????????????????? mem.duplex = "off"
> +?????????????????????????????? mem.offset = 0
> +?????????????????????? elif int(_mem.rxfreq) == int(_mem.txfreq):
> +?????????????????????????????? mem.duplex = ""
> +?????????????????????????????? mem.offset = 0
> +?????????????????????? else:
> +?????????????????????????????? mem.duplex = int(_mem.rxfreq) > int(_mem.txfreq) and
> "-" or "+"
> +?????????????????????????????? mem.offset = abs(int(_mem.rxfreq) - int(_mem.txfreq)) * 10
> +
> +?????????????????????? if _do_map(mem.number, 2, self._memobj.skpchns.map) > 0:
> +?????????????????????????????? mem.skip = "S"
> +?????????????????????? else:
> +?????????????????????????????? mem.skip = ""
> +
> +?????????????? else:???????????? # specials VFO
> +?????????????????????? mem.name = "----"
> +?????????????????????? mem.duplex = LIST_SHIFT[_mem.duplx]
> +?????????????????????? mem.offset = int(_mem.ofst) * 10
> +?????????????????????? mem.skip = ""
> +?????????????? # End if specials
> +
> +?????????????? # Channel Extra settings: Only Boolean & List methods, no
> call-backs
> +?????????????? rx = RadioSettingValueBoolean(bool(not _mem.bcl))???? # Inverted bool
> +?????????????? # NOTE: first param of RadioSetting is the object attribute name
> +?????????????? rset = RadioSetting("bcl", "Busy Channel Lockout", rx)
> +?????????????? mem.extra.append(rset)
> +
> +?????????????? rx = RadioSettingValueBoolean(bool(not _mem.vox_on))
> +?????????????? rset = RadioSetting("vox_on", "Vox", rx)
> +?????????????? mem.extra.append(rset)
> +
> +?????????????? rx = RadioSettingValueBoolean(bool(not _mem.ani))
> +?????????????? rset = RadioSetting("ani", "Auto Number ID (ANI)", rx)
> +?????????????? mem.extra.append(rset)
> +
> +?????????????? # ID code can't be done in extra - no Integer method or call-back
> +
> +?????????????? rx = RadioSettingValueList(LIST_PTT, LIST_PTT[_mem.ptt])
> +?????????????? rset = RadioSetting("ptt", "Xmit PTT ID", rx)
> +?????????????? mem.extra.append(rset)
> +
> +?????????????? rx = RadioSettingValueBoolean(bool(_mem.epilogue))
> +?????????????? rset = RadioSetting("epilogue", "Epilogue/Tail", rx)
> +?????????????? mem.extra.append(rset)
> +
> +?????????????? return mem
> +
> +?????? def _get_special(self, number):
> +?????????????? mem = chirp_common.Memory()
> +?????????????? mem.number = self.SPECIAL_MEMORIES[number]
> +?????????????? mem.extd_number = number
> +?????????????? # Unused attributes are ignored in Set_memory
> +?????????????? if (mem.number == -1) or (mem.number == -2):
> +?????????????????????? # Print Upper[1] first, and Lower[0] next
> +?????????????????????? rx = 0
> +?????????????????????? if mem.number == -2:
> +?????????????????????????????? rx = 1
> +?????????????????????? _mem = self._memobj.frq[rx]
> +?????????????????????? # immutable = ["number", "extd_number", "name"]
> +?????????????????????? mem = self._get_memory(mem, _mem)
> +?????????????? elif mem.number in range(self.FIRST_FM_INDEX,
> +?????????????????????????????????????? self.LAST_FM_INDEX - 1, -1):
> +?????????????????????? _mem = self._memobj.fm_stations[-self.LAST_FM_INDEX +
> mem.number]
> +?????????????????????? # immutable = ["number", "extd_number", "name", "power",
> "ctone",
> +?????????????????????? #?????????????????????? "rtone", "skip", "duplex", "offset", "mode"]
> +?????????????????????? mem = self._get_fm_memory(mem, _mem)?????????????? # special fnctn
> +?????????????? else:
> +?????????????????????? raise Exception("Sorry, you can't edit that special"
> +???????????????????????????????????? " memory channel %i." % mem.number)
> +
> +?????????????? # mem.immutable = immutable
> +
> +?????????????? return mem
> +
> +?????? def _set_memory(self, mem, _mem):
> +?????????????? """Convert UI column data (mem) into MEM_FORMAT memory (_mem)."""
> +?????????????? # At this point mem points to either normal, fm or Freq chans
> +?????????????? # These first attributes are common to all types
> +?????????????? if mem.empty:
> +?????????????????????? if mem.number > 0:
> +?????????????????????????????? _mem.rxfreq = 0xffffffff
> +?????????????????????????????? # Set 'empty' and 'skip' bits
> +?????????????????????????????? _do_map(mem.number, 1, self._memobj.chnmap.map)
> +?????????????????????????????? _do_map(mem.number, 1, self._memobj.skpchns.map)
> +?????????????????????? elif mem.number == -2:?? #?? upper VFO Freq
> +?????????????????????????????? _mem.rxfreq = 14652000???? # VHF National Calling freq
> +?????????????????????? elif mem.number == -1:?? #?? lower VFO
> +?????????????????????????????? _mem.rxfreq = 44600000???? # UHF National Calling freq
> +?????????????????????? else:???????????? # FM stations, mem.number -3 to -27
> +?????????????????????????????? _mem.rxfreq = 0xffff
> +?????????????????????????????? _do_map(mem.number + 28, 1, self._memobj.fmmap.fmset)
> +?????????????????????? return
> +
> +?????????????? _mem.rxfreq = mem.freq / 10
> +
> +?????????????? if mem.number < -2:???????? # FM stations, only rxfreq
> +?????????????????????? _mem.rxfreq = (force_odd(mem.freq) * 40) / 1000000
> +?????????????????????? _do_map(mem.number + 28, 0, self._memobj.fmmap.fmset)
> +?????????????????????? return
> +
> +?????????????? if str(mem.power) == "Low":
> +?????????????????????? _mem.power = 0
> +?????????????? else:
> +?????????????????????? _mem.power = 1
> +
> +?????????????? _mem.wide = self.MODES.index(mem.mode)
> +
> +?????????????? rxmode = ""
> +?????????????? txmode = ""
> +
> +?????????????? if mem.tmode == "Tone":
> +?????????????????????? txmode = "Tone"
> +?????????????? elif mem.tmode == "TSQL":
> +?????????????????????? rxmode = "Tone"
> +?????????????????????? txmode = "TSQL"
> +?????????????? elif mem.tmode == "DTCS":
> +?????????????????????? rxmode = "DTCSSQL"
> +?????????????????????? txmode = "DTCS"
> +?????????????? elif mem.tmode == "Cross":
> +?????????????????????? txmode, rxmode = mem.cross_mode.split("->", 1)
> +
> +?????????????? sx = mem.dtcs_polarity[1]
> +?????????????? if rxmode == "":
> +?????????????????????? _mem.rxtone[0] = 0xFF
> +?????????????????????? _mem.rxtone[1] = 0xFF
> +?????????????? elif rxmode == "Tone":
> +?????????????????????? val = int(mem.ctone * 10)
> +?????????????????????? i = set_tone(_mem, True, True, val, sx)
> +?????????????? elif rxmode == "DTCSSQL":
> +?????????????????????? i = set_tone(_mem, True, False, mem.dtcs, sx)
> +?????????????? elif rxmode == "DTCS":
> +?????????????????????? i = set_tone(_mem, True, False, mem.rx_dtcs, sx)
> +
> +?????????????? sx = mem.dtcs_polarity[0]
> +?????????????? if txmode == "":
> +?????????????????????? _mem.txtone[0] = 0xFF
> +?????????????????????? _mem.txtone[1] = 0xFF
> +?????????????? elif txmode == "Tone":
> +?????????????????????? val = int(mem.rtone * 10)
> +?????????????????????? i = set_tone(_mem, False, True, val, sx)
> +?????????????? elif txmode == "TSQL":
> +?????????????????????? val = int(mem.ctone * 10)
> +?????????????????????? i = set_tone(_mem, False, True, val, sx)
> +?????????????? elif txmode == "DTCS":
> +?????????????????????? i = set_tone(_mem, False, False, mem.dtcs, sx)
> +
> +?????????????? if mem.number > 0:?????????? # Normal chans
> +?????????????????????? for i in range(self.NAME_LENGTH):
> +?????????????????????????????? pq = ord(mem.name.ljust(self.NAME_LENGTH)[i]) -32
> +?????????????????????????????? if pq < 0: pq = 0
> +?????????????????????????????? _mem.name[i] = pq
> +
> +?????????????????????? if mem.duplex == "off":
> +?????????????????????????????? _mem.txfreq = 0xFFFFFFFF
> +?????????????????????? elif mem.duplex == "+":
> +?????????????????????????????? _mem.txfreq = (mem.freq + mem.offset) / 10
> +?????????????????????? elif mem.duplex == "-":
> +?????????????????????????????? _mem.txfreq = (mem.freq - mem.offset) / 10
> +?????????????????????? else:
> +?????????????????????????????? _mem.txfreq = mem.freq / 10
> +
> +?????????????????????? # Set the channel map bit FALSE = Enabled
> +?????????????????????? _do_map(mem.number, 0, self._memobj.chnmap.map)
> +?????????????????????? # Skip
> +?????????????????????? if mem.skip == "S":
> +?????????????????????????????? _do_map(mem.number, 1, self._memobj.skpchns.map)
> +?????????????????????? else:
> +?????????????????????????????? _do_map(mem.number, 0, self._memobj.skpchns.map)
> +
> +?????????????? else:?????? # Freq (VFO) chans
> +?????????????????????? _mem.duplx = 0
> +?????????????????????? _mem.ofst = 0
> +?????????????????????? if mem.duplex == "+":
> +?????????????????????????????? _mem.duplx = 1
> +?????????????????????????????? _mem.ofst = mem.offset / 10
> +?????????????????????? elif mem.duplex == "-":
> +?????????????????????????????? _mem.duplx = 2
> +?????????????????????????????? _mem.ofst = mem.offset / 10
> +?????????????????????? for i in range(self.NAME_LENGTH):
> +?????????????????????????????? _mem.name[i] = 0xff
> +
> +?????????????? # All mem.extra << Once the channel is defined
> +?????????????? for setting in mem.extra:
> +?????????????????????? # Overide list strings with signed value
> +?????????????????????? if setting.get_name() == "ptt":
> +?????????????????????????????? sx = str(setting.value)
> +?????????????????????????????? for i in range(0, 4):
> +?????????????????????????????????????? if sx == LIST_PTT[i]:
> +?????????????????????????????????????????????? val = i
> +?????????????????????????????? setattr(_mem, "ptt", val)
> +?????????????????????? elif setting.get_name() == "epilogue":?? # not inverted bool
> +?????????????????????????????????????? setattr(_mem, setting.get_name(), setting.value)
> +?????????????????????? else:???????????? # inverted booleans
> +?????????????????????????????? setattr(_mem, setting.get_name(), not setting.value)
> +
> +?????? def _set_special(self, mem):
> +
> +?????????????? cur_mem = self._get_special(self.SPECIAL_MEMORIES_REV[mem.number])
> +
> +?????????????? if mem.number == -2:?????? # upper frq[1]
> +?????????????????????? _mem = self._memobj.frq[1]
> +?????????????? elif mem.number == -1:?? # lower frq[0]
> +?????????????????????? _mem = self._memobj.frq[0]
> +?????????????? elif mem.number in range(self.FIRST_FM_INDEX,
> +?????????????????????????????????????? self.LAST_FM_INDEX - 1, -1):
> +?????????????????????? _mem = self._memobj.fm_stations[-self.LAST_FM_INDEX +
> mem.number]
> +?????????????? else:
> +?????????????????????? raise Exception("Sorry, you can't edit that special memory.")
> +
> +?????????????? self._set_memory(mem, _mem)???????? # Now update the _mem
> +
> +?????? def _set_normal(self, mem):
> +?????????????? _mem = self._memobj.chan_mem[mem.number - 1]
> +
> +?????????????? self._set_memory(mem, _mem)
> +
> +?????? def get_settings(self):
> +?????????????? """Translate the MEM_FORMAT structs into setstuf in the UI"""
> +?????????????? # Define mem struct write-back shortcuts
> +?????????????? _sets = self._memobj.setstuf
> +?????????????? _fmx = self._memobj.fmfrqs
> +
> +?????????????? basic = RadioSettingGroup("basic", "Basic Settings")
> +?????????????? adv = RadioSettingGroup("adv", "Other Settings")
> +?????????????? fmb = RadioSettingGroup("fmb", "FM Broadcast")
> +?????????????? scn = RadioSettingGroup("scn", "Scan Settings")
> +?????????????? dtmf = RadioSettingGroup("dtmf", "DTMF Settings")
> +?????????????? frng = RadioSettingGroup("frng", "Frequency Ranges")
> +?????????????? group = RadioSettings(basic, adv, scn, fmb, dtmf, frng)
> +
> +?????????????? def my_val_list(setting, obj, atrb):
> +?????????????????????? """Callback:from ValueList with non-sequential, actual
> values."""
> +?????????????????????? # This call back also used in get_settings
> +?????????????????????? value = int(str(setting.value)) # Get the integer value
> +?????????????????????? setattr(obj, atrb, value)
> +?????????????????????? return
> +
> +?????????????? def my_adjraw(setting, obj, atrb, fix):
> +?????????????????????? """Callback from Integer add or subtract fix from value."""
> +?????????????????????? vx = int(str(setting.value))
> +?????????????????????? value = vx?? + int(fix)
> +?????????????????????? if value < 0:
> +?????????????????????????????? value = 0
> +?????????????????????? setattr(obj, atrb, value)
> +?????????????????????? return
> +
> +?????????????? def my_strnam(setting, obj, atrb, mln):
> +?????????????????????? """Callback from String to build u8 array with -32 offset."""
> +?????????????????????? # mln is max string length
> +?????????????????????? ary = []
> +?????????????????????? knt = mln
> +?????????????????????? for j in range (mln - 1, -1, -1):?? # Strip trailing spaces
> or nulls
> +?????????????????????????????? pq = str(setting.value)[j]
> +?????????????????????????????? if pq == "" or pq == " ":
> +?????????????????????????????????????? knt = knt - 1
> +?????????????????????????????? else:
> +?????????????????????????????????????? break
> +?????????????????????? for j in range(mln):?? # 0 to mln-1
> +?????????????????????????????? pq = str(setting.value).ljust(mln)[j]
> +?????????????????????????????? if j < knt: ary.append(ord(pq) - 32)
> +?????????????????????????????? else: ary.append(0)
> +?????????????????????? setattr(obj, atrb, ary)
> +?????????????????????? return
> +
> +?????????????? def unpack_str(cary, cknt, mxw):
> +?????????????????????? """Convert u8 nibble array to a string: NOT a callback."""
> +?????????????????????? # cknt is char count, 2/word; mxw is max WORDS
> +?????????????????????? stx = ""
> +?????????????????????? mty = True
> +?????????????????????? for i in range(mxw):?????? # unpack entire array
> +?????????????????????????????? nib = (cary[i] & 0xf0) >> 4?? # LE, Hi nib first
> +?????????????????????????????? if nib != 0xf: mty = False
> +?????????????????????????????? stx += format(nib, '0X')
> +?????????????????????????????? nib = cary[i] & 0xf
> +?????????????????????????????? if nib != 0xf: mty = False
> +?????????????????????????????? stx += format(nib, '0X')
> +?????????????????????? stx = stx[:cknt]
> +?????????????????????? if mty:???????? # all ff, empty string
> +?????????????????????????????? sty = ""
> +?????????????????????? else:
> +?????????????????????????????? # Convert E to #, F to *
> +?????????????????????????????? sty = ""
> +?????????????????????????????? for i in range(cknt):
> +?????????????????????????????????????? if stx[i] == "E":
> +?????????????????????????????????????????????? sty += "#"
> +?????????????????????????????????????? elif stx[i] == "F":
> +?????????????????????????????????????????????? sty += "*"
> +?????????????????????????????????????? else:
> +?????????????????????????????????????????????? sty += stx[i]
> +
> +?????????????????????? return sty
> +
> +?????????????? def pack_chars(setting, obj, atrstr, atrcnt, mxl):
> +?????????????????????? """Callback to build 0-9,A-D,*# nibble array from string"""
> +?????????????????????? # cknt is generated char count, 2 chars per word
> +?????????????????????? # String will be f padded to mxl
> +?????????????????????? # Chars are stored as hex values
> +?????????????????????? # store cknt-1 in atrcnt, 0xf if empty
> +?????????????????????? cknt = 0
> +?????????????????????? ary = []
> +?????????????????????? stx = str(setting.value).upper()
> +?????????????????????? stx = stx.strip()???????????? # trim spaces
> +?????????????????????? # Remove illegal characters first
> +?????????????????????? sty = ""
> +?????????????????????? for j in range(0, len(stx)):
> +?????????????????????????????? if stx[j] in self.DTMF_CHARS: sty += stx[j]
> +?????????????????????? for j in range(mxl):
> +?????????????????????????????? if j < len(sty):
> +?????????????????????????????????????? if sty[j] == "#":
> +?????????????????????????????????????????????? chrv = 0xE
> +?????????????????????????????????????? elif sty[j] == "*":
> +?????????????????????????????????????????????? chrv = 0xF
> +?????????????????????????????????????? else:
> +?????????????????????????????????????????????? chrv = int(sty[j], 16)
> +?????????????????????????????????????? cknt += 1?????????? # char count
> +?????????????????????????????? else:???? # pad to mxl, cknt does not increment
> +?????????????????????????????????????? chrv = 0xF
> +?????????????????????????????? if (j % 2) == 0:?? # odd count (0-based), high nibble
> +?????????????????????????????????????? hi_nib = chrv
> +?????????????????????????????? else:???? # even count, lower nibble
> +?????????????????????????????????????? lo_nib = chrv
> +?????????????????????????????????????? nibs = lo_nib | (hi_nib << 4)
> +?????????????????????????????????????? ary.append(nibs)?????? # append word
> +?????????????????????? setattr(obj, atrstr, ary)
> +?????????????????????? if setting.get_name() != "setstuf.stuncode":?? # cknt is actual
> +?????????????????????????????? if cknt > 0:
> +?????????????????????????????????????? cknt = cknt - 1
> +?????????????????????????????? else:
> +?????????????????????????????????????? cknt = 0xf
> +?????????????????????? setattr(obj, atrcnt, cknt)
> +?????????????????????? return
> +
> +?????????????? def myset_freq(setting, obj, atrb, mult):
> +?????????????????????? """ Callback to set frequency by applying multiplier"""
> +?????????????????????? value = int(float(str(setting.value)) * mult)
> +?????????????????????? setattr(obj, atrb, value)
> +?????????????????????? return
> +
> +?????????????? def my_invbool(setting, obj, atrb):
> +?????????????????????? """Callback to invert the boolean """
> +?????????????????????? bval = not setting.value
> +?????????????????????? setattr(obj, atrb, bval)
> +?????????????????????? return
> +
> +?????????????? def my_batsav(setting, obj, atrb):
> +?????????????????????? """Callback to set batsav attribute """
> +?????????????????????? stx = str(setting.value)?? # Off, 1:1...
> +?????????????????????? if stx == "Off":
> +?????????????????????????????? value = 0x1???????? # bit value 4 clear, ratio 1 = 1:2
> +?????????????????????? elif stx == "1:1":
> +?????????????????????????????? value = 0x4???????? # On, ratio 0 = 1:1
> +?????????????????????? elif stx == "1:2":
> +?????????????????????????????? value = 0x5???????? # On, ratio 1 = 1:2
> +?????????????????????? elif stx == "1:3":
> +?????????????????????????????? value = 0x6???????? # On, ratio 2 = 1:3
> +?????????????????????? else:
> +?????????????????????????????? value = 0x7???????? # On, ratio 3 = 1:4
> +?????????????????????? # LOG.warning("Batsav stx:%s:, value= %x" % (stx, value))
> +?????????????????????? setattr(obj, atrb, value)
> +?????????????????????? return
> +
> +?????????????? def my_manfrq(setting, obj, atrb):
> +?????????????????????? """Callback to set 2-byte manfrqyn yes/no """
> +?????????????????????? # LOG.warning("Manfrq value = %d" % setting.value)
> +?????????????????????? if (str(setting.value)) == "No":
> +?????????????????????????????? value = 0xff
> +?????????????????????? else:
> +?????????????????????????????? value = 0xaa
> +?????????????????????? setattr(obj, atrb, value)
> +?????????????????????? return
> +
> +?????????????? rx = RadioSettingValueInteger(1, 9, _sets.voxgain + 1)
> +?????????????? rset = RadioSetting("setstuf.voxgain", "Vox Level", rx)
> +?????????????? rset.set_apply_callback(my_adjraw, _sets, "voxgain", -1)
> +?????????????? basic.append(rset)
> +
> +?????????????? rx = RadioSettingValueList(LIST_VOXDLY,
> LIST_VOXDLY[_sets.voxdelay])
> +?????????????? rset = RadioSetting("setstuf.voxdelay", "Vox Delay (secs)", rx)
> +?????????????? basic.append(rset)
> +
> +?????????????? rx = RadioSettingValueInteger(0, 9, _sets.sql)
> +?????????????? rset = RadioSetting("setstuf.sql", "Squelch", rx)
> +?????????????? basic.append(rset)
> +
> +?????????????? rx = RadioSettingValueList(LIST_STEPS, LIST_STEPS[_sets.freqstep])
> +?????????????? rset = RadioSetting("setstuf.freqstep", "VFO Tune Step (KHz))", rx)
> +?????????????? basic.append(rset)
> +
> +?????????????? rx = RadioSettingValueBoolean(bool(_sets.dbw))???????? # true logic
> +?????????????? rset = RadioSetting("setstuf.dbw", "Dual Band Watch (D.WAIT)", rx)
> +?????????????? basic.append(rset)
> +
> +?????????????? options = ["Off", "On", "Auto"]
> +?????????????? rx = RadioSettingValueList(options, options[_sets.lampon])
> +?????????????? rset = RadioSetting("setstuf.lampon", "Backlight (LED)", rx)
> +?????????????? basic.append(rset)
> +
> +?????????????? options = ["Orange", "Purple", "Blue"]
> +?????????????? rx = RadioSettingValueList(options, options[_sets.ledclr])
> +?????????????? rset = RadioSetting("setstuf.ledclr", "Backlight Color
> (LIGHT)", rx)
> +?????????????? basic.append(rset)
> +
> +?????????????? rx = RadioSettingValueBoolean(bool(_sets.beepon))
> +?????????????? rset = RadioSetting("setstuf.beepon", "Keypad Beep", rx)
> +?????????????? basic.append(rset)
> +
> +?????????????? rx = RadioSettingValueBoolean(bool(_sets.xbandenable))
> +?????????????? rset = RadioSetting("setstuf.xbandenable", "Cross Band
> Allowed", rx)
> +?????????????? basic.append(rset)
> +
> +?????????????? rx = RadioSettingValueBoolean(bool(not _sets.xbandon))
> +?????????????? rset = RadioSetting("setstuf.xbandon", "Cross Band On", rx)
> +?????????????? rset.set_apply_callback(my_invbool, _sets, "xbandon")
> +?????????????? basic.append(rset)
> +
> +?????????????? rx = RadioSettingValueList(LIST_TIMEOUT, LIST_TIMEOUT[_sets.tot])
> +?????????????? rset = RadioSetting("setstuf.tot", "TX Timeout (Secs)", rx)
> +?????????????? basic.append(rset)
> +
> +?????????????? rx = RadioSettingValueBoolean(bool(not _sets.rgrbeep))?? # Invert
> +?????????????? rset = RadioSetting("setstuf.rgrbeep", "Beep at Eot (Roger)", rx)
> +?????????????? rset.set_apply_callback(my_invbool, _sets, "rgrbeep")
> +?????????????? basic.append(rset)
> +
> +?????????????? rx = RadioSettingValueBoolean(bool(not _sets.keylok))
> +?????????????? rset = RadioSetting("setstuf.keylok", "Keypad AutoLock", rx)
> +?????????????? rset.set_apply_callback(my_invbool, _sets, "keylok")
> +?????????????? basic.append(rset)
> +
> +?????????????? options = ["None", "Message", "DC Volts"]
> +?????????????? rx = RadioSettingValueList(options, options[_sets.openmsg])
> +?????????????? rset = RadioSetting("setstuf.openmsg", "Power-On Display", rx)
> +?????????????? basic.append(rset)
> +
> +?????????????? options = ["Channel Name", "Frequency"]
> +?????????????? rx = RadioSettingValueList(options, options[_sets.chs_name])
> +?????????????? rset = RadioSetting("setstuf.chs_name", "Display Name/Frq", rx)
> +?????????????? basic.append(rset)
> +
> +?????????????? sx = ""
> +?????????????? for i in range(7):
> +?????????????????????? if _sets.radioname[i] != 0:
> +?????????????????????????????? sx += chr(_sets.radioname[i] + 32)
> +?????????????? rx = RadioSettingValueString(0, 7, sx)
> +?????????????? rset = RadioSetting("setstuf.radioname", "Power-On Message", rx)
> +?????????????? rset.set_apply_callback(my_strnam, _sets, "radioname", 7)
> +?????????????? basic.append(rset)
> +
> +?????????????? # Advanced (Strange) Settings
> +?????????????? options = ["Busy: Last Tx Band", "Edit: Current Band"]
> +?????????????? rx?? = RadioSettingValueList(options, options[_sets.txsel])
> +?????????????? rset = RadioSetting("setstuf.txsel", "Transmit Priority", rx)
> +?????????????? rset.set_doc("'Busy' transmits on last band used, not current
> one.")
> +?????????????? adv.append(rset)
> +
> +?????????????? options = ["Off", "English", "Unk", "Chinese"]
> +?????????????? val = _sets.voice
> +?????????????? rx = RadioSettingValueList(options, options[val])
> +?????????????? rset = RadioSetting("setstuf.voice", "Voice", rx)
> +?????????????? adv.append(rset)
> +
> +?????????????? options = ["Off", "1:1", "1:2", "1:3", "1:4"]
> +?????????????? val = (_sets.batsav & 0x3) +1???????? # ratio
> +?????????????? if (_sets.batsav & 0x4) == 0:?????? # Off
> +?????????????????????? val = 0
> +?????????????? rx = RadioSettingValueList(options, options[val])
> +?????????????? rset = RadioSetting("setstuf.batsav", "Battery Saver", rx)
> +?????????????? rset.set_apply_callback(my_batsav, _sets, "batsav")
> +?????????????? adv.append(rset)
> +
> +?????????????? # Find out what & where SuperSave is
> +?????????????? options = ["Off", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
> +?????????????? rx = RadioSettingValueList(options, options[_sets.supersave])
> +?????????????? rset = RadioSetting("setstuf.supersave", "Super Save (Secs)", rx)
> +?????????????? rset.set_doc("Unknown radio attribute??")
> +?????????????? adv.append(rset)
> +
> +?????????????? sx = unpack_str(_sets.pttbot, _sets.pttbcnt + 1, 8)
> +?????????????? rx = RadioSettingValueString(0, 16, sx)
> +?????????????? rset = RadioSetting("setstuf.pttbot", "PTT BoT Code", rx)
> +?????????????? rset.set_apply_callback(pack_chars, _sets, "pttbot", "pttbcnt", 16)
> +?????????????? adv.append(rset)
> +
> +?????????????? sx = unpack_str(_sets.ptteot, _sets.pttecnt + 1, 8)
> +?????????????? rx = RadioSettingValueString(0, 16, sx)
> +?????????????? rset = RadioSetting("setstuf.ptteot", "PTT EoT Code", rx)
> +?????????????? rset.set_apply_callback(pack_chars, _sets, "ptteot", "pttecnt", 16)
> +?????????????? adv.append(rset)
> +
> +?????????????? options = ["None", "Low", "High", "Both"]
> +?????????????? rx = RadioSettingValueList(options, options[_sets.voltx])
> +?????????????? rset = RadioSetting("setstuf.voltx", "Transmit Inhibit
> Voltage", rx)
> +?????????????? rset.set_doc("Block Transmit if battery volts are too high or
> low,")
> +?????????????? adv.append(rset)
> +
> +?????????????? val = 0???????? # No = 0xff
> +?????????????? if _sets.manfrqyn == 0xaa: val = 1
> +?????????????? options = ["No", "Yes"]
> +?????????????? rx = RadioSettingValueList(options, options[val])
> +?????????????? rset = RadioSetting("setstuf.manfrqyn", "Manual Frequency", rx)
> +?????????????? rset.set_apply_callback(my_manfrq, _sets, "manfrqyn")
> +?????????????? adv.append(rset)
> +
> +?????????????? rx = RadioSettingValueBoolean(bool(_sets.manualset))
> +?????????????? rset = RadioSetting("setstuf.manualset", "Manual Setting", rx)
> +?????????????? adv.append(rset)
> +
> +?????????????? # Scan Settings
> +?????????????? options = ["CO: During Rx", "TO: Timed", "SE: Halt"]
> +?????????????? rx = RadioSettingValueList(options, options[_sets.scanmode])
> +?????????????? rset = RadioSetting("setstuf.scanmode",
> +???????????????????????????????????? "Scan Mode (Scan Pauses When)", rx)
> +?????????????? scn.append(rset)
> +
> +?????????????? options = ["100", "150", "200", "250",
> +???????????????????????????????????? "300", "350", "400", "450"]
> +?????????????? rx = RadioSettingValueList(options, options[_sets.scanspeed])
> +?????????????? rset = RadioSetting("setstuf.scanspeed", "Scan Speed (ms)", rx)
> +?????????????? scn.append(rset)
> +
> +?????????????? val =_sets.scantmo + 3
> +?????????????? rx = RadioSettingValueInteger(3, 30, val)
> +?????????????? rset = RadioSetting("setstuf.scantmo",
> +?????????????????????????????? "TO Mode Timeout (secs)", rx)
> +?????????????? rset.set_apply_callback(my_adjraw, _sets, "scantmo", -3)
> +?????????????? scn.append(rset)
> +
> +?????????????? val = _sets.prichan
> +?????????????? if val <= 0: val = 1
> +?????????????? rx = RadioSettingValueInteger(1, 128, val)
> +?????????????? rset = RadioSetting("setstuf.prichan", "Priority Channel", rx)
> +?????????????? scn.append(rset)
> +
> +?????????????? # FM Broadcast Settings
> +?????????????? val =_fmx.fmcur
> +?????????????? val = val / 40.0
> +?????????????? if val < 87.5 or val > 107.9: val = 88.0
> +?????????????? rx = RadioSettingValueFloat(87.5, 107.9, val, 0.1, 1)
> +?????????????? rset = RadioSetting("fmfrqs.fmcur", "Manual FM Freq (MHz)", rx)
> +?????????????? rset.set_apply_callback(myset_freq, _fmx, "fmcur", 40)
> +?????????????? fmb.append(rset)
> +
> +?????????????? options = ["5", "50", "100", "200(USA)"]?????? # 5 is not used
> +?????????????? rx = RadioSettingValueList(options, options[_sets.fmstep])
> +?????????????? rset = RadioSetting("setstuf.fmstep", "FM Freq Step (KHz)", rx)
> +?????????????? fmb.append(rset)
> +
> +?????????????? if False:???? # Skip these unknowns
> +?????????????????????? # FM Scan Range lo and Hi ??? MEM
> +?????????????????????? val = 87.5
> +?????????????????????? rx = RadioSettingValueFloat(87.5, 107.9, val, 0.1, 1)
> +?????????????????????? rset = RadioSetting("setstuf.fmsclo",
> +???????????????????????????????????? "Low FM Scan Bound (MHz)", rx)
> +?????????????????????? rset.set_apply_callback(myset_freq, _sets, "fmsclo", 40)
> +?????????????????????? fmb.append(rset)
> +
> +?????????????????????? val = 107.9???????? # ??? @@@ where
> +?????????????????????? rx = RadioSettingValueFloat(87.5, 107.9, val, 0.1, 1)
> +?????????????????????? rset = RadioSetting("setstuf.fmschi",
> +???????????????????????????????????? "High FM Scan Freq (MHz)", rx)
> +?????????????????????? rset.set_apply_callback(myset_freq, _sets, "fmschi", 40)
> +?????????????????????? fmb.append(rset)
> +
> +?????????????? rx = RadioSettingValueBoolean(bool(_sets.rxinhib))
> +?????????????? rset = RadioSetting("setstuf.rxinhib",
> +?????????????????????????????? "Rcvr Will Interupt FM (DW)", rx)
> +?????????????? fmb.append(rset)
> +
> +?????????????? options = [str(x) for x in range(4, 16)]
> +?????????????? rx = RadioSettingValueList(options, options[_sets.dtmfspd])
> +?????????????? rset = RadioSetting("setstuf.dtmfspd",
> +???????????????????????????????????? "Tx Speed (digits/sec)", rx)
> +?????????????? dtmf.append(rset)
> +
> +?????????????? options = [str(x) for x in range(0, 1100, 100)]
> +?????????????? rx = RadioSettingValueList(options, options[_sets.dtmfdig1time])
> +?????????????? rset = RadioSetting("setstuf.dtmfdig1time",
> +?????????????????????????????? "Tx 1st Digit Time (ms)", rx)
> +?????????????? dtmf.append(rset)
> +
> +?????????????? options = [str(x) for x in range(100, 1100, 100)]
> +?????????????? rx = RadioSettingValueList(options, options[_sets.dtmfdig1dly])
> +?????????????? rset = RadioSetting("setstuf.dtmfdig1dly",
> +???????????????????????????????????? "Tx 1st Digit Delay (ms)", rx)
> +?????????????? dtmf.append(rset)
> +
> +?????????????? options = ["0", "100", "500", "1000"]
> +?????????????? rx = RadioSettingValueList(options, options[_sets.dtmfspms])
> +?????????????? rset = RadioSetting("setstuf.dtmfspms",
> +???????????????????????????????????? "Tx Star & Pound Time (ms)", rx)
> +?????????????? dtmf.append(rset)
> +
> +?????????????? options = ["None"] + [str(x) for x in range(600, 2100, 100)]
> +?????????????? rx = RadioSettingValueList(options, options[_sets.codespctim])
> +?????????????? rset = RadioSetting("setstuf.codespctim",
> +???????????????????????????????????? "Tx Code Space Time (ms)", rx)
> +?????????????? dtmf.append(rset)
> +
> +?????????????? rx = RadioSettingValueBoolean(bool(_sets.codeabcd))
> +?????????????? rset = RadioSetting("setstuf.codeabcd", "Tx Codes A,B,C,D", rx)
> +?????????????? dtmf.append(rset)
> +
> +?????????????? rx = RadioSettingValueBoolean(bool(_sets.dtmfside))
> +?????????????? rset = RadioSetting("setstuf.dtmfside", "DTMF Side Tone", rx)
> +?????????????? dtmf.append(rset)
> +
> +?????????????? options = ["Off", "A", "B", "C", "D"]
> +?????????????? rx = RadioSettingValueList(options, options[_sets.grpcode])
> +?????????????? rset = RadioSetting("setstuf.grpcode", "Rx Group Code", rx)
> +?????????????? dtmf.append(rset)
> +
> +?????????????? options = ["Off"] + [str(x) for x in range(1, 16)]
> +?????????????? rx = RadioSettingValueList(options, options[_sets.autoresettmo])
> +?????????????? rset = RadioSetting("setstuf.autoresettmo",
> +???????????????????????????????????? "Rx Auto Reset Timeout (secs)", rx)
> +?????????????? dtmf.append(rset)
> +
> +?????????????? rx = RadioSettingValueBoolean(bool(_sets.txdecode))
> +?????????????? rset = RadioSetting("setstuf.txdecode", "Tx Decode", rx)
> +?????????????? dtmf.append(rset)
> +
> +?????????????? rx = RadioSettingValueBoolean(bool(_sets.idedit))
> +?????????????? rset = RadioSetting("setstuf.idedit", "Allow ANI Code Edit", rx)
> +?????????????? dtmf.append(rset)
> +
> +?????????????? options = [str(x) for x in range(500, 1600, 100)]
> +?????????????? rx = RadioSettingValueList(options, options[_sets.decodetmo])
> +?????????????? rset = RadioSetting("setstuf.decodetmo",
> +?????????????????????????????? "Rx Decode Timeout (ms)", rx)
> +?????????????? dtmf.append(rset)
> +
> +?????????????? options = ["Tx & Rx Inhibit", "Tx Inhibit"]
> +?????????????? rx = RadioSettingValueList(options, options[_sets.stuntype])
> +?????????????? rset = RadioSetting("setstuf.stuntype", "Stun Type", rx)
> +?????????????? dtmf.append(rset)
> +
> +?????????????? sx = unpack_str(_sets.stuncode, _sets.stuncnt, 5)
> +?????????????? rx = RadioSettingValueString(0, 10, sx)
> +?????????????? rset = RadioSetting("setstuf.stuncode", "Stun Code", rx)
> +?????????????? rset.set_apply_callback(pack_chars, _sets,
> +???????????????????????????????????? "stuncode", "stuncnt", 10)
> +?????????????? dtmf.append(rset)
> +
> +?????????????? # Frequency ranges
> +?????????????? rx = RadioSettingValueBoolean(bool(_sets.frqr1))
> +?????????????? rset = RadioSetting("setstuf.frqr1", "Freq Range 1 (UHF)", rx)
> +?????????????? rset.set_doc("Enable the UHF frequency bank.")
> +?????????????? frng.append(rset)
> +
> +?????????????? rx = RadioSettingValueBoolean(bool(_sets.frqr2))
> +?????????????? rset = RadioSetting("setstuf.frqr2", "Freq Range 2 (VHF)", rx)
> +?????????????? rset.set_doc("Enable the VHF frequency bank.")
> +?????????????? frng.append(rset)
> +
> +?????????????? mod_se = True???????? # UV8000SE has 3rd freq bank
> +?????????????? if mod_se:
> +?????????????????????? rx = RadioSettingValueBoolean(bool(_sets.frqr3))
> +?????????????????????? rset = RadioSetting("setstuf.frqr3", "Freq Range 3
> (220Mhz)", rx)
> +?????????????????????? rset.set_doc("Enable the 220MHz frequency bank.")
> +?????????????????????? frng.append(rset)
> +
> +?????????????? frqm = 100000
> +?????????????? val = _sets.frqr1lo / frqm
> +?????????????? rx = RadioSettingValueFloat(400.0, 520.0, val, 0.005, 3)
> +?????????????? rset = RadioSetting("setstuf.frqr1lo",
> +???????????????????????????????????? "UHF Range Low Limit (MHz)", rx)
> +?????????????? rset.set_apply_callback(myset_freq, _sets, "frqr1lo", frqm)
> +?????????????? rset.set_doc("Low limit of the UHF frequency bank.")
> +?????????????? frng.append(rset)
> +
> +?????????????? val = _sets.frqr1hi / frqm
> +?????????????? rx = RadioSettingValueFloat(400.0, 520.0, val, 0.005, 3)
> +?????????????? rset = RadioSetting("setstuf.frqr1hi",
> +?????????????????????? "UHF Range High Limit (MHz)", rx)
> +?????????????? rset.set_apply_callback(myset_freq, _sets, "frqr1hi", frqm)
> +?????????????? rset.set_doc("High limit of the UHF frequency bank.")
> +?????????????? frng.append(rset)
> +
> +?????????????? val = _sets.frqr2lo / frqm
> +?????????????? rx = RadioSettingValueFloat(136.0, 174.0, val, 0.005, 3)
> +?????????????? rset = RadioSetting("setstuf.frqr2lo",
> +???????????????????????????????????? "VHF Range Low Limit (MHz)", rx)
> +?????????????? rset.set_apply_callback(myset_freq, _sets, "frqr2lo", frqm)
> +?????????????? rset.set_doc("Low limit of the VHF frequency bank.")
> +?????????????? frng.append(rset)
> +
> +?????????????? val = _sets.frqr2hi / frqm
> +?????????????? rx = RadioSettingValueFloat(136.0, 174.0, val, 0.005, 3)
> +?????????????? rset = RadioSetting("setstuf.frqr2hi",
> +?????????????????????????????? "VHF Range High Limit (MHz)", rx)
> +?????????????? rset.set_apply_callback(myset_freq, _sets, "frqr2hi", frqm)
> +?????????????? rset.set_doc("High limit of the VHF frequency bank.")
> +?????????????? frng.append(rset)
> +
> +?????????????? if mod_se:
> +?????????????????????? val = _sets.frqr3lo / frqm
> +?????????????????????? if val == 0: val = 222.0
> +?????????????????????? rx = RadioSettingValueFloat(220.0, 260.0, val, 0.005, 3)
> +?????????????????????? rset = RadioSetting("setstuf.frqr3lo",
> +???????????????????????????????????? "1.25m Range Low Limit (MHz)", rx)
> +?????????????????????? rset.set_apply_callback(myset_freq, _sets, "frqr3lo", frqm)
> +?????????????????????? frng.append(rset)
> +
> +?????????????????????? val = _sets.frqr3hi / frqm
> +?????????????????????? if val == 0: val = 225.0
> +?????????????????????? rx = RadioSettingValueFloat(220.0, 260.0, val, 0.005, 3)
> +?????????????????????? rset = RadioSetting("setstuf.frqr3hi",
> +?????????????????????????????????????? "1.25m Range High Limit (MHz)", rx)
> +?????????????????????? rset.set_apply_callback(myset_freq, _sets, "frqr3hi", 1000)
> +?????????????????????? frng.append(rset)
> +
> +?????????????? return group???????????? # END get_settings()
> +
> +
> +?????? def set_settings(self, settings):
> +?????????????? _settings = self._memobj.setstuf
> +?????????????? _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
> +
> +?????? @classmethod
> +?????? def match_model(cls, filedata, filename):
> +?????????????? match_size = False
> +?????????????? match_model = False
> +
> +?????????????? # Testing the file data size
> +?????????????? if len(filedata) == MEM_SIZE + 10:
> +?????????????????????? match_size = True
> +
> +?????????????? # Testing the firmware model fingerprint
> +?????????????? match_model = model_match(cls, filedata)
> +
> +?????????????? if match_size and match_model:
> +?????????????????????? return True
> +?????????????? else:
> +?????????????????????? return False
>
>
> --
> Rick DeWitt
> AA0RD
> Sequim, Washington, USA 98382
> (360) 681-3494
>
> _______________________________________________
> chirp_devel mailing list
> chirp_devel at intrepid.danplanet.com
> http://intrepid.danplanet.com/mailman/listinfo/chirp_devel
> Developer docs: http://chirp.danplanet.com/projects/chirp/wiki/Developers
More information about the chirp_devel
mailing list