[hamradio-commits] [chirp] 01/03: New upstream version 20161123
Iain R. Learmonth
irl at moszumanska.debian.org
Sat Dec 3 15:47:11 UTC 2016
This is an automated email from the git hooks/post-receive script.
irl pushed a commit to branch master
in repository chirp.
commit b048c8e58e1d3c879a022b081c017aa0bc1d5f47
Author: Iain R. Learmonth <irl at fsfe.org>
Date: Sat Dec 3 15:42:16 2016 +0000
New upstream version 20161123
---
PKG-INFO | 2 +-
chirp/__init__.py | 2 +-
chirp/drivers/alinco.py | 211 +++++++
chirp/drivers/btech.py | 916 ++++++++++++++++++++++++++++++
chirp/drivers/ft2900.py | 37 +-
chirp/drivers/ft60.py | 64 ++-
chirp/drivers/ft817.py | 9 +-
chirp/drivers/kguv8d.py | 48 +-
chirp/drivers/kyd.py | 67 ++-
chirp/drivers/leixen.py | 88 ++-
chirp/drivers/{kyd.py => retevis_rt22.py} | 269 ++++++---
chirp/drivers/thd72.py | 6 +-
chirp/drivers/uv5r.py | 30 +-
chirp/drivers/uv5x3.py | 29 +
chirp/settings.py | 15 +-
chirp/ui/mainapp.py | 3 +-
chirp/ui/settingsedit.py | 10 +-
17 files changed, 1615 insertions(+), 191 deletions(-)
diff --git a/PKG-INFO b/PKG-INFO
index cfa0b9c..f336a43 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.0
Name: chirp
-Version: daily-20161102
+Version: daily-20161123
Summary: UNKNOWN
Home-page: UNKNOWN
Author: UNKNOWN
diff --git a/chirp/__init__.py b/chirp/__init__.py
index 9cd6026..33863f9 100644
--- a/chirp/__init__.py
+++ b/chirp/__init__.py
@@ -17,7 +17,7 @@ import os
import sys
from glob import glob
-CHIRP_VERSION="daily-20161102"
+CHIRP_VERSION="daily-20161123"
module_dir = os.path.dirname(sys.modules["chirp"].__file__)
__all__ = []
diff --git a/chirp/drivers/alinco.py b/chirp/drivers/alinco.py
index 5662aaa..65ff70f 100644
--- a/chirp/drivers/alinco.py
+++ b/chirp/drivers/alinco.py
@@ -1,4 +1,5 @@
# Copyright 2011 Dan Smith <dsmith at danplanet.com>
+# 2016 Matt Weyland <lt-betrieb at hb9uf.ch>
#
# 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
@@ -566,3 +567,213 @@ class DJ175Radio(DRx35Radio):
raise Exception("Radio returned less than 16 bytes")
return data
+
+
+DJG7EG_MEM_FORMAT = """
+#seekto 0x200;
+ul16 bank[50];
+ul16 special_bank[7];
+#seekto 0x1200;
+struct {
+ u8 unknown;
+ ul32 freq;
+ u8 mode;
+ u8 step;
+ ul32 offset;
+ u8 duplex;
+ u8 squelch_type;
+ u8 tx_tone;
+ u8 rx_tone;
+ u8 dcs;
+#seek 3;
+ u8 skip;
+#seek 12;
+ char name[32];
+} memory[1000];
+"""
+
+ at directory.register
+class AlincoDJG7EG(AlincoStyleRadio):
+ """Alinco DJ-G7EG"""
+ VENDOR = "Alinco"
+ MODEL = "DJ-G7EG"
+ BAUD_RATE = 57600
+
+ # Those are different from the other Alinco radios.
+ STEPS = [5.0, 6.25, 8.33, 10.0, 12.5, 15.0, 20.0, 25.0, 30.0, 50.0, 100.0, 125.0, 150.0, 200.0, 500.0, 1000.0]
+ DUPLEX = ["", "+", "-"]
+ MODES = ["NFM", "FM", "AM", "WFM"]
+ TMODES = ["", "??1", "Tone", "TSQL", "TSQL-R", "DTCS"]
+
+ _model = "AL~DJ-G7EG" # This is a bit of a hack to avoid overwriting _identify()
+ _memsize = 0x1a7c0
+ _range = [(500000, 1300000000)]
+
+ def get_features(self):
+ rf = chirp_common.RadioFeatures()
+ rf.has_dtcs_polarity = False
+ rf.has_bank = False
+ rf.has_settings = False
+
+ rf.valid_modes = self.MODES
+ rf.valid_tmodes = ["", "Tone", "TSQL", "Cross", "TSQL-R", "DTCS"]
+ rf.valid_tuning_steps = self.STEPS
+ rf.valid_bands = self._range
+ rf.valid_skips = ["", "S"]
+ rf.valid_characters = chirp_common.CHARSET_ASCII
+ rf.valid_name_length = 16
+ rf.memory_bounds = (0, 999)
+
+ return rf
+
+ def _download_chunk(self, addr):
+ if addr % 0x40:
+ raise Exception("Addr 0x%04x not on 64-byte boundary" % addr)
+
+ cmd = "AL~F%05XR\r" % addr
+ self._send(cmd)
+
+ # Response: "\r\n[ ... data ... ]\r\n
+ # data is encoded in hex, hence we read two chars per byte
+ _data = self._read(2+2*64+2).strip()
+ if len(_data) == 0:
+ raise errors.RadioError("No response from radio")
+
+ data = ""
+ for i in range(0, len(_data), 2):
+ data += chr(int(_data[i:i+2], 16))
+
+ if len(data) != 64:
+ LOG.debug("Response was:")
+ LOG.debug("|%s|")
+ LOG.debug("Which I converted to:")
+ LOG.debug(util.hexprint(data))
+ raise Exception("Chunk from radio has wrong size")
+
+ return data
+
+ def _download(self, limit):
+ self._identify()
+
+ data = "\x00"*0x200
+
+ for addr in range(0x200, limit, 0x40):
+ data += self._download_chunk(addr)
+ # Other Alinco drivers delay here, but doesn't seem to be necessary
+ # for this model.
+
+ if self.status_fn:
+ status = chirp_common.Status()
+ status.cur = addr
+ status.max = limit
+ status.msg = "Downloading from radio"
+ self.status_fn(status)
+ return memmap.MemoryMap(data)
+
+ def _upload_chunk(self, addr):
+ if addr % 0x40:
+ raise Exception("Addr 0x%04x not on 64-byte boundary" % addr)
+
+ _data = self._mmap[addr:addr+0x40]
+ data = "".join(["%02X" % ord(x) for x in _data])
+
+ cmd = "AL~F%05XW%s\r" % (addr, data)
+ self._send(cmd)
+
+ resp = self._read(6)
+ if resp.strip() != "OK":
+ raise Exception("Unexpected response from radio: %s" % resp)
+
+ def _upload(self, limit):
+ if not self._identify():
+ raise Exception("I can't talk to this model")
+
+ for addr in range(0x200, self._memsize, 0x40):
+ self._upload_chunk(addr)
+ # Other Alinco drivers delay here, but doesn't seem to be necessary
+ # for this model.
+
+ if self.status_fn:
+ status = chirp_common.Status()
+ status.cur = addr
+ status.max = self._memsize
+ status.msg = "Uploading to radio"
+ self.status_fn(status)
+
+ def process_mmap(self):
+ self._memobj = bitwise.parse(DJG7EG_MEM_FORMAT, self._mmap)
+
+ def get_memory(self, number):
+ _mem = self._memobj.memory[number]
+ mem = chirp_common.Memory()
+ mem.number = number
+ if _mem.unknown == 0:
+ mem.empty = True
+ else:
+ mem.freq = int(_mem.freq)
+ mem.mode = self.MODES[_mem.mode]
+ mem.tuning_step = self.STEPS[_mem.step]
+ mem.offset = int(_mem.offset)
+ mem.duplex = self.DUPLEX[_mem.duplex]
+ if self.TMODES[_mem.squelch_type] == "TSQL" and _mem.tx_tone != _mem.rx_tone:
+ mem.tmode = "Cross"
+ mem.cross_mode = "Tone->Tone"
+ else:
+ mem.tmode = self.TMODES[_mem.squelch_type]
+ mem.rtone = ALINCO_TONES[_mem.tx_tone-1]
+ mem.ctone = ALINCO_TONES[_mem.rx_tone-1]
+ mem.dtcs = DCS_CODES[self.VENDOR][_mem.dcs]
+ if _mem.skip:
+ mem.skip = "S"
+ # FIXME find out what every other byte is used for. Japanese?
+ mem.name = str(_mem.name.get_raw()[::2]).rstrip('\0')
+ return mem
+
+ def set_memory(self, mem):
+ # Get a low-level memory object mapped to the image
+ _mem = self._memobj.memory[mem.number]
+ if mem.empty:
+ _mem.unknown = 0x00 # Maybe 0 is empty, 2 is used?
+ else:
+ _mem.unknown = 0x02
+ _mem.freq = mem.freq
+ _mem.mode = self.MODES.index(mem.mode)
+ _mem.step = self.STEPS.index(mem.tuning_step)
+ _mem.offset = mem.offset
+ _mem.duplex = self.DUPLEX.index(mem.duplex)
+ if mem.tmode == "Cross":
+ _mem.squelch_type = self.TMODES.index("TSQL")
+ try:
+ _mem.tx_tone = ALINCO_TONES.index(mem.rtone)+1
+ except ValueError:
+ raise errors.UnsupportedToneError("This radio does not support " +
+ "tone %.1fHz" % mem.rtone)
+ try:
+ _mem.rx_tone = ALINCO_TONES.index(mem.ctone)+1
+ except ValueError:
+ raise errors.UnsupportedToneError("This radio does not support " +
+ "tone %.1fHz" % mem.ctone)
+ elif mem.tmode == "TSQL":
+ _mem.squelch_type = self.TMODES.index("TSQL")
+ # Note how the same TSQL tone is copied to both memory locaations
+ try:
+ _mem.tx_tone = ALINCO_TONES.index(mem.ctone)+1
+ _mem.rx_tone = ALINCO_TONES.index(mem.ctone)+1
+ except ValueError:
+ raise errors.UnsupportedToneError("This radio does not support " +
+ "tone %.1fHz" % mem.ctone)
+ else:
+ _mem.squelch_type = self.TMODES.index(mem.tmode)
+ try:
+ _mem.tx_tone = ALINCO_TONES.index(mem.rtone)+1
+ except ValueError:
+ raise errors.UnsupportedToneError("This radio does not support " +
+ "tone %.1fHz" % mem.rtone)
+ try:
+ _mem.rx_tone = ALINCO_TONES.index(mem.ctone)+1
+ except ValueError:
+ raise errors.UnsupportedToneError("This radio does not support " +
+ "tone %.1fHz" % mem.ctone)
+ _mem.dcs = DCS_CODES[self.VENDOR].index(mem.dtcs)
+ _mem.skip = (mem.skip == "S")
+ _mem.name = "\x00".join(mem.name).ljust(32,"\x00")
diff --git a/chirp/drivers/btech.py b/chirp/drivers/btech.py
index 3d634fa..249f29c 100644
--- a/chirp/drivers/btech.py
+++ b/chirp/drivers/btech.py
@@ -155,6 +155,129 @@ struct {
u8 unknown1[10];
} names[200];
+#seekto 0x2400;
+struct {
+ u8 period; // one out of LIST_5TONE_STANDARD_PERIODS
+ u8 group_tone;
+ u8 repeat_tone;
+ u8 unused[13];
+} _5tone_std_settings[15];
+
+#seekto 0x2500;
+struct {
+ u8 frame1[5];
+ u8 frame2[5];
+ u8 frame3[5];
+ u8 standard; // one out of LIST_5TONE_STANDARDS
+} _5tone_codes[15];
+
+#seekto 0x25F0;
+struct {
+ u8 _5tone_delay1; // * 10ms
+ u8 _5tone_delay2; // * 10ms
+ u8 _5tone_delay3; // * 10ms
+ u8 _5tone_first_digit_ext_length;
+ u8 unknown1;
+ u8 unknown2;
+ u8 unknown3;
+ u8 unknown4;
+ u8 decode_standard;
+ u8 unknown5:5,
+ _5tone_decode_call_frame3:1,
+ _5tone_decode_call_frame2:1,
+ _5tone_decode_call_frame1:1;
+ u8 unknown6:5,
+ _5tone_decode_disp_frame3:1,
+ _5tone_decode_disp_frame2:1,
+ _5tone_decode_disp_frame1:1;
+ u8 decode_reset_time; // * 100 + 100ms
+} _5tone_settings;
+
+#seekto 0x2900;
+struct {
+ u8 code[16]; // 0=x0A, A=0x0D, B=0x0E, C=0x0F, D=0x00, #=0x0C *=0x0B
+} dtmf_codes[15];
+
+#seekto 0x29F0;
+struct {
+ u8 dtmfspeed_on; //list with 50..2000ms in steps of 10
+ u8 dtmfspeed_off; //list with 50..2000ms in steps of 10
+ u8 unknown0[14];
+ u8 inspection[16];
+ u8 monitor[16];
+ u8 alarmcode[16];
+ u8 stun[16];
+ u8 kill[16];
+ u8 revive[16];
+ u8 unknown1[16];
+ u8 unknown2[16];
+ u8 unknown3[16];
+ u8 unknown4[16];
+ u8 unknown5[16];
+ u8 unknown6[16];
+ u8 unknown7[16];
+ u8 masterid[16];
+ u8 viceid[16];
+ u8 unused01:7,
+ mastervice:1;
+ u8 unused02:3,
+ mrevive:1,
+ mkill:1,
+ mstun:1,
+ mmonitor:1,
+ minspection:1;
+ u8 unused03:3,
+ vrevive:1,
+ vkill:1,
+ vstun:1,
+ vmonitor:1,
+ vinspection:1;
+ u8 unused04:6,
+ txdisable:1,
+ rxdisable:1;
+ u8 groupcode;
+ u8 spacecode;
+ u8 delayproctime; // * 100 + 100ms
+ u8 resettime; // * 100 + 100ms
+} dtmf_settings;
+
+#seekto 0x2D00;
+struct {
+ struct {
+ ul16 freq1;
+ u8 unused01[6];
+ ul16 freq2;
+ u8 unused02[6];
+ } _2tone_encode[15];
+ u8 duration_1st_tone; // *10ms
+ u8 duration_2nd_tone; // *10ms
+ u8 duration_gap; // *10ms
+ u8 unused03[13];
+ struct {
+ struct {
+ u8 dec; // one out of LIST_2TONE_DEC
+ u8 response; // one out of LIST_2TONE_RESPONSE
+ u8 alert; // 1-16
+ } decs[4];
+ u8 unused04[4];
+ } _2tone_decode[15];
+ u8 unused05[16];
+
+ struct {
+ ul16 freqA;
+ ul16 freqB;
+ ul16 freqC;
+ ul16 freqD;
+ // unknown what those values mean, but they are
+ // derived from configured frequencies
+ ul16 derived_from_freqA; // 2304000/freqA
+ ul16 derived_from_freqB; // 2304000/freqB
+ ul16 derived_from_freqC; // 2304000/freqC
+ ul16 derived_from_freqD; // 2304000/freqD
+ }freqs[15];
+ u8 reset_time; // * 100 + 100ms - 100-8000ms
+} _2tone;
+
#seekto 0x3000;
struct {
u8 freq[8];
@@ -237,6 +360,34 @@ LIST_TXP = ["High", "Low"]
LIST_WIDE = ["Wide", "Narrow"]
STEPS = [2.5, 5.0, 6.25, 10.0, 12.5, 25.0]
LIST_STEP = [str(x) for x in STEPS]
+LIST_5TONE_STANDARDS = ["CCIR1", "CCIR2", "PCCIR", "ZVEI1", "ZVEI2", "ZVEI3",
+ "PZVEI", "DZVEI", "PDZVEI", "EEA", "EIA", "EURO",
+ "CCITT", "NATEL", "MODAT", "none"]
+LIST_5TONE_STANDARDS_without_none = ["CCIR1", "CCIR2", "PCCIR", "ZVEI1",
+ "ZVEI2", "ZVEI3",
+ "PZVEI", "DZVEI", "PDZVEI", "EEA", "EIA",
+ "EURO", "CCITT", "NATEL", "MODAT"]
+LIST_5TONE_STANDARD_PERIODS = ["20", "30", "40", "50", "60", "70", "80", "90",
+ "100", "110", "120", "130", "140", "150", "160",
+ "170", "180", "190", "200"]
+LIST_5TONE_DIGITS = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A",
+ "B", "C", "D", "E", "F"]
+LIST_5TONE_DELAY = ["%s ms" % x for x in range(0, 1010, 10)]
+LIST_5TONE_RESET = ["%s ms" % x for x in range(100, 8100, 100)]
+LIST_DTMF_SPEED = ["%s ms" % x for x in range(50, 2010, 10)]
+LIST_DTMF_DIGITS = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B",
+ "C", "D", "#", "*"]
+LIST_DTMF_VALUES = [0x0A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+ 0x0D, 0x0E, 0x0F, 0x00, 0x0C, 0x0B ]
+LIST_DTMF_SPECIAL_DIGITS = [ "*", "#", "A", "B", "C", "D"]
+LIST_DTMF_SPECIAL_VALUES = [ 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00]
+LIST_DTMF_DELAY = ["%s ms" % x for x in range(100, 4100, 100)]
+CHARSET_DTMF_DIGITS = "0123456789AaBbCcDd#*"
+LIST_2TONE_DEC = ["A-B", "A-C", "A-D",
+ "B-A", "B-C", "B-D",
+ "C-A", "C-B", "C-D",
+ "D-A", "D-B", "D-C"]
+LIST_2TONE_RESPONSE = ["None", "Alert", "Transpond", "Alert+Transpond"]
# This is a general serial timeout for all serial read functions.
# Practice has show that about 0.7 sec will be enough to cover all radios.
@@ -1613,7 +1764,772 @@ class BTech(chirp_common.CloneModeRadio, chirp_common.ExperimentalRadio):
fm_presets.append(fmfreq)
i = i + 1
+
+ # DTMF-Setting
+ dtmf_enc_settings = RadioSettingGroup ("dtmf_enc_settings",
+ "DTMF Encoding Settings")
+ dtmf_dec_settings = RadioSettingGroup ("dtmf_dec_settings",
+ "DTMF Decoding Settings")
+ top.append(dtmf_enc_settings)
+ top.append(dtmf_dec_settings)
+ txdisable = RadioSetting("dtmf_settings.txdisable",
+ "TX-Disable",
+ RadioSettingValueBoolean(
+ _mem.dtmf_settings.txdisable))
+ dtmf_enc_settings.append(txdisable)
+
+ rxdisable = RadioSetting("dtmf_settings.rxdisable",
+ "RX-Disable",
+ RadioSettingValueBoolean(
+ _mem.dtmf_settings.rxdisable))
+ dtmf_enc_settings.append(rxdisable)
+
+ dtmfspeed_on = RadioSetting(
+ "dtmf_settings.dtmfspeed_on",
+ "DTMF Speed (On Time)",
+ RadioSettingValueList(LIST_DTMF_SPEED,
+ LIST_DTMF_SPEED[
+ _mem.dtmf_settings.dtmfspeed_on]))
+ dtmf_enc_settings.append(dtmfspeed_on)
+
+ dtmfspeed_off = RadioSetting(
+ "dtmf_settings.dtmfspeed_off",
+ "DTMF Speed (Off Time)",
+ RadioSettingValueList(LIST_DTMF_SPEED,
+ LIST_DTMF_SPEED[
+ _mem.dtmf_settings.dtmfspeed_off]))
+ dtmf_enc_settings.append(dtmfspeed_off)
+
+ def memory2string(dmtf_mem):
+ dtmf_string = ""
+ for digit in dmtf_mem:
+ if digit != 255:
+ index = LIST_DTMF_VALUES.index(digit)
+ dtmf_string = dtmf_string + LIST_DTMF_DIGITS[index]
+ return dtmf_string
+
+ def apply_dmtf_frame(setting, obj):
+ LOG.debug("Setting DTMF-Code: " + str(setting.value) )
+ val_string = str(setting.value)
+ for i in range(0,16):
+ obj[i] = 255
+ i = 0
+ for current_char in val_string:
+ current_char = current_char.upper()
+ index = LIST_DTMF_DIGITS.index(current_char)
+ obj[i] = LIST_DTMF_VALUES[ index ]
+ i = i + 1
+
+ codes = self._memobj.dtmf_codes
+ i = 1
+ for dtmfcode in codes:
+ val = RadioSettingValueString(0, 16,
+ memory2string(dtmfcode.code),
+ False, CHARSET_DTMF_DIGITS)
+ line = RadioSetting("dtmf_code_" + str(i) + "_code",
+ "DMTF Code " + str(i), val)
+ line.set_apply_callback(apply_dmtf_frame, dtmfcode.code)
+ dtmf_enc_settings.append(line)
+ i = i + 1
+
+ line = RadioSetting("dtmf_settings.mastervice",
+ "Master and Vice ID",
+ RadioSettingValueBoolean(
+ _mem.dtmf_settings.mastervice))
+ dtmf_dec_settings.append(line)
+
+ val = RadioSettingValueString(0, 16,
+ memory2string(
+ _mem.dtmf_settings.masterid),
+ False, CHARSET_DTMF_DIGITS)
+ line = RadioSetting("dtmf_settings.masterid",
+ "Master Control ID ", val)
+ line.set_apply_callback(apply_dmtf_frame,
+ _mem.dtmf_settings.masterid)
+ dtmf_dec_settings.append(line)
+
+ line = RadioSetting("dtmf_settings.minspection",
+ "Master Inspection",
+ RadioSettingValueBoolean(
+ _mem.dtmf_settings.minspection))
+ dtmf_dec_settings.append(line)
+
+ line = RadioSetting("dtmf_settings.mmonitor",
+ "Master Monitor",
+ RadioSettingValueBoolean(
+ _mem.dtmf_settings.mmonitor))
+ dtmf_dec_settings.append(line)
+
+ line = RadioSetting("dtmf_settings.mstun",
+ "Master Stun",
+ RadioSettingValueBoolean(
+ _mem.dtmf_settings.mstun))
+ dtmf_dec_settings.append(line)
+
+ line = RadioSetting("dtmf_settings.mkill",
+ "Master Kill",
+ RadioSettingValueBoolean(
+ _mem.dtmf_settings.mkill))
+ dtmf_dec_settings.append(line)
+
+ line = RadioSetting("dtmf_settings.mrevive",
+ "Master Revive",
+ RadioSettingValueBoolean(
+ _mem.dtmf_settings.mrevive))
+ dtmf_dec_settings.append(line)
+
+ val = RadioSettingValueString(0, 16,
+ memory2string(
+ _mem.dtmf_settings.viceid),
+ False, CHARSET_DTMF_DIGITS)
+ line = RadioSetting("dtmf_settings.viceid",
+ "Vice Control ID ", val)
+ line.set_apply_callback(apply_dmtf_frame,
+ _mem.dtmf_settings.viceid)
+ dtmf_dec_settings.append(line)
+
+ line = RadioSetting("dtmf_settings.vinspection",
+ "Vice Inspection",
+ RadioSettingValueBoolean(
+ _mem.dtmf_settings.vinspection))
+ dtmf_dec_settings.append(line)
+
+ line = RadioSetting("dtmf_settings.vmonitor",
+ "Vice Monitor",
+ RadioSettingValueBoolean(
+ _mem.dtmf_settings.vmonitor))
+ dtmf_dec_settings.append(line)
+
+ line = RadioSetting("dtmf_settings.vstun",
+ "Vice Stun",
+ RadioSettingValueBoolean(
+ _mem.dtmf_settings.vstun))
+ dtmf_dec_settings.append(line)
+
+ line = RadioSetting("dtmf_settings.vkill",
+ "Vice Kill",
+ RadioSettingValueBoolean(
+ _mem.dtmf_settings.vkill))
+ dtmf_dec_settings.append(line)
+
+ line = RadioSetting("dtmf_settings.vrevive",
+ "Vice Revive",
+ RadioSettingValueBoolean(
+ _mem.dtmf_settings.vrevive))
+ dtmf_dec_settings.append(line)
+
+ val = RadioSettingValueString(0, 16,
+ memory2string(
+ _mem.dtmf_settings.inspection),
+ False, CHARSET_DTMF_DIGITS)
+ line = RadioSetting("dtmf_settings.inspection",
+ "Inspection", val)
+ line.set_apply_callback(apply_dmtf_frame,
+ _mem.dtmf_settings.inspection)
+ dtmf_dec_settings.append(line)
+
+ val = RadioSettingValueString(0, 16,
+ memory2string(
+ _mem.dtmf_settings.alarmcode),
+ False, CHARSET_DTMF_DIGITS)
+ line = RadioSetting("dtmf_settings.alarmcode",
+ "Alarm", val)
+ line.set_apply_callback(apply_dmtf_frame,
+ _mem.dtmf_settings.alarmcode)
+ dtmf_dec_settings.append(line)
+
+ val = RadioSettingValueString(0, 16,
+ memory2string(
+ _mem.dtmf_settings.kill),
+ False, CHARSET_DTMF_DIGITS)
+ line = RadioSetting("dtmf_settings.kill",
+ "Kill", val)
+ line.set_apply_callback(apply_dmtf_frame,
+ _mem.dtmf_settings.kill)
+ dtmf_dec_settings.append(line)
+
+ val = RadioSettingValueString(0, 16,
+ memory2string(
+ _mem.dtmf_settings.monitor),
+ False, CHARSET_DTMF_DIGITS)
+ line = RadioSetting("dtmf_settings.monitor",
+ "Monitor", val)
+ line.set_apply_callback(apply_dmtf_frame,
+ _mem.dtmf_settings.monitor)
+ dtmf_dec_settings.append(line)
+
+ val = RadioSettingValueString(0, 16,
+ memory2string(
+ _mem.dtmf_settings.stun),
+ False, CHARSET_DTMF_DIGITS)
+ line = RadioSetting("dtmf_settings.stun",
+ "Stun", val)
+ line.set_apply_callback(apply_dmtf_frame,
+ _mem.dtmf_settings.stun)
+ dtmf_dec_settings.append(line)
+
+ val = RadioSettingValueString(0, 16,
+ memory2string(
+ _mem.dtmf_settings.revive),
+ False, CHARSET_DTMF_DIGITS)
+ line = RadioSetting("dtmf_settings.revive",
+ "Revive", val)
+ line.set_apply_callback(apply_dmtf_frame,
+ _mem.dtmf_settings.revive)
+ dtmf_dec_settings.append(line)
+
+ def apply_dmtf_listvalue(setting, obj):
+ LOG.debug("Setting value: "+ str(setting.value) + " from list")
+ val = str(setting.value)
+ index = LIST_DTMF_SPECIAL_DIGITS.index(val)
+ val = LIST_DTMF_SPECIAL_VALUES[index]
+ obj.set_value(val)
+
+ idx = LIST_DTMF_SPECIAL_VALUES.index(_mem.dtmf_settings.groupcode)
+ line = RadioSetting(
+ "dtmf_settings.groupcode",
+ "Group Code",
+ RadioSettingValueList(LIST_DTMF_SPECIAL_DIGITS,
+ LIST_DTMF_SPECIAL_DIGITS[idx]))
+ line.set_apply_callback(apply_dmtf_listvalue,
+ _mem.dtmf_settings.groupcode)
+ dtmf_dec_settings.append(line)
+
+ idx = LIST_DTMF_SPECIAL_VALUES.index(_mem.dtmf_settings.spacecode)
+ line = RadioSetting(
+ "dtmf_settings.spacecode",
+ "Space Code",
+ RadioSettingValueList(LIST_DTMF_SPECIAL_DIGITS,
+ LIST_DTMF_SPECIAL_DIGITS[idx]))
+ line.set_apply_callback(apply_dmtf_listvalue,
+ _mem.dtmf_settings.spacecode)
+ dtmf_dec_settings.append(line)
+
+ line = RadioSetting(
+ "dtmf_settings.resettime",
+ "Reset time",
+ RadioSettingValueList(LIST_5TONE_RESET,
+ LIST_5TONE_RESET[
+ _mem.dtmf_settings.resettime]))
+ dtmf_dec_settings.append(line)
+
+ line = RadioSetting(
+ "dtmf_settings.delayproctime",
+ "Delay processing time",
+ RadioSettingValueList(LIST_DTMF_DELAY,
+ LIST_DTMF_DELAY[
+ _mem.dtmf_settings.delayproctime]))
+ dtmf_dec_settings.append(line)
+
+
+ # 5 Tone Settings
+ stds_5tone = RadioSettingGroup ("stds_5tone", "Standards")
+ codes_5tone = RadioSettingGroup ("codes_5tone", "Codes")
+
+ group_5tone = RadioSettingGroup ("group_5tone", "5 Tone Settings")
+ group_5tone.append(stds_5tone)
+ group_5tone.append(codes_5tone)
+
+ top.append(group_5tone)
+
+ def apply_list_value(setting, obj):
+ options = setting.value.get_options()
+ obj.set_value ( options.index(str(setting.value)) )
+
+ _5tone_standards = self._memobj._5tone_std_settings
+ i = 0
+ for standard in _5tone_standards:
+ std_5tone = RadioSettingGroup ("std_5tone_" + str(i),
+ LIST_5TONE_STANDARDS[i])
+ stds_5tone.append(std_5tone)
+
+ period = standard.period
+ if period == 255:
+ LOG.debug("Period for " + LIST_5TONE_STANDARDS[i] +
+ " is not yet configured. Setting to 70ms.")
+ period = 5
+
+ if period <= len( LIST_5TONE_STANDARD_PERIODS ):
+ line = RadioSetting(
+ "_5tone_std_settings_" + str(i) + "_period",
+ "Period (ms)", RadioSettingValueList
+ (LIST_5TONE_STANDARD_PERIODS,
+ LIST_5TONE_STANDARD_PERIODS[period]))
+ line.set_apply_callback(apply_list_value, standard.period)
+ std_5tone.append(line)
+ else:
+ LOG.debug("Invalid value for 5tone period! Disabling.")
+
+ group_tone = standard.group_tone
+ if group_tone == 255:
+ LOG.debug("Group-Tone for " + LIST_5TONE_STANDARDS[i] +
+ " is not yet configured. Setting to A.")
+ group_tone = 10
+
+ if group_tone <= len( LIST_5TONE_DIGITS ):
+ line = RadioSetting(
+ "_5tone_std_settings_" + str(i) + "_grouptone",
+ "Group Tone",
+ RadioSettingValueList(LIST_5TONE_DIGITS,
+ LIST_5TONE_DIGITS[
+ group_tone]))
+ line.set_apply_callback(apply_list_value,
+ standard.group_tone)
+ std_5tone.append(line)
+ else:
+ LOG.debug("Invalid value for 5tone digit! Disabling.")
+
+ repeat_tone = standard.repeat_tone
+ if repeat_tone == 255:
+ LOG.debug("Repeat-Tone for " + LIST_5TONE_STANDARDS[i] +
+ " is not yet configured. Setting to E.")
+ repeat_tone = 14
+
+ if repeat_tone <= len( LIST_5TONE_DIGITS ):
+ line = RadioSetting(
+ "_5tone_std_settings_" + str(i) + "_repttone",
+ "Repeat Tone",
+ RadioSettingValueList(LIST_5TONE_DIGITS,
+ LIST_5TONE_DIGITS[
+ repeat_tone]))
+ line.set_apply_callback(apply_list_value,
+ standard.repeat_tone)
+ std_5tone.append(line)
+ else:
+ LOG.debug("Invalid value for 5tone digit! Disabling.")
+ i = i + 1
+
+ def my_apply_5tonestdlist_value(setting, obj):
+ if LIST_5TONE_STANDARDS.index(str(setting.value)) == 15:
+ obj.set_value(0xFF)
+ else:
+ obj.set_value( LIST_5TONE_STANDARDS.
+ index(str(setting.value)) )
+
+ def apply_5tone_frame(setting, obj):
+ LOG.debug("Setting 5 Tone: " + str(setting.value) )
+ valstring = str(setting.value)
+ if len(valstring) == 0:
+ for i in range(0,5):
+ obj[i] = 255
+ else:
+ validFrame = True
+ for i in range(0,5):
+ currentChar = valstring[i].upper()
+ if currentChar in LIST_5TONE_DIGITS:
+ obj[i] = LIST_5TONE_DIGITS.index(currentChar)
+ else:
+ validFrame = False
+ LOG.debug("invalid char: " + str(currentChar))
+ if not validFrame:
+ LOG.debug("setting whole frame to FF" )
+ for i in range(0,5):
+ obj[i] = 255
+
+ def validate_5tone_frame(value):
+ if (len(str(value)) != 5) and (len(str(value)) != 0) :
+ msg = ("5 Tone must have 5 digits or 0 digits")
+ raise InvalidValueError(msg)
+ for digit in str(value):
+ if digit.upper() not in LIST_5TONE_DIGITS:
+ msg = (str(digit) + " is not a valid digit for 5tones")
+ raise InvalidValueError(msg)
+ return value
+
+ def frame2string(frame):
+ frameString = ""
+ for digit in frame:
+ if digit != 255:
+ frameString = frameString + LIST_5TONE_DIGITS[digit]
+ return frameString
+
+ _5tone_codes = self._memobj._5tone_codes
+ i = 1
+ for code in _5tone_codes:
+ code_5tone = RadioSettingGroup ("code_5tone_" + str(i),
+ "5 Tone code " + str(i))
+ codes_5tone.append(code_5tone)
+ if (code.standard == 255 ):
+ currentVal = 15
+ else:
+ currentVal = code.standard
+ line = RadioSetting("_5tone_code_" + str(i) + "_std",
+ " Standard",
+ RadioSettingValueList(LIST_5TONE_STANDARDS,
+ LIST_5TONE_STANDARDS[
+ currentVal]) )
+ line.set_apply_callback(my_apply_5tonestdlist_value,
+ code.standard)
+ code_5tone.append(line)
+
+ val = RadioSettingValueString(0, 6,
+ frame2string(code.frame1), False)
+ line = RadioSetting("_5tone_code_" + str(i) + "_frame1",
+ " Frame 1", val)
+ val.set_validate_callback(validate_5tone_frame)
+ line.set_apply_callback(apply_5tone_frame, code.frame1)
+ code_5tone.append(line)
+
+ val = RadioSettingValueString(0, 6,
+ frame2string(code.frame2), False)
+ line = RadioSetting("_5tone_code_" + str(i) + "_frame2",
+ " Frame 2", val)
+ val.set_validate_callback(validate_5tone_frame)
+ line.set_apply_callback(apply_5tone_frame, code.frame2)
+ code_5tone.append(line)
+
+ val = RadioSettingValueString(0, 6,
+ frame2string(code.frame3), False)
+ line = RadioSetting("_5tone_code_" + str(i) + "_frame3",
+ " Frame 3", val)
+ val.set_validate_callback(validate_5tone_frame)
+ line.set_apply_callback(apply_5tone_frame, code.frame3)
+ code_5tone.append(line)
+ i = i + 1
+
+ _5_tone_decode1 = RadioSetting(
+ "_5tone_settings._5tone_decode_call_frame1",
+ "5 Tone decode call Frame 1",
+ RadioSettingValueBoolean(
+ _mem._5tone_settings._5tone_decode_call_frame1))
+ group_5tone.append(_5_tone_decode1)
+
+ _5_tone_decode2 = RadioSetting(
+ "_5tone_settings._5tone_decode_call_frame2",
+ "5 Tone decode call Frame 2",
+ RadioSettingValueBoolean(
+ _mem._5tone_settings._5tone_decode_call_frame2))
+ group_5tone.append(_5_tone_decode2)
+
+ _5_tone_decode3 = RadioSetting(
+ "_5tone_settings._5tone_decode_call_frame3",
+ "5 Tone decode call Frame 3",
+ RadioSettingValueBoolean(
+ _mem._5tone_settings._5tone_decode_call_frame3))
+ group_5tone.append(_5_tone_decode3)
+
+ _5_tone_decode_disp1 = RadioSetting(
+ "_5tone_settings._5tone_decode_disp_frame1",
+ "5 Tone decode disp Frame 1",
+ RadioSettingValueBoolean(
+ _mem._5tone_settings._5tone_decode_disp_frame1))
+ group_5tone.append(_5_tone_decode_disp1)
+
+ _5_tone_decode_disp2 = RadioSetting(
+ "_5tone_settings._5tone_decode_disp_frame2",
+ "5 Tone decode disp Frame 2",
+ RadioSettingValueBoolean(
+ _mem._5tone_settings._5tone_decode_disp_frame2))
+ group_5tone.append(_5_tone_decode_disp2)
+
+ _5_tone_decode_disp3 = RadioSetting(
+ "_5tone_settings._5tone_decode_disp_frame3",
+ "5 Tone decode disp Frame 3",
+ RadioSettingValueBoolean(
+ _mem._5tone_settings._5tone_decode_disp_frame3))
+ group_5tone.append(_5_tone_decode_disp3)
+
+ decode_standard = _mem._5tone_settings.decode_standard
+ if decode_standard == 255:
+ decode_standard = 0
+ if decode_standard <= len (LIST_5TONE_STANDARDS_without_none) :
+ line = RadioSetting("_5tone_settings.decode_standard",
+ "5 Tone-decode Standard",
+ RadioSettingValueList(
+ LIST_5TONE_STANDARDS_without_none,
+ LIST_5TONE_STANDARDS_without_none[
+ decode_standard]))
+ group_5tone.append(line)
+ else:
+ LOG.debug("Invalid decode std...")
+ _5tone_delay1 = _mem._5tone_settings._5tone_delay1
+ if _5tone_delay1 == 255:
+ _5tone_delay1 = 20
+
+ if _5tone_delay1 <= len( LIST_5TONE_DELAY ):
+ list = RadioSettingValueList(LIST_5TONE_DELAY,
+ LIST_5TONE_DELAY[
+ _5tone_delay1])
+ line = RadioSetting("_5tone_settings._5tone_delay1",
+ "5 Tone Delay Frame 1", list)
+ group_5tone.append(line)
+ else:
+ LOG.debug("Invalid value for 5tone delay (frame1) ! Disabling.")
+
+ _5tone_delay2 = _mem._5tone_settings._5tone_delay2
+ if _5tone_delay2 == 255:
+ _5tone_delay2 = 20
+ LOG.debug("5 Tone delay unconfigured! Resetting to 200ms.")
+
+ if _5tone_delay2 <= len( LIST_5TONE_DELAY ):
+ list = RadioSettingValueList(LIST_5TONE_DELAY,
+ LIST_5TONE_DELAY[
+ _5tone_delay2])
+ line = RadioSetting("_5tone_settings._5tone_delay2",
+ "5 Tone Delay Frame 2", list)
+ group_5tone.append(line)
+ else:
+ LOG.debug("Invalid value for 5tone delay (frame2)! Disabling.")
+
+ _5tone_delay3 = _mem._5tone_settings._5tone_delay3
+ if _5tone_delay3 == 255:
+ _5tone_delay3 = 20
+ LOG.debug("5 Tone delay unconfigured! Resetting to 200ms.")
+
+ if _5tone_delay3 <= len( LIST_5TONE_DELAY ):
+ list = RadioSettingValueList(LIST_5TONE_DELAY,
+ LIST_5TONE_DELAY[
+ _5tone_delay3])
+ line = RadioSetting("_5tone_settings._5tone_delay3",
+ "5 Tone Delay Frame 3", list )
+ group_5tone.append(line)
+ else:
+ LOG.debug("Invalid value for 5tone delay (frame3)! Disabling.")
+
+ ext_length = _mem._5tone_settings._5tone_first_digit_ext_length
+ if ext_length == 255:
+ ext_length = 0
+ LOG.debug("1st Tone ext lenght unconfigured! Resetting to 0")
+
+ if ext_length <= len(
+ LIST_5TONE_DELAY ):
+ list = RadioSettingValueList(
+ LIST_5TONE_DELAY,
+ LIST_5TONE_DELAY[
+ ext_length])
+ line = RadioSetting(
+ "_5tone_settings._5tone_first_digit_ext_length",
+ "First digit extend length", list)
+ group_5tone.append(line)
+ else:
+ LOG.debug("Invalid value for 5tone ext length! Disabling.")
+
+ decode_reset_time = _mem._5tone_settings.decode_reset_time
+ if decode_reset_time == 255:
+ decode_reset_time = 59
+ LOG.debug("Decode reset time unconfigured. resetting.")
+ if decode_reset_time <= len(LIST_5TONE_RESET):
+ list = RadioSettingValueList(
+ LIST_5TONE_RESET,
+ LIST_5TONE_RESET[
+ decode_reset_time])
+ line = RadioSetting("_5tone_settings.decode_reset_time",
+ "Decode reset time", list)
+ group_5tone.append(line)
+ else:
+ LOG.debug("Invalid value decode reset time! Disabling.")
+
+ # 2 Tone
+ encode_2tone = RadioSettingGroup ("encode_2tone", "2 Tone Encode")
+ decode_2tone = RadioSettingGroup ("decode_2tone", "2 Code Decode")
+
+ top.append(encode_2tone)
+ top.append(decode_2tone)
+
+ duration_1st_tone = self._memobj._2tone.duration_1st_tone
+ if duration_1st_tone == 255:
+ LOG.debug("Duration of first 2 Tone digit is not yet " +
+ "configured. Setting to 600ms")
+ duration_1st_tone = 60
+
+ if duration_1st_tone <= len( LIST_5TONE_DELAY ):
+ line = RadioSetting("_2tone.duration_1st_tone",
+ "Duration 1st Tone",
+ RadioSettingValueList(LIST_5TONE_DELAY,
+ LIST_5TONE_DELAY[
+ duration_1st_tone]))
+ encode_2tone.append(line)
+
+ duration_2nd_tone = self._memobj._2tone.duration_2nd_tone
+ if duration_2nd_tone == 255:
+ LOG.debug("Duration of second 2 Tone digit is not yet " +
+ "configured. Setting to 600ms")
+ duration_2nd_tone = 60
+
+ if duration_2nd_tone <= len( LIST_5TONE_DELAY ):
+ line = RadioSetting("_2tone.duration_2nd_tone",
+ "Duration 2nd Tone",
+ RadioSettingValueList(LIST_5TONE_DELAY,
+ LIST_5TONE_DELAY[
+ duration_2nd_tone]))
+ encode_2tone.append(line)
+
+ duration_gap = self._memobj._2tone.duration_gap
+ if duration_gap == 255:
+ LOG.debug("Duration of gap is not yet " +
+ "configured. Setting to 300ms")
+ duration_gap = 30
+
+ if duration_gap <= len( LIST_5TONE_DELAY ):
+ line = RadioSetting("_2tone.duration_gap", "Duration of gap",
+ RadioSettingValueList(LIST_5TONE_DELAY,
+ LIST_5TONE_DELAY[
+ duration_gap]))
+ encode_2tone.append(line)
+
+ def _2tone_validate(value):
+ if value == 0:
+ return 65535
+ if value == 65535:
+ return value
+ if not (300 <= value and value <= 3000):
+ msg = ("2 Tone Frequency: Must be between 300 and 3000 Hz")
+ raise InvalidValueError(msg)
+ return value
+
+ def apply_2tone_freq(setting, obj):
+ val = int(setting.value)
+ if (val == 0) or (val == 65535):
+ obj.set_value(65535)
+ else:
+ obj.set_value(val)
+
+ i = 1
+ for code in self._memobj._2tone._2tone_encode:
+ code_2tone = RadioSettingGroup ("code_2tone_" + str(i),
+ "Encode Code " + str(i))
+ encode_2tone.append(code_2tone)
+
+ tmp = code.freq1
+ if tmp == 65535:
+ tmp = 0
+ val1 = RadioSettingValueInteger(0, 65535, tmp)
+ freq1 = RadioSetting("2tone_code_"+ str(i) + "_freq1",
+ "Frequency 1", val1)
+ val1.set_validate_callback(_2tone_validate)
+ freq1.set_apply_callback(apply_2tone_freq, code.freq1)
+ code_2tone.append(freq1)
+
+ tmp = code.freq2
+ if tmp == 65535:
+ tmp = 0
+ val2 = RadioSettingValueInteger(0, 65535, tmp)
+ freq2 = RadioSetting("2tone_code_"+ str(i) + "_freq2",
+ "Frequency 2", val2)
+ val2.set_validate_callback(_2tone_validate)
+ freq2.set_apply_callback(apply_2tone_freq, code.freq2)
+ code_2tone.append(freq2)
+
+ i = i + 1
+
+ decode_reset_time = _mem._2tone.reset_time
+ if decode_reset_time == 255:
+ decode_reset_time = 59
+ LOG.debug("Decode reset time unconfigured. resetting.")
+ if decode_reset_time <= len(LIST_5TONE_RESET):
+ list = RadioSettingValueList(
+ LIST_5TONE_RESET,
+ LIST_5TONE_RESET[
+ decode_reset_time])
+ line = RadioSetting("_2tone.reset_time",
+ "Decode reset time", list)
+ decode_2tone.append(line)
+ else:
+ LOG.debug("Invalid value decode reset time! Disabling.")
+
+ def apply_2tone_freq_pair(setting, obj):
+ val = int(setting.value)
+ derived_val = 65535
+ frqname = str(setting._name[-5:])
+ derivedname = "derived_from_" + frqname
+
+ if (val == 0):
+ val = 65535
+ derived_val = 65535
+ else:
+ derived_val = int(round(2304000.0/val))
+
+ obj[frqname].set_value( val )
+ obj[derivedname].set_value( derived_val )
+
+ LOG.debug("Apply " + frqname + ": " + str(val) + " | "
+ + derivedname + ": " + str(derived_val))
+
+ i = 1
+ for decode_code in self._memobj._2tone._2tone_decode:
+ _2tone_dec_code = RadioSettingGroup ("code_2tone_" + str(i),
+ "Decode Code " + str(i))
+ decode_2tone.append(_2tone_dec_code)
+
+ j = 1
+ for dec in decode_code.decs:
+ val = dec.dec
+ if val == 255:
+ LOG.debug("Dec for Code " + str(i) + " Dec " + str(j) +
+ " is not yet configured. Setting to 0.")
+ val = 0
+
+ if val <= len( LIST_2TONE_DEC ):
+ line = RadioSetting(
+ "_2tone_dec_settings_" + str(i) + "_dec_" + str(j),
+ "Dec " + str(j), RadioSettingValueList
+ (LIST_2TONE_DEC,
+ LIST_2TONE_DEC[val]))
+ line.set_apply_callback(apply_list_value, dec.dec)
+ _2tone_dec_code.append(line)
+ else:
+ LOG.debug("Invalid value for 2tone dec! Disabling.")
+
+ val = dec.response
+ if val == 255:
+ LOG.debug("Response for Code " + str(i) + " Dec " + str(j)+
+ " is not yet configured. Setting to 0.")
+ val = 0
+
+ if val <= len( LIST_2TONE_RESPONSE ):
+ line = RadioSetting(
+ "_2tone_dec_settings_" + str(i) + "_resp_" + str(j),
+ "Response " + str(j), RadioSettingValueList
+ (LIST_2TONE_RESPONSE,
+ LIST_2TONE_RESPONSE[val]))
+ line.set_apply_callback(apply_list_value, dec.response)
+ _2tone_dec_code.append(line)
+ else:
+ LOG.debug("Invalid value for 2tone response! Disabling.")
+
+ val = dec.alert
+ if val == 255:
+ LOG.debug("Alert for Code " + str(i) + " Dec " + str(j) +
+ " is not yet configured. Setting to 0.")
+ val = 0
+
+ if val <= len( PTTIDCODE_LIST ):
+ line = RadioSetting(
+ "_2tone_dec_settings_" + str(i) + "_alert_" + str(j),
+ "Alert " + str(j), RadioSettingValueList
+ (PTTIDCODE_LIST,
+ PTTIDCODE_LIST[val]))
+ line.set_apply_callback(apply_list_value, dec.alert)
+ _2tone_dec_code.append(line)
+ else:
+ LOG.debug("Invalid value for 2tone alert! Disabling.")
+ j = j + 1
+
+ freq = self._memobj._2tone.freqs[i-1]
+ for char in ['A', 'B', 'C', 'D']:
+ setting_name = "freq" + str(char)
+
+ tmp = freq[setting_name]
+ if tmp == 65535:
+ tmp = 0
+ if tmp != 0:
+ expected = int(round(2304000.0/tmp))
+ from_mem = freq["derived_from_" + setting_name]
+ if expected != from_mem:
+ LOG.error("Expected " + str(expected) +
+ " but read " + str(from_mem ) +
+ ". Disabling 2Tone Decode Freqs!")
+ break
+ val = RadioSettingValueInteger(0, 65535, tmp)
+ frq = RadioSetting("2tone_dec_"+ str(i) + "_freq" + str(char),
+ ("Decode Frequency " +str(char)), val)
+ val.set_validate_callback(_2tone_validate)
+ frq.set_apply_callback(apply_2tone_freq_pair, freq)
+ _2tone_dec_code.append(frq)
+
+ i = i + 1
+
return top
def set_settings(self, settings):
diff --git a/chirp/drivers/ft2900.py b/chirp/drivers/ft2900.py
index 7175733..a7ad33d 100644
--- a/chirp/drivers/ft2900.py
+++ b/chirp/drivers/ft2900.py
@@ -494,6 +494,7 @@ class FT2900BankModel(chirp_common.BankModel):
@directory.register
class FT2900Radio(YaesuCloneModeRadio):
+
"""Yaesu FT-2900"""
VENDOR = "Yaesu"
MODEL = "FT-2900R/1900R"
@@ -778,7 +779,8 @@ class FT2900Radio(YaesuCloneModeRadio):
# 7 BELL
opts = ["Off", "1", "3", "5", "8", "Continuous"]
ctcss.append(RadioSetting("bell", "Bell Repetitions",
- RadioSettingValueList(opts, opts[_settings.bell])))
+ RadioSettingValueList(opts, opts[
+ _settings.bell])))
# 8 BNK.LNK
for i in range(0, 8):
@@ -802,7 +804,8 @@ class FT2900Radio(YaesuCloneModeRadio):
# 11 CW.ID
opts = ["Off", "On"]
arts.append(RadioSetting("cw_id", "CW ID Enable",
- RadioSettingValueList(opts, opts[_settings.cw_id])))
+ RadioSettingValueList(opts, opts[
+ _settings.cw_id])))
cw_id_text = ""
for i in _settings.cw_id_string:
@@ -832,14 +835,16 @@ class FT2900Radio(YaesuCloneModeRadio):
"10WPM", "11WPM", "12WPM", "13WPM", "15WPM", "17WPM",
"20WPM", "24WPM", "30WPM", "40WPM"]
misc.append(RadioSetting("cw_trng", "CW Training",
- RadioSettingValueList(opts, opts[_settings.cw_trng])))
+ RadioSettingValueList(opts, opts[
+ _settings.cw_trng])))
# todo: make the setting of the units here affect the display
# of the speed. Not critical, but would be slick.
opts = ["CPM", "WPM"]
misc.append(RadioSetting("cw_trng_units", "CW Training Units",
RadioSettingValueList(opts,
- opts[_settings.cw_trng_units])))
+ opts[_settings.
+ cw_trng_units])))
# 13 DC VLT - a read-only status, so nothing to do here
@@ -920,7 +925,8 @@ class FT2900Radio(YaesuCloneModeRadio):
# 22 INT.CD
opts = ["DTMF %X" % (x) for x in range(0, 16)]
wires.append(RadioSetting("int_cd", "Access Number for WiRES(TM)",
- RadioSettingValueList(opts, opts[_settings.int_cd])))
+ RadioSettingValueList(opts, opts[
+ _settings.int_cd])))
# 23 ING MD
opts = ["Sister Radio Group", "Friends Radio Group"]
@@ -1103,24 +1109,28 @@ class FT2900Radio(YaesuCloneModeRadio):
# 41 RESUME
opts = ["3 Sec", "5 Sec", "10 Sec", "Busy", "Hold"]
scan.append(RadioSetting("resume", "Scan Resume Mode",
- RadioSettingValueList(opts, opts[_settings.resume])))
+ RadioSettingValueList(opts, opts[
+ _settings.resume])))
# 42 RF.SQL
opts = ["Off"] + ["S-%d" % (x) for x in range(1, 10)]
misc.append(RadioSetting("rf_sql", "RF Squelch Threshold",
- RadioSettingValueList(opts, opts[_settings.rf_sql])))
+ RadioSettingValueList(opts, opts[
+ _settings.rf_sql])))
# 43 RPT - per channel attribute, nothing to do here
# 44 RVRT
opts = ["Off", "On"]
misc.append(RadioSetting("revert", "Priority Revert",
- RadioSettingValueList(opts, opts[_settings.revert])))
+ RadioSettingValueList(opts, opts[
+ _settings.revert])))
# 45 S.SRCH
opts = ["Single", "Continuous"]
misc.append(RadioSetting("s_search", "Smart Search Sweep Mode",
- RadioSettingValueList(opts, opts[_settings.s_search])))
+ RadioSettingValueList(opts, opts[
+ _settings.s_search])))
# 46 SHIFT - per channel setting, nothing to do here
@@ -1166,12 +1176,14 @@ class FT2900Radio(YaesuCloneModeRadio):
# 57 WX.ALT
opts = ["Off", "On"]
misc.append(RadioSetting("wx_alert", "Weather Alert Scan",
- RadioSettingValueList(opts, opts[_settings.wx_alert])))
+ RadioSettingValueList(opts, opts[
+ _settings.wx_alert])))
# 58 WX.VOL
opts = ["Normal", "Maximum"]
misc.append(RadioSetting("wx_vol_max", "Weather Alert Volume",
- RadioSettingValueList(opts, opts[_settings.wx_vol_max])))
+ RadioSettingValueList(opts, opts[
+ _settings.wx_vol_max])))
# 59 W/N DV - this is a per-channel attribute, nothing to do here
@@ -1235,8 +1247,9 @@ class FT2900Radio(YaesuCloneModeRadio):
# to the R (USA) version, except for the model number and ID Block. We
# create and register a class for it, with only the needed overrides
# NOTE: Disabled until detection is fixed
-#@directory.register
+# @directory.register
class FT2900ERadio(FT2900Radio):
+
"""Yaesu FT-2900E"""
MODEL = "FT-2900E/1900E"
VARIANT = "E"
diff --git a/chirp/drivers/ft60.py b/chirp/drivers/ft60.py
index 39c8f44..3c00d84 100644
--- a/chirp/drivers/ft60.py
+++ b/chirp/drivers/ft60.py
@@ -340,6 +340,7 @@ class FT60BankModel(chirp_common.BankModel):
@directory.register
class FT60Radio(yaesu_clone.YaesuCloneModeRadio):
+
"""Yaesu FT-60"""
BAUD_RATE = 9600
VENDOR = "Yaesu"
@@ -487,27 +488,32 @@ class FT60Radio(yaesu_clone.YaesuCloneModeRadio):
# BELL
opts = ["OFF", "1T", "3T", "5T", "8T", "CONT"]
ctcss.append(RadioSetting("bell", "Bell Repetitions",
- RadioSettingValueList(opts, opts[_settings.bell])))
+ RadioSettingValueList(opts, opts[
+ _settings.bell])))
# BSY.LED
opts = ["ON", "OFF"]
misc.append(RadioSetting("bsy_led", "Busy LED",
- RadioSettingValueList(opts, opts[_settings.bsy_led])))
+ RadioSettingValueList(opts, opts[
+ _settings.bsy_led])))
# DCS.NR
opts = ["TR/X N", "RX R", "TX R", "T/RX R"]
ctcss.append(RadioSetting("dcs_nr", "\"Inverted\" DCS Code Decoding",
- RadioSettingValueList(opts, opts[_settings.dcs_nr])))
+ RadioSettingValueList(opts, opts[
+ _settings.dcs_nr])))
# DT.DLY
opts = ["50 MS", "100 MS", "250 MS", "450 MS", "750 MS", "1000 MS"]
ctcss.append(RadioSetting("dt_dly", "DTMF Autodialer Delay Time",
- RadioSettingValueList(opts, opts[_settings.dt_dly])))
+ RadioSettingValueList(opts, opts[
+ _settings.dt_dly])))
# DT.SPD
opts = ["50 MS", "100 MS"]
ctcss.append(RadioSetting("dt_spd", "DTMF Autodialer Sending Speed",
- RadioSettingValueList(opts, opts[_settings.dt_spd])))
+ RadioSettingValueList(opts, opts[
+ _settings.dt_spd])))
# DT.WRT
for i in range(0, 9):
@@ -535,7 +541,8 @@ class FT60Radio(yaesu_clone.YaesuCloneModeRadio):
# EDG.BEP
opts = ["OFF", "ON"]
misc.append(RadioSetting("edg_bep", "Band Edge Beeper",
- RadioSettingValueList(opts, opts[_settings.edg_bep])))
+ RadioSettingValueList(opts, opts[
+ _settings.edg_bep])))
# I.NET
opts = ["OFF", "COD", "MEM"]
@@ -553,7 +560,8 @@ class FT60Radio(yaesu_clone.YaesuCloneModeRadio):
"CODE 5", "CODE 6", "CODE 7", "CODE 8", "CODE 9",
"CODE A", "CODE B", "CODE C", "CODE D", "CODE E", "CODE F"]
wires.append(RadioSetting("int_cd", "Access Number for WiRES(TM)",
- RadioSettingValueList(opts, opts[_settings.int_cd])))
+ RadioSettingValueList(opts, opts[
+ _settings.int_cd])))
# INT.MR
opts = ["d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9"]
@@ -564,7 +572,8 @@ class FT60Radio(yaesu_clone.YaesuCloneModeRadio):
# LAMP
opts = ["KEY", "5SEC", "TOGGLE"]
switch.append(RadioSetting("lamp", "Lamp Mode",
- RadioSettingValueList(opts, opts[_settings.lamp])))
+ RadioSettingValueList(opts, opts[
+ _settings.lamp])))
# LOCK
opts = ["LK KEY", "LKDIAL", "LK K+D", "LK PTT",
@@ -581,33 +590,39 @@ class FT60Radio(yaesu_clone.YaesuCloneModeRadio):
# M/T-CL
opts = ["MONI", "T-CALL"]
switch.append(RadioSetting("mt_cl", "MONI Switch Function",
- RadioSettingValueList(opts, opts[_settings.mt_cl])))
+ RadioSettingValueList(opts, opts[
+ _settings.mt_cl])))
# PAG.ABK
opts = ["OFF", "ON"]
eai.append(RadioSetting("pag_abk", "Paging Answer Back",
- RadioSettingValueList(opts, opts[_settings.pag_abk])))
+ RadioSettingValueList(opts, opts[
+ _settings.pag_abk])))
# RESUME
opts = ["TIME", "HOLD", "BUSY"]
scan.append(RadioSetting("resume", "Scan Resume Mode",
- RadioSettingValueList(opts, opts[_settings.resume])))
+ RadioSettingValueList(opts, opts[
+ _settings.resume])))
# REV/HM
opts = ["REV", "HOME"]
switch.append(RadioSetting("rev_hm", "HM/RV Key Function",
- RadioSettingValueList(opts, opts[_settings.rev_hm])))
+ RadioSettingValueList(opts, opts[
+ _settings.rev_hm])))
# RF.SQL
opts = ["OFF", "S-1", "S-2", "S-3", "S-4", "S-5", "S-6",
"S-7", "S-8", "S-FULL"]
misc.append(RadioSetting("rf_sql", "RF Squelch Threshold",
- RadioSettingValueList(opts, opts[_settings.rf_sql])))
+ RadioSettingValueList(opts, opts[
+ _settings.rf_sql])))
# PRI.RVT
opts = ["OFF", "ON"]
scan.append(RadioSetting("pri_rvt", "Priority Revert",
- RadioSettingValueList(opts, opts[_settings.pri_rvt])))
+ RadioSettingValueList(opts, opts[
+ _settings.pri_rvt])))
# RXSAVE
opts = ["OFF", "200 MS", "300 MS", "500 MS", "1 S", "2 S"]
@@ -618,7 +633,8 @@ class FT60Radio(yaesu_clone.YaesuCloneModeRadio):
# S.SRCH
opts = ["SINGLE", "CONT"]
misc.append(RadioSetting("ssrch", "Smart Search Sweep Mode",
- RadioSettingValueList(opts, opts[_settings.ssrch])))
+ RadioSettingValueList(opts, opts[
+ _settings.ssrch])))
# SCN.MD
opts = ["MEM", "ONLY"]
@@ -629,32 +645,38 @@ class FT60Radio(yaesu_clone.YaesuCloneModeRadio):
# SCN.LMP
opts = ["OFF", "ON"]
scan.append(RadioSetting("scn_lmp", "Scan Lamp",
- RadioSettingValueList(opts, opts[_settings.scn_lmp])))
+ RadioSettingValueList(opts, opts[
+ _settings.scn_lmp])))
# TOT
opts = ["OFF"] + ["%dMIN" % (x) for x in range(1, 30 + 1)]
misc.append(RadioSetting("tot", "Timeout Timer",
- RadioSettingValueList(opts, opts[_settings.tot])))
+ RadioSettingValueList(opts, opts[
+ _settings.tot])))
# TX.LED
opts = ["ON", "OFF"]
misc.append(RadioSetting("tx_led", "TX LED",
- RadioSettingValueList(opts, opts[_settings.tx_led])))
+ RadioSettingValueList(opts, opts[
+ _settings.tx_led])))
# TXSAVE
opts = ["OFF", "ON"]
power.append(RadioSetting("txsave", "Transmitter Battery Saver",
- RadioSettingValueList(opts, opts[_settings.txsave])))
+ RadioSettingValueList(opts, opts[
+ _settings.txsave])))
# VFO.BND
opts = ["BAND", "ALL"]
misc.append(RadioSetting("vfo_bnd", "VFO Band Edge Limiting",
- RadioSettingValueList(opts, opts[_settings.vfo_bnd])))
+ RadioSettingValueList(opts, opts[
+ _settings.vfo_bnd])))
# WX.ALT
opts = ["OFF", "ON"]
scan.append(RadioSetting("wx_alt", "Weather Alert Scan",
- RadioSettingValueList(opts, opts[_settings.wx_alt])))
+ RadioSettingValueList(opts, opts[
+ _settings.wx_alt])))
# MBS
for i in range(0, 10):
diff --git a/chirp/drivers/ft817.py b/chirp/drivers/ft817.py
index 28cd2a2..f34169f 100644
--- a/chirp/drivers/ft817.py
+++ b/chirp/drivers/ft817.py
@@ -33,6 +33,7 @@ CMD_ACK = 0x06
@directory.register
class FT817Radio(yaesu_clone.YaesuCloneModeRadio):
+
"""Yaesu FT-817"""
BAUD_RATE = 9600
MODEL = "FT-817"
@@ -1007,7 +1008,8 @@ class FT817Radio(yaesu_clone.YaesuCloneModeRadio):
antenna.append(rs)
st = RadioSettingValueString(0, 7, ''.join([self._CALLSIGN_CHARSET[x]
- for x in self._memobj.callsign]))
+ for x in self._memobj.
+ callsign]))
st.set_charset(self._CALLSIGN_CHARSET)
rs = RadioSetting("callsign", "Callsign", st)
cw.append(rs)
@@ -1084,7 +1086,8 @@ class FT817Radio(yaesu_clone.YaesuCloneModeRadio):
setting = element.get_name()
try:
LOG.debug("Setting %s(%s) <= %s" % (setting,
- getattr(obj, setting), element.value))
+ getattr(obj, setting),
+ element.value))
except AttributeError:
LOG.debug("Setting %s <= %s" % (setting, element.value))
if setting == "contrast":
@@ -1102,6 +1105,7 @@ class FT817Radio(yaesu_clone.YaesuCloneModeRadio):
@directory.register
class FT817NDRadio(FT817Radio):
+
"""Yaesu FT-817ND"""
MODEL = "FT-817ND"
@@ -1113,6 +1117,7 @@ class FT817NDRadio(FT817Radio):
@directory.register
class FT817NDUSRadio(FT817Radio):
+
"""Yaesu FT-817ND (US version)"""
# seems that radios configured for 5MHz operations send one paket
# more than others so we have to distinguish sub models
diff --git a/chirp/drivers/kguv8d.py b/chirp/drivers/kguv8d.py
index a119c86..bf92856 100644
--- a/chirp/drivers/kguv8d.py
+++ b/chirp/drivers/kguv8d.py
@@ -276,6 +276,7 @@ _MEM_FORMAT = """
@directory.register
class KGUV8DRadio(chirp_common.CloneModeRadio,
chirp_common.ExperimentalRadio):
+
"""Wouxun KG-UV8D"""
VENDOR = "Wouxun"
MODEL = "KG-UV8D"
@@ -341,7 +342,7 @@ class KGUV8DRadio(chirp_common.CloneModeRadio,
# 31:34 VHF rx upper limit
# 35:38 VHF tx lower limit
# 39:42 VHF tx upper limit
-##
+#
@classmethod
def match_model(cls, filedata, filename):
return cls._file_ident in filedata[0x400:0x408]
@@ -475,7 +476,7 @@ class KGUV8DRadio(chirp_common.CloneModeRadio,
rf.valid_modes = ["FM", "NFM"]
rf.valid_power_levels = self.POWER_LEVELS
rf.valid_name_length = 8
- rf.valid_duplexes = ["", "+", "-", "split"]
+ rf.valid_duplexes = ["", "-", "+", "split", "off"]
rf.valid_bands = [(134000000, 175000000), # supports 2m
(400000000, 520000000)] # supports 70cm
rf.valid_characters = chirp_common.CHARSET_ASCII
@@ -554,7 +555,11 @@ class KGUV8DRadio(chirp_common.CloneModeRadio,
mem.freq = int(_mem.rxfreq) * 10
- if int(_mem.rxfreq) == int(_mem.txfreq):
+ 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
elif abs(int(_mem.rxfreq) * 10 - int(_mem.txfreq) * 10) > 70000000:
@@ -629,7 +634,9 @@ class KGUV8DRadio(chirp_common.CloneModeRadio,
return
_mem.rxfreq = int(mem.freq / 10)
- if mem.duplex == "split":
+ if mem.duplex == "off":
+ _mem.txfreq = 0xFFFFFFFF
+ elif mem.duplex == "split":
_mem.txfreq = int(mem.offset / 10)
elif mem.duplex == "off":
for i in range(0, 4):
@@ -689,7 +696,8 @@ class KGUV8DRadio(chirp_common.CloneModeRadio,
cfg_grp.append(rs)
rs = RadioSetting("language", "Language",
RadioSettingValueList(LANGUAGE_LIST,
- LANGUAGE_LIST[_settings.language]))
+ LANGUAGE_LIST[_settings.
+ language]))
cfg_grp.append(rs)
rs = RadioSetting("timeout", "Timeout Timer",
RadioSettingValueInteger(15, 900,
@@ -718,11 +726,13 @@ class KGUV8DRadio(chirp_common.CloneModeRadio,
cfg_grp.append(rs)
rs = RadioSetting("backlight", "Backlight",
RadioSettingValueList(BACKLIGHT_LIST,
- BACKLIGHT_LIST[_settings.backlight]))
+ BACKLIGHT_LIST[_settings.
+ backlight]))
cfg_grp.append(rs)
rs = RadioSetting("dtmf_st", "DTMF Sidetone",
RadioSettingValueList(DTMFST_LIST,
- DTMFST_LIST[_settings.dtmf_st]))
+ DTMFST_LIST[_settings.
+ dtmf_st]))
cfg_grp.append(rs)
rs = RadioSetting("ani-id_sw", "ANI-ID Switch",
RadioSettingValueBoolean(_settings.ani_sw))
@@ -737,7 +747,8 @@ class KGUV8DRadio(chirp_common.CloneModeRadio,
cfg_grp.append(rs)
rs = RadioSetting("scan_rev", "Scan Mode",
RadioSettingValueList(SCANMODE_LIST,
- SCANMODE_LIST[_settings.scan_rev]))
+ SCANMODE_LIST[_settings.
+ scan_rev]))
cfg_grp.append(rs)
rs = RadioSetting("vox", "VOX",
RadioSettingValueList(LIST_10,
@@ -751,11 +762,13 @@ class KGUV8DRadio(chirp_common.CloneModeRadio,
cfg_grp.append(rs)
rs = RadioSetting("rpt_mode", "Radio Mode",
RadioSettingValueList(RPTMODE_LIST,
- RPTMODE_LIST[_settings.rpt_mode]))
+ RPTMODE_LIST[_settings.
+ rpt_mode]))
cfg_grp.append(rs)
rs = RadioSetting("rpt_set", "Repeater Setting",
RadioSettingValueList(RPTSET_LIST,
- RPTSET_LIST[_settings.rpt_set]))
+ RPTSET_LIST[_settings.
+ rpt_set]))
cfg_grp.append(rs)
rs = RadioSetting("rpt_spk", "Repeater Mode Speaker",
RadioSettingValueBoolean(_settings.rpt_spk))
@@ -765,11 +778,13 @@ class KGUV8DRadio(chirp_common.CloneModeRadio,
cfg_grp.append(rs)
rs = RadioSetting("dtmf_tx_time", "DTMF Tx Duration",
RadioSettingValueList(DTMF_TIMES,
- DTMF_TIMES[_settings.dtmf_tx_time]))
+ DTMF_TIMES[_settings.
+ dtmf_tx_time]))
cfg_grp.append(rs)
rs = RadioSetting("dtmf_interval", "DTMF Interval",
RadioSettingValueList(DTMF_TIMES,
- DTMF_TIMES[_settings.dtmf_interval]))
+ DTMF_TIMES[_settings.
+ dtmf_interval]))
cfg_grp.append(rs)
rs = RadioSetting("alert", "Alert Tone",
RadioSettingValueList(ALERTS_LIST,
@@ -780,7 +795,8 @@ class KGUV8DRadio(chirp_common.CloneModeRadio,
cfg_grp.append(rs)
rs = RadioSetting("rpt_hold", "Repeater Hold Time",
RadioSettingValueList(HOLD_TIMES,
- HOLD_TIMES[_settings.rpt_hold]))
+ HOLD_TIMES[_settings.
+ rpt_hold]))
cfg_grp.append(rs)
rs = RadioSetting("scan_det", "Scan DET",
RadioSettingValueBoolean(_settings.scan_det))
@@ -791,7 +807,8 @@ class KGUV8DRadio(chirp_common.CloneModeRadio,
cfg_grp.append(rs)
rs = RadioSetting("smuteset", "SubFreq Mute",
RadioSettingValueList(SMUTESET_LIST,
- SMUTESET_LIST[_settings.smuteset]))
+ SMUTESET_LIST[_settings.
+ smuteset]))
cfg_grp.append(rs)
_pwd = "".join(map(chr, _settings.mode_sw_pwd))
val = RadioSettingValueString(0, 6, _pwd)
@@ -808,7 +825,8 @@ class KGUV8DRadio(chirp_common.CloneModeRadio,
#
rs = RadioSetting("vfoa_mode", "VFO A Workmode",
RadioSettingValueList(WORKMODE_LIST,
- WORKMODE_LIST[_settings.workmode_a]))
+ WORKMODE_LIST[_settings.
+ workmode_a]))
vfoa_grp.append(rs)
rs = RadioSetting("vfoa_chan", "VFO A Channel",
RadioSettingValueInteger(1, 999, _settings.work_cha))
diff --git a/chirp/drivers/kyd.py b/chirp/drivers/kyd.py
index 87c46cc..01ec7b3 100644
--- a/chirp/drivers/kyd.py
+++ b/chirp/drivers/kyd.py
@@ -63,7 +63,6 @@ u8 skipflags[2]; // SCAN_ADD
"""
CMD_ACK = "\x06"
-BLOCK_SIZE = 0x08
NC630A_POWER_LEVELS = [chirp_common.PowerLevel("Low", watts=1.00),
chirp_common.PowerLevel("High", watts=5.00)]
@@ -91,8 +90,6 @@ def _nc630a_enter_programming_mode(radio):
serial = radio.pipe
try:
- serial.write("\x02")
- time.sleep(0.1)
serial.write("PROGRAM")
ack = serial.read(1)
except:
@@ -109,7 +106,7 @@ def _nc630a_enter_programming_mode(radio):
except:
raise errors.RadioError("Error communicating with radio")
- if not ident.startswith("P32073"):
+ if not ident.startswith(radio._fileid):
LOG.debug(util.hexprint(ident))
raise errors.RadioError("Radio returned unknown identification string")
@@ -123,24 +120,16 @@ def _nc630a_enter_programming_mode(radio):
raise errors.RadioError("Radio refused to enter programming mode")
-def _nc630a_exit_programming_mode(radio):
- serial = radio.pipe
- try:
- serial.write("E")
- except:
- raise errors.RadioError("Radio refused to exit programming mode")
-
-
def _nc630a_read_block(radio, block_addr, block_size):
serial = radio.pipe
- cmd = struct.pack(">cHb", 'R', block_addr, BLOCK_SIZE)
+ cmd = struct.pack(">cHb", 'R', block_addr, block_size)
expectedresponse = "W" + cmd[1:]
LOG.debug("Reading block %04x..." % (block_addr))
try:
serial.write(cmd)
- response = serial.read(4 + BLOCK_SIZE)
+ response = serial.read(4 + block_size)
if response[:4] != expectedresponse:
raise Exception("Error reading block %04x." % (block_addr))
@@ -160,8 +149,8 @@ def _nc630a_read_block(radio, block_addr, block_size):
def _nc630a_write_block(radio, block_addr, block_size):
serial = radio.pipe
- cmd = struct.pack(">cHb", 'W', block_addr, BLOCK_SIZE)
- data = radio.get_mmap()[block_addr:block_addr + 8]
+ cmd = struct.pack(">cHb", 'W', block_addr, block_size)
+ data = radio.get_mmap()[block_addr:block_addr + block_size]
LOG.debug("Writing Data:")
LOG.debug(util.hexprint(cmd + data))
@@ -187,18 +176,16 @@ def do_download(radio):
status.cur = 0
status.max = radio._memsize
- for addr in range(0, radio._memsize, BLOCK_SIZE):
- status.cur = addr + BLOCK_SIZE
+ for addr in range(0, radio._memsize, radio._block_size):
+ status.cur = addr + radio._block_size
radio.status_fn(status)
- block = _nc630a_read_block(radio, addr, BLOCK_SIZE)
+ block = _nc630a_read_block(radio, addr, radio._block_size)
data += block
LOG.debug("Address: %04x" % addr)
LOG.debug(util.hexprint(block))
- _nc630a_exit_programming_mode(radio)
-
return memmap.MemoryMap(data)
@@ -212,25 +199,30 @@ def do_upload(radio):
status.max = radio._memsize
for start_addr, end_addr in radio._ranges:
- for addr in range(start_addr, end_addr, BLOCK_SIZE):
- status.cur = addr + BLOCK_SIZE
+ for addr in range(start_addr, end_addr, radio._block_size):
+ status.cur = addr + radio._block_size
radio.status_fn(status)
- _nc630a_write_block(radio, addr, BLOCK_SIZE)
+ _nc630a_write_block(radio, addr, radio._block_size)
- _nc630a_exit_programming_mode(radio)
+class MT700Alias(chirp_common.Alias):
+ VENDOR = "Plant-Tours"
+ MODEL = "MT-700"
@directory.register
class NC630aRadio(chirp_common.CloneModeRadio):
"""KYD NC-630A"""
VENDOR = "KYD"
MODEL = "NC-630A"
+ ALIASES = [MT700Alias]
BAUD_RATE = 9600
_ranges = [
- (0x0000, 0x0338),
+ (0x0000, 0x0330),
]
- _memsize = 0x0338
+ _memsize = 0x03C8
+ _block_size = 0x08
+ _fileid = "P32073"
def get_features(self):
rf = chirp_common.RadioFeatures()
@@ -403,9 +395,11 @@ class NC630aRadio(chirp_common.CloneModeRadio):
_skp = self._memobj.skipflags[bytepos]
if mem.empty:
- _mem.set_raw("\xFF" * (_mem.size() / 8))
+ _mem.set_raw("\xFF" * 16)
return
+ _mem.set_raw("\x00" * 14 + "\xFF" * 2)
+
_mem.rxfreq = mem.freq / 10
if mem.duplex == "off":
@@ -504,3 +498,20 @@ class NC630aRadio(chirp_common.CloneModeRadio):
except Exception, e:
LOG.debug(element.get_name())
raise
+
+ @classmethod
+ def match_model(cls, filedata, filename):
+ match_size = match_model = False
+
+ # testing the file data size
+ if len(filedata) in [0x338, 0x3C8]:
+ match_size = True
+
+ # testing model fingerprint
+ if filedata[0x01B8:0x01BE] == cls._fileid:
+ match_model = True
+
+ if match_size and match_model:
+ return True
+ else:
+ return False
diff --git a/chirp/drivers/leixen.py b/chirp/drivers/leixen.py
index c484495..74225d4 100644
--- a/chirp/drivers/leixen.py
+++ b/chirp/drivers/leixen.py
@@ -129,9 +129,11 @@ struct channel {
bbcd rx_freq[4];
bbcd tx_freq[4];
u8 rx_tone;
- u8 rx_tmode;
+ u8 rx_tmode_extra:6,
+ rx_tmode:2;
u8 tx_tone;
- u8 tx_tmode;
+ u8 tx_tmode_extra:6,
+ tx_tmode:2;
u8 unknown5;
u8 pttidoff:1,
dtmfoff:1,
@@ -154,12 +156,12 @@ struct name {
u8 pad;
};
-#seekto 0x0d00;
-struct channel default[3];
+#seekto 0x%(chanstart)x;
+struct channel default[%(defaults)i];
struct channel memory[199];
-#seekto 0x19b0;
-struct name defaultname[3];
+#seekto 0x%(namestart)x;
+struct name defaultname[%(defaults)i];
struct name name[199];
"""
@@ -330,6 +332,7 @@ def do_upload(radio):
do_ident(radio)
for start, end in _ranges:
+ LOG.debug('Uploading range 0x%04X - 0x%04X' % (start, end))
for addr in range(start, end, 0x10):
frame = make_frame("W", addr, radio._mmap[addr:addr + 0x10])
send(radio, frame)
@@ -362,6 +365,7 @@ class LT898UV(chirp_common.Alias):
@directory.register
class LeixenVV898Radio(chirp_common.CloneModeRadio):
+
"""Leixen VV-898"""
VENDOR = "Leixen"
MODEL = "VV-898"
@@ -383,7 +387,10 @@ class LeixenVV898Radio(chirp_common.CloneModeRadio):
]
_mem_formatter = {'unknownormode': 'unknown6:1',
- 'modeorpower': 'mode:1, power:1'}
+ 'modeorpower': 'mode:1, power:1',
+ 'chanstart': 0x0D00,
+ 'namestart': 0x19B0,
+ 'defaults': 3}
_power_levels = [chirp_common.PowerLevel("Low", watts=4),
chirp_common.PowerLevel("High", watts=10)]
@@ -437,8 +444,8 @@ class LeixenVV898Radio(chirp_common.CloneModeRadio):
raise errors.RadioError("Failed to upload to radio: %s" % e)
def get_raw_memory(self, number):
- return repr(self._memobj.name[number - 1]) + \
- repr(self._memobj.memory[number - 1])
+ name, mem = self._get_memobjs(number)
+ return repr(name) + repr(mem)
def _get_tone(self, mem, _mem):
rx_tone = tx_tone = None
@@ -468,9 +475,13 @@ class LeixenVV898Radio(chirp_common.CloneModeRadio):
raw_tx += _mem.tx_freq[i].get_raw()
return raw_tx == "\xFF\xFF\xFF\xFF"
- def get_memory(self, number):
+ def _get_memobjs(self, number):
_mem = self._memobj.memory[number - 1]
_name = self._memobj.name[number - 1]
+ return _mem, _name
+
+ def get_memory(self, number):
+ _mem, _name = self._get_memobjs(number)
mem = chirp_common.Memory()
mem.number = number
@@ -572,8 +583,7 @@ class LeixenVV898Radio(chirp_common.CloneModeRadio):
_mem.rx_tone = DTCS_CODES.index(rxtone) + 1
def set_memory(self, mem):
- _mem = self._memobj.memory[mem.number - 1]
- _name = self._memobj.name[mem.number - 1]
+ _mem, _name = self._get_memobjs(mem.number)
if mem.empty:
_mem.set_raw("\xFF" * 16)
@@ -944,6 +954,7 @@ class LeixenVV898Radio(chirp_common.CloneModeRadio):
@directory.register
class JetstreamJT270MRadio(LeixenVV898Radio):
+
"""Jetstream JT270M"""
VENDOR = "Jetstream"
MODEL = "JT270M"
@@ -952,14 +963,60 @@ class JetstreamJT270MRadio(LeixenVV898Radio):
_model_ident = 'LX-\x89\x85\x53'
+ at directory.register
+class JetstreamJT270MHRadio(LeixenVV898Radio):
+
+ """Jetstream JT270MH"""
+ VENDOR = "Jetstream"
+ MODEL = "JT270MH"
+
+ _file_ident = "Leixen"
+ _model_ident = 'LX-\x89\x85\x85'
+ _ranges = [(0x0C00, 0x2000)]
+ _mem_formatter = {'unknownormode': 'unknown6:1',
+ 'modeorpower': 'mode:1, power:1',
+ 'chanstart': 0x0C00,
+ 'namestart': 0x1930,
+ 'defaults': 6}
+
+ def get_features(self):
+ rf = super(JetstreamJT270MHRadio, self).get_features()
+ rf.has_sub_devices = self.VARIANT == ''
+ rf.memory_bounds = (1, 99)
+ return rf
+
+ def get_sub_devices(self):
+ return [JetstreamJT270MHRadioA(self._mmap),
+ JetstreamJT270MHRadioB(self._mmap)]
+
+ def _get_memobjs(self, number):
+ number = number * 2 - self._offset
+ _mem = self._memobj.memory[number]
+ _name = self._memobj.name[number]
+ return _mem, _name
+
+
+class JetstreamJT270MHRadioA(JetstreamJT270MHRadio):
+ VARIANT = 'A Band'
+ _offset = 1
+
+
+class JetstreamJT270MHRadioB(JetstreamJT270MHRadio):
+ VARIANT = 'B Band'
+ _offset = 2
+
+
class VV898E(chirp_common.Alias):
- '''Leixen has called this radio both 898E and S historically, ident is identical'''
+
+ '''Leixen has called this radio both 898E and S historically, ident is
+ identical'''
VENDOR = "Leixen"
MODEL = "VV-898E"
@directory.register
class LeixenVV898SRadio(LeixenVV898Radio):
+
"""Leixen VV-898S, also VV-898E which is identical"""
VENDOR = "Leixen"
MODEL = "VV-898S"
@@ -967,7 +1024,10 @@ class LeixenVV898SRadio(LeixenVV898Radio):
_model_ident = 'LX-\x89\x85\x75'
_mem_formatter = {'unknownormode': 'mode:1',
- 'modeorpower': 'power:2'}
+ 'modeorpower': 'power:2',
+ 'chanstart': 0x0D00,
+ 'namestart': 0x19B0,
+ 'defaults': 3}
_power_levels = [chirp_common.PowerLevel("Low", watts=5),
chirp_common.PowerLevel("Med", watts=10),
chirp_common.PowerLevel("High", watts=25)]
diff --git a/chirp/drivers/kyd.py b/chirp/drivers/retevis_rt22.py
similarity index 66%
copy from chirp/drivers/kyd.py
copy to chirp/drivers/retevis_rt22.py
index 87c46cc..a7098c9 100644
--- a/chirp/drivers/kyd.py
+++ b/chirp/drivers/retevis_rt22.py
@@ -1,5 +1,4 @@
-# Copyright 2014 Jim Unroe <rock.unroe at gmail.com>
-# Copyright 2014 Dan Smith <dsmith at danplanet.com>
+# Copyright 2016 Jim Unroe <rock.unroe at gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -23,93 +22,106 @@ from chirp import chirp_common, directory, memmap
from chirp import bitwise, errors, util
from chirp.settings import RadioSetting, RadioSettingGroup, \
RadioSettingValueInteger, RadioSettingValueList, \
- RadioSettingValueBoolean, RadioSettings
+ RadioSettingValueBoolean, RadioSettings, \
+ RadioSettingValueString
LOG = logging.getLogger(__name__)
MEM_FORMAT = """
#seekto 0x0010;
struct {
- lbcd rxfreq[4];
- lbcd txfreq[4];
- ul16 rx_tone;
- ul16 tx_tone;
- u8 unknown1:3,
- bcl:2, // Busy Lock
- unknown2:3;
- u8 unknown3:2,
- highpower:1, // Power Level
- wide:1, // Bandwidth
- unknown4:4;
+ lbcd rxfreq[4];
+ lbcd txfreq[4];
+ ul16 rx_tone;
+ ul16 tx_tone;
+ u8 unknown1;
+ u8 unknown3:2,
+ highpower:1, // Power Level
+ wide:1, // Bandwidth
+ unknown4:4;
u8 unknown5[2];
} memory[16];
#seekto 0x012F;
struct {
u8 voice; // Voice Annunciation
- u8 tot; // Time-out Timer
- u8 totalert; // Time-out Timer Pre-alert
- u8 unknown1[2];
+ u8 tot; // Time-out Timer
+ u8 unknown1[3];
u8 squelch; // Squelch Level
- u8 save; // Battery Saver
- u8 beep; // Beep
- u8 unknown2[3];
- u8 vox; // VOX Gain
- u8 voxdelay; // VOX Delay
+ u8 save; // Battery Saver
+ u8 beep; // Beep
+ u8 unknown2[2];
+ u8 vox; // VOX
+ u8 voxgain; // VOX Gain
+ u8 voxdelay; // VOX Delay
+ u8 unknown3[2];
+ u8 pf2key; // PF2 Key
} settings;
#seekto 0x017E;
u8 skipflags[2]; // SCAN_ADD
+
+#seekto 0x0300;
+struct {
+ char line1[32];
+ char line2[32];
+} embedded_msg;
"""
CMD_ACK = "\x06"
-BLOCK_SIZE = 0x08
-NC630A_POWER_LEVELS = [chirp_common.PowerLevel("Low", watts=1.00),
- chirp_common.PowerLevel("High", watts=5.00)]
+RT22_POWER_LEVELS = [chirp_common.PowerLevel("Low", watts=2.00),
+ chirp_common.PowerLevel("High", watts=5.00)]
-NC630A_DTCS = sorted(chirp_common.DTCS_CODES + [645])
+RT22_DTCS = sorted(chirp_common.DTCS_CODES + [645])
-BCL_LIST = ["Off", "Carrier", "QT/DQT"]
+PF2KEY_LIST = ["Scan", "Local Alarm", "Remote Alarm"]
TIMEOUTTIMER_LIST = [""] + ["%s seconds" % x for x in range(15, 615, 15)]
-TOTALERT_LIST = ["", "Off"] + ["%s seconds" % x for x in range(1, 11)]
VOICE_LIST = ["Off", "Chinese", "English"]
VOX_LIST = ["OFF"] + ["%s" % x for x in range(1, 17)]
-VOXDELAY_LIST = ["0.3", "0.5", "1.0", "1.5", "2.0", "3.0"]
+VOXDELAY_LIST = ["0.5", "1.0", "1.5", "2.0", "2.5", "3.0"]
SETTING_LISTS = {
- "bcl": BCL_LIST,
+ "pf2key": PF2KEY_LIST,
"tot": TIMEOUTTIMER_LIST,
- "totalert": TOTALERT_LIST,
"voice": VOICE_LIST,
"vox": VOX_LIST,
"voxdelay": VOXDELAY_LIST,
}
+VALID_CHARS = chirp_common.CHARSET_ALPHANUMERIC + \
+ "`{|}!\"#$%&'()*+,-./:;<=>?@[]^_"
+
-def _nc630a_enter_programming_mode(radio):
+def _rt22_enter_programming_mode(radio):
serial = radio.pipe
+ magic = "PROGRGS"
try:
- serial.write("\x02")
- time.sleep(0.1)
- serial.write("PROGRAM")
+ for j in range(0, len(magic)):
+ time.sleep(0.005)
+ serial.write(magic[j])
ack = serial.read(1)
except:
+ _rt22_exit_programming_mode(radio)
raise errors.RadioError("Error communicating with radio")
if not ack:
+ _rt22_exit_programming_mode(radio)
raise errors.RadioError("No response from radio")
elif ack != CMD_ACK:
+ _rt22_exit_programming_mode(radio)
raise errors.RadioError("Radio refused to enter programming mode")
try:
serial.write("\x02")
ident = serial.read(8)
except:
+ _rt22_exit_programming_mode(radio)
raise errors.RadioError("Error communicating with radio")
if not ident.startswith("P32073"):
+ _rt22_exit_programming_mode(radio)
LOG.debug(util.hexprint(ident))
raise errors.RadioError("Radio returned unknown identification string")
@@ -117,13 +129,26 @@ def _nc630a_enter_programming_mode(radio):
serial.write(CMD_ACK)
ack = serial.read(1)
except:
+ _rt22_exit_programming_mode(radio)
raise errors.RadioError("Error communicating with radio")
if ack != CMD_ACK:
+ _rt22_exit_programming_mode(radio)
+ raise errors.RadioError("Radio refused to enter programming mode")
+
+ try:
+ serial.write("\x07")
+ ack = serial.read(1)
+ except:
+ _rt22_exit_programming_mode(radio)
+ raise errors.RadioError("Error communicating with radio")
+
+ if ack != "\x4E":
+ _rt22_exit_programming_mode(radio)
raise errors.RadioError("Radio refused to enter programming mode")
-def _nc630a_exit_programming_mode(radio):
+def _rt22_exit_programming_mode(radio):
serial = radio.pipe
try:
serial.write("E")
@@ -131,17 +156,21 @@ def _nc630a_exit_programming_mode(radio):
raise errors.RadioError("Radio refused to exit programming mode")
-def _nc630a_read_block(radio, block_addr, block_size):
+def _rt22_read_block(radio, block_addr, block_size):
serial = radio.pipe
- cmd = struct.pack(">cHb", 'R', block_addr, BLOCK_SIZE)
+ cmd = struct.pack(">cHb", 'R', block_addr, block_size)
expectedresponse = "W" + cmd[1:]
LOG.debug("Reading block %04x..." % (block_addr))
try:
- serial.write(cmd)
- response = serial.read(4 + BLOCK_SIZE)
+ for j in range(0, len(cmd)):
+ time.sleep(0.005)
+ serial.write(cmd[j])
+
+ response = serial.read(4 + block_size)
if response[:4] != expectedresponse:
+ _rt22_exit_programming_mode(radio)
raise Exception("Error reading block %04x." % (block_addr))
block_data = response[4:]
@@ -149,35 +178,43 @@ def _nc630a_read_block(radio, block_addr, block_size):
serial.write(CMD_ACK)
ack = serial.read(1)
except:
+ _rt22_exit_programming_mode(radio)
raise errors.RadioError("Failed to read block at %04x" % block_addr)
if ack != CMD_ACK:
+ _rt22_exit_programming_mode(radio)
raise Exception("No ACK reading block %04x." % (block_addr))
return block_data
-def _nc630a_write_block(radio, block_addr, block_size):
+def _rt22_write_block(radio, block_addr, block_size):
serial = radio.pipe
- cmd = struct.pack(">cHb", 'W', block_addr, BLOCK_SIZE)
- data = radio.get_mmap()[block_addr:block_addr + 8]
+ cmd = struct.pack(">cHb", 'W', block_addr, block_size)
+ data = radio.get_mmap()[block_addr:block_addr + block_size]
LOG.debug("Writing Data:")
LOG.debug(util.hexprint(cmd + data))
try:
- serial.write(cmd + data)
+ for j in range(0, len(cmd)):
+ time.sleep(0.005)
+ serial.write(cmd[j])
+ for j in range(0, len(data)):
+ time.sleep(0.005)
+ serial.write(data[j])
if serial.read(1) != CMD_ACK:
raise Exception("No ACK")
except:
+ _rt22_exit_programming_mode(radio)
raise errors.RadioError("Failed to send block "
"to radio at %04x" % block_addr)
def do_download(radio):
LOG.debug("download")
- _nc630a_enter_programming_mode(radio)
+ _rt22_enter_programming_mode(radio)
data = ""
@@ -187,17 +224,19 @@ def do_download(radio):
status.cur = 0
status.max = radio._memsize
- for addr in range(0, radio._memsize, BLOCK_SIZE):
- status.cur = addr + BLOCK_SIZE
+ for addr in range(0, radio._memsize, radio._block_size):
+ status.cur = addr + radio._block_size
radio.status_fn(status)
- block = _nc630a_read_block(radio, addr, BLOCK_SIZE)
+ block = _rt22_read_block(radio, addr, radio._block_size)
data += block
LOG.debug("Address: %04x" % addr)
LOG.debug(util.hexprint(block))
- _nc630a_exit_programming_mode(radio)
+ data += radio.MODEL.ljust(8)
+
+ _rt22_exit_programming_mode(radio)
return memmap.MemoryMap(data)
@@ -206,31 +245,45 @@ def do_upload(radio):
status = chirp_common.Status()
status.msg = "Uploading to radio"
- _nc630a_enter_programming_mode(radio)
+ _rt22_enter_programming_mode(radio)
status.cur = 0
status.max = radio._memsize
- for start_addr, end_addr in radio._ranges:
- for addr in range(start_addr, end_addr, BLOCK_SIZE):
- status.cur = addr + BLOCK_SIZE
+ for start_addr, end_addr, block_size in radio._ranges:
+ for addr in range(start_addr, end_addr, block_size):
+ status.cur = addr + block_size
radio.status_fn(status)
- _nc630a_write_block(radio, addr, BLOCK_SIZE)
+ _rt22_write_block(radio, addr, block_size)
+
+ _rt22_exit_programming_mode(radio)
- _nc630a_exit_programming_mode(radio)
+
+def model_match(cls, data):
+ """Match the opened/downloaded image to the correct version"""
+
+ if len(data) == 0x0408:
+ rid = data[0x0400:0x0408]
+ return rid.startswith(cls.MODEL)
+ else:
+ return False
@directory.register
-class NC630aRadio(chirp_common.CloneModeRadio):
- """KYD NC-630A"""
- VENDOR = "KYD"
- MODEL = "NC-630A"
+class RT22Radio(chirp_common.CloneModeRadio):
+ """Retevis RT22"""
+ VENDOR = "Retevis"
+ MODEL = "RT22"
BAUD_RATE = 9600
_ranges = [
- (0x0000, 0x0338),
+ (0x0000, 0x0180, 0x10),
+ (0x01B8, 0x01F8, 0x10),
+ (0x01F8, 0x0200, 0x08),
+ (0x0200, 0x0340, 0x10),
]
- _memsize = 0x0338
+ _memsize = 0x0400
+ _block_size = 0x40
def get_features(self):
rf = chirp_common.RadioFeatures()
@@ -246,7 +299,7 @@ class NC630aRadio(chirp_common.CloneModeRadio):
rf.valid_tmodes = ["", "Tone", "TSQL", "DTCS", "Cross"]
rf.valid_cross_modes = ["Tone->Tone", "Tone->DTCS", "DTCS->Tone",
"->Tone", "->DTCS", "DTCS->", "DTCS->DTCS"]
- rf.valid_power_levels = NC630A_POWER_LEVELS
+ rf.valid_power_levels = RT22_POWER_LEVELS
rf.valid_duplexes = ["", "-", "+", "split", "off"]
rf.valid_modes = ["NFM", "FM"] # 12.5 KHz, 25 kHz.
rf.memory_bounds = (1, 16)
@@ -344,18 +397,11 @@ class NC630aRadio(chirp_common.CloneModeRadio):
self._get_tone(_mem, mem)
- mem.power = NC630A_POWER_LEVELS[_mem.highpower]
+ mem.power = RT22_POWER_LEVELS[_mem.highpower]
mem.skip = "" if (_skp & bitpos) else "S"
LOG.debug("mem.skip %s" % mem.skip)
- mem.extra = RadioSettingGroup("Extra", "extra")
-
- rs = RadioSetting("bcl", "Busy Channel Lockout",
- RadioSettingValueList(
- BCL_LIST, BCL_LIST[_mem.bcl]))
- mem.extra.append(rs)
-
return mem
def _set_tone(self, mem, _mem):
@@ -424,7 +470,7 @@ class NC630aRadio(chirp_common.CloneModeRadio):
self._set_tone(mem, _mem)
- _mem.highpower = mem.power == NC630A_POWER_LEVELS[1]
+ _mem.highpower = mem.power == RT22_POWER_LEVELS[1]
if mem.skip != "S":
_skp |= bitpos
@@ -432,52 +478,72 @@ class NC630aRadio(chirp_common.CloneModeRadio):
_skp &= ~bitpos
LOG.debug("_skp %s" % _skp)
- for setting in mem.extra:
- setattr(_mem, setting.get_name(), setting.value)
-
def get_settings(self):
_settings = self._memobj.settings
+ _message = self._memobj.embedded_msg
basic = RadioSettingGroup("basic", "Basic Settings")
top = RadioSettings(basic)
+ rs = RadioSetting("squelch", "Squelch Level",
+ RadioSettingValueInteger(0, 9, _settings.squelch))
+ basic.append(rs)
+
rs = RadioSetting("tot", "Time-out timer",
RadioSettingValueList(
TIMEOUTTIMER_LIST,
TIMEOUTTIMER_LIST[_settings.tot]))
basic.append(rs)
- rs = RadioSetting("totalert", "TOT Pre-alert",
+ rs = RadioSetting("voice", "Voice Prompts",
RadioSettingValueList(
- TOTALERT_LIST,
- TOTALERT_LIST[_settings.totalert]))
+ VOICE_LIST, VOICE_LIST[_settings.voice]))
basic.append(rs)
- rs = RadioSetting("vox", "VOX Gain",
+ rs = RadioSetting("pf2key", "PF2 Key",
RadioSettingValueList(
- VOX_LIST, VOX_LIST[_settings.vox]))
+ PF2KEY_LIST, PF2KEY_LIST[_settings.pf2key]))
basic.append(rs)
- rs = RadioSetting("voice", "Voice Annumciation",
- RadioSettingValueList(
- VOICE_LIST, VOICE_LIST[_settings.voice]))
+ rs = RadioSetting("vox", "Vox",
+ RadioSettingValueBoolean(_settings.vox))
basic.append(rs)
- rs = RadioSetting("squelch", "Squelch Level",
- RadioSettingValueInteger(0, 9, _settings.squelch))
+ rs = RadioSetting("voxgain", "VOX Level",
+ RadioSettingValueList(
+ VOX_LIST, VOX_LIST[_settings.voxgain]))
basic.append(rs)
- rs = RadioSetting("voxdelay", "VOX Delay",
+ rs = RadioSetting("voxdelay", "VOX Delay Time",
RadioSettingValueList(
VOXDELAY_LIST,
VOXDELAY_LIST[_settings.voxdelay]))
basic.append(rs)
+ rs = RadioSetting("save", "Battery Save",
+ RadioSettingValueBoolean(_settings.save))
+ basic.append(rs)
+
rs = RadioSetting("beep", "Beep",
RadioSettingValueBoolean(_settings.beep))
basic.append(rs)
- rs = RadioSetting("save", "Battery Saver",
- RadioSettingValueBoolean(_settings.save))
+ def _filter(name):
+ filtered = ""
+ for char in str(name):
+ if char in VALID_CHARS:
+ filtered += char
+ else:
+ filtered += " "
+ return filtered
+
+ rs = RadioSetting("embedded_msg.line1", "Embedded Message 1",
+ RadioSettingValueString(0, 32, _filter(
+ _message.line1)))
+ basic.append(rs)
+
+ rs = RadioSetting("embedded_msg.line2", "Embedded Message 2",
+ RadioSettingValueString(0, 32, _filter(
+ _message.line2)))
basic.append(rs)
return top
@@ -504,3 +570,32 @@ class NC630aRadio(chirp_common.CloneModeRadio):
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) in [0x0408, ]:
+ match_size = True
+
+ # testing the model fingerprint
+ match_model = model_match(cls, filedata)
+
+ if match_size and match_model:
+ return True
+ else:
+ return False
+
+ at directory.register
+class KDC1(RT22Radio):
+ """WLN KD-C1"""
+ VENDOR = "WLN"
+ MODEL = "KD-C1"
+
+ at directory.register
+class ZTX6(RT22Radio):
+ """Zastone ZT-X6"""
+ VENDOR = "Zastone"
+ MODEL = "ZT-X6"
diff --git a/chirp/drivers/thd72.py b/chirp/drivers/thd72.py
index c0a0cc7..2cf978f 100644
--- a/chirp/drivers/thd72.py
+++ b/chirp/drivers/thd72.py
@@ -189,6 +189,7 @@ EXCH_W = "W\x00\x00\x00\x00"
@directory.register
class THD72Radio(chirp_common.CloneModeRadio):
+
BAUD_RATE = 9600
VENDOR = "Kenwood"
MODEL = "TH-D72 (clone mode)"
@@ -202,8 +203,9 @@ class THD72Radio(chirp_common.CloneModeRadio):
_LCD_CONTRAST = ["Level %d" % x for x in range(1, 16)]
_LAMP_CONTROL = ["Manual", "Auto"]
_LAMP_TIMER = ["Seconds %d" % x for x in range(2, 11)]
- _BATTERY_SAVER = ["OFF", "0.03 Seconds", "0.2 Seconds", "0.4 Seconds", "0.6 Seconds",
- "0.8 Seconds", "1 Seconds", "2 Seconds", "3 Seconds", "4 Seconds", "5 Seconds"]
+ _BATTERY_SAVER = ["OFF", "0.03 Seconds", "0.2 Seconds", "0.4 Seconds",
+ "0.6 Seconds", "0.8 Seconds", "1 Seconds", "2 Seconds",
+ "3 Seconds", "4 Seconds", "5 Seconds"]
_APO = ["OFF", "15 Minutes", "30 Minutes", "60 Minutes"]
_AUDIO_BALANCE = ["Center", "A +50%", "A +100%", "B +50%", "B +100%"]
_KEY_BEEP = ["OFF", "Radio & GPS", "Radio Only", "GPS Only"]
diff --git a/chirp/drivers/uv5r.py b/chirp/drivers/uv5r.py
index e2ebc7f..8a2f9ee 100644
--- a/chirp/drivers/uv5r.py
+++ b/chirp/drivers/uv5r.py
@@ -289,8 +289,8 @@ BASETYPE_KT980HP = ["BFP3V3 B"]
BASETYPE_F8HP = ["BFP3V3 F", "N5R-3", "N5R3", "F5R3", "BFT"]
BASETYPE_UV82HP = ["N82-3", "N823"]
BASETYPE_LIST = BASETYPE_UV5R + BASETYPE_F11 + BASETYPE_UV82 + \
- BASETYPE_BJ55 + BASETYPE_UV6 + BASETYPE_KT980HP + \
- BASETYPE_F8HP + BASETYPE_UV82HP
+ BASETYPE_BJ55 + BASETYPE_UV6 + BASETYPE_KT980HP + \
+ BASETYPE_F8HP + BASETYPE_UV82HP
AB_LIST = ["A", "B"]
ALMOD_LIST = ["Site", "Tone", "Code"]
@@ -607,6 +607,7 @@ UV5R_CHARSET = chirp_common.CHARSET_UPPER_NUMERIC + \
class BaofengUV5R(chirp_common.CloneModeRadio,
chirp_common.ExperimentalRadio):
+
"""Baofeng UV-5R"""
VENDOR = "Baofeng"
MODEL = "UV-5R"
@@ -860,6 +861,20 @@ class BaofengUV5R(chirp_common.CloneModeRadio,
_nam.set_raw("\xff" * 16)
return
+ was_empty = False
+ # same method as used in get_memory to find
+ # out whether a raw memory is empty
+ if _mem.get_raw()[0] == "\xff":
+ was_empty = True
+ LOG.debug("UV5R: this mem was empty")
+ else:
+ # memorize old extra-values before erasing the whole memory
+ # used to solve issue 4121
+ LOG.debug("mem was not empty, memorize extra-settings")
+ prev_bcl = _mem.bcl.get_value()
+ prev_scode = _mem.scode.get_value()
+ prev_pttid = _mem.pttid.get_value()
+
_mem.set_raw("\x00" * 16)
_mem.rxfreq = mem.freq / 10
@@ -929,6 +944,12 @@ class BaofengUV5R(chirp_common.CloneModeRadio,
else:
_mem.lowpower = 0
+ if not was_empty:
+ # restoring old extra-settings (issue 4121
+ _mem.bcl.set_value(prev_bcl)
+ _mem.scode.set_value(prev_scode)
+ _mem.pttid.set_value(prev_pttid)
+
for setting in mem.extra:
setattr(_mem, setting.get_name(), setting.value)
@@ -1341,14 +1362,14 @@ class BaofengUV5R(chirp_common.CloneModeRadio,
value /= 10
val1a = RadioSettingValueString(
- 0, 10, convert_bytes_to_offset(_vfoa.offset))
+ 0, 10, convert_bytes_to_offset(_vfoa.offset))
rs = RadioSetting("vfoa.offset",
"VFO A Offset (0.00-69.95)", val1a)
rs.set_apply_callback(apply_offset, _vfoa)
workmode.append(rs)
val1b = RadioSettingValueString(
- 0, 10, convert_bytes_to_offset(_vfob.offset))
+ 0, 10, convert_bytes_to_offset(_vfob.offset))
rs = RadioSetting("vfob.offset",
"VFO B Offset (0.00-69.95)", val1b)
rs.set_apply_callback(apply_offset, _vfob)
@@ -1644,6 +1665,7 @@ class BaofengUV82Radio(BaofengUV5R):
@directory.register
class BaofengUV6Radio(BaofengUV5R):
+
"""Baofeng UV-6/UV-7"""
VENDOR = "Baofeng"
MODEL = "UV-6"
diff --git a/chirp/drivers/uv5x3.py b/chirp/drivers/uv5x3.py
index 9246121..1ca42a7 100644
--- a/chirp/drivers/uv5x3.py
+++ b/chirp/drivers/uv5x3.py
@@ -71,6 +71,8 @@ LIST_TIMEOUT = ["%s sec" % x for x in range(15, 615, 15)]
LIST_TXPOWER = ["High", "Low"]
LIST_VOICE = ["Off", "English", "Chinese"]
LIST_WORKMODE = ["Frequency", "Channel"]
+LIST_DTMF_SPECIAL_DIGITS = [ "*", "#", "A", "B", "C", "D"]
+LIST_DTMF_SPECIAL_VALUES = [ 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00]
def model_match(cls, data):
"""Match the opened/downloaded image to the correct version"""
@@ -1119,6 +1121,33 @@ class UV5X3(baofeng_common.BaofengCommonHT):
rs.set_apply_callback(apply_code, self._memobj.ani)
dtmfd.append(rs)
+ def apply_dmtf_listvalue(setting, obj):
+ LOG.debug("Setting value: "+ str(setting.value) + " from list")
+ val = str(setting.value)
+ index = LIST_DTMF_SPECIAL_DIGITS.index(val)
+ val = LIST_DTMF_SPECIAL_VALUES[index]
+ obj.set_value(val)
+
+ if _mem.ani.groupcode in LIST_DTMF_SPECIAL_VALUES:
+ idx = LIST_DTMF_SPECIAL_VALUES.index(_mem.ani.groupcode)
+ else:
+ idx = LIST_DTMF_SPECIAL_VALUES.index(0x0B)
+ rs = RadioSetting("ani.groupcode", "Group Code",
+ RadioSettingValueList(LIST_DTMF_SPECIAL_DIGITS,
+ LIST_DTMF_SPECIAL_DIGITS[idx]))
+ rs.set_apply_callback(apply_dmtf_listvalue, _mem.ani.groupcode)
+ dtmfd.append(rs)
+
+ if _mem.ani.spacecode in LIST_DTMF_SPECIAL_VALUES:
+ idx = LIST_DTMF_SPECIAL_VALUES.index(_mem.ani.spacecode)
+ else:
+ idx = LIST_DTMF_SPECIAL_VALUES.index(0x0C)
+ rs = RadioSetting("ani.spacecode", "Space Code",
+ RadioSettingValueList(LIST_DTMF_SPECIAL_DIGITS,
+ LIST_DTMF_SPECIAL_DIGITS[idx]))
+ rs.set_apply_callback(apply_dmtf_listvalue, _mem.ani.spacecode)
+ dtmfd.append(rs)
+
if _mem.ani.resettime > 0x9F:
val = 0x4F
else:
diff --git a/chirp/settings.py b/chirp/settings.py
index dd690ad..210e046 100644
--- a/chirp/settings.py
+++ b/chirp/settings.py
@@ -17,16 +17,19 @@ from chirp import chirp_common
class InvalidValueError(Exception):
+
"""An invalid value was specified for a given setting"""
pass
class InternalError(Exception):
+
"""A driver provided an invalid settings object structure"""
pass
class RadioSettingValue:
+
"""Base class for a single radio setting"""
def __init__(self):
@@ -69,6 +72,7 @@ class RadioSettingValue:
class RadioSettingValueInteger(RadioSettingValue):
+
"""An integer setting"""
def __init__(self, minval, maxval, current, step=1):
@@ -102,6 +106,7 @@ class RadioSettingValueInteger(RadioSettingValue):
class RadioSettingValueFloat(RadioSettingValue):
+
"""A floating-point setting"""
def __init__(self, minval, maxval, current, resolution=0.001, precision=4):
@@ -142,6 +147,7 @@ class RadioSettingValueFloat(RadioSettingValue):
class RadioSettingValueBoolean(RadioSettingValue):
+
"""A boolean setting"""
def __init__(self, current):
@@ -160,6 +166,7 @@ class RadioSettingValueBoolean(RadioSettingValue):
class RadioSettingValueList(RadioSettingValue):
+
"""A list-of-strings setting"""
def __init__(self, options, current):
@@ -181,6 +188,7 @@ class RadioSettingValueList(RadioSettingValue):
class RadioSettingValueString(RadioSettingValue):
+
"""A string setting"""
def __init__(self, minlength, maxlength, current,
@@ -213,6 +221,7 @@ class RadioSettingValueString(RadioSettingValue):
class RadioSettingValueMap(RadioSettingValueList):
+
"""Map User Options to Radio Memory Values
Provides User Option list for GUI, maintains state, verifies new values,
@@ -253,7 +262,8 @@ class RadioSettingValueMap(RadioSettingValueList):
"%s is not valid for this setting" % mem_val)
def get_mem_val(self):
- """Get the mem val corresponding to the currently selected user option"""
+ """Get the mem val corresponding to the currently selected user
+ option"""
return self._mem_vals[self._options.index(self.get_value())]
def __trunc__(self):
@@ -286,6 +296,7 @@ class RadioSettings(list):
class RadioSettingGroup(object):
+
"""A group of settings"""
def _validate(self, element):
@@ -331,6 +342,7 @@ class RadioSettingGroup(object):
def __iter__(self):
class RSGIterator:
+
"""Iterator for a RadioSettingGroup"""
def __init__(self, rsg):
@@ -377,6 +389,7 @@ class RadioSettingGroup(object):
class RadioSetting(RadioSettingGroup):
+
"""A single setting, which could be an array of items like a group"""
def __init__(self, *args):
diff --git a/chirp/ui/mainapp.py b/chirp/ui/mainapp.py
index 1d0156c..23ac948 100644
--- a/chirp/ui/mainapp.py
+++ b/chirp/ui/mainapp.py
@@ -1376,7 +1376,8 @@ of file.
def do_change_language(self):
langs = ["Auto", "English", "Polish", "Italian", "Dutch", "German",
- "Hungarian", "Russian", "Portuguese (BR)", "French", "Spanish"]
+ "Hungarian", "Russian", "Portuguese (BR)", "French",
+ "Spanish"]
d = inputdialog.ChoiceDialog(langs, parent=self,
title="Choose Language")
d.label.set_text(_("Choose a language or Auto to use the "
diff --git a/chirp/ui/settingsedit.py b/chirp/ui/settingsedit.py
index 4d50048..289c796 100644
--- a/chirp/ui/settingsedit.py
+++ b/chirp/ui/settingsedit.py
@@ -25,12 +25,14 @@ LOG = logging.getLogger(__name__)
class RadioSettingProxy(settings.RadioSetting):
+
def __init__(self, setting, editor):
self._setting = setting
self._editor = editor
class SettingsEditor(common.Editor):
+
def __init__(self, rthread):
super(SettingsEditor, self).__init__(rthread)
@@ -45,12 +47,16 @@ class SettingsEditor(common.Editor):
# The selection tree
self._store = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_INT)
self._view = gtk.TreeView(self._store)
- self._view.set_size_request(150, -1)
self._view.get_selection().connect("changed", self._view_changed_cb)
self._view.append_column(
gtk.TreeViewColumn("", gtk.CellRendererText(), text=0))
self._view.show()
- paned.pack1(self._view)
+ scrolled_window = gtk.ScrolledWindow()
+ scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ scrolled_window.add_with_viewport(self._view)
+ scrolled_window.set_size_request(200, -1)
+ scrolled_window.show()
+ paned.pack1(scrolled_window)
# The settings notebook
self._notebook = gtk.Notebook()
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-hamradio/chirp.git
More information about the pkg-hamradio-commits
mailing list