Developers
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
February 2017
- 5 participants
- 16 discussions
[chirp_devel] [PATCH] Support pySerial 3+. Fixes #3167 #3209 #3521 #3671 #3703
by Tom Hayward 03 Feb '18
by Tom Hayward 03 Feb '18
03 Feb '18
# HG changeset patch
# User Tom Hayward <tom(a)tomh.us>
# Date 1465361362 25200
# Tue Jun 07 21:49:22 2016 -0700
# Node ID d1bc2c9177858ff87c86e08447513f53794c2868
# Parent 333a280ca0c4e856258ebf9dfdb7c547fa9ec90c
Support pySerial 3+. Fixes #3167 #3209 #3521 #3671 #3703
diff -r 333a280ca0c4 -r d1bc2c917785 chirp/detect.py
--- a/chirp/detect.py Wed Jun 01 17:30:31 2016 -0700
+++ b/chirp/detect.py Tue Jun 07 21:49:22 2016 -0700
@@ -39,7 +39,7 @@
# ICOM VHF/UHF Clone-type radios @ 9600 baud
try:
- ser.setBaudrate(9600)
+ ser.baudrate = 9600
md = icf.get_model_data(ser)
return _icom_model_data_to_rclass(md)
except errors.RadioError, e:
@@ -47,7 +47,7 @@
# ICOM IC-91/92 Live-mode radios @ 4800/38400 baud
- ser.setBaudrate(4800)
+ ser.baudrate = 4800
try:
ic9x_ll.send_magic(ser)
return _icom_model_data_to_rclass("ic9x")
@@ -58,7 +58,7 @@
for rate in [9600, 4800, 19200]:
try:
- ser.setBaudrate(rate)
+ ser.baudrate = rate
return icomciv.probe_model(ser)
except errors.RadioError:
pass
diff -r 333a280ca0c4 -r d1bc2c917785 chirp/drivers/btech.py
--- a/chirp/drivers/btech.py Wed Jun 01 17:30:31 2016 -0700
+++ b/chirp/drivers/btech.py Tue Jun 07 21:49:22 2016 -0700
@@ -332,7 +332,7 @@
# touching the serial timeout to optimize the flushing
# restored at the end to the default value
- radio.pipe.setTimeout(0.1)
+ radio.pipe.timeout = 0.1
dump = "1"
datacount = 0
@@ -347,7 +347,7 @@
raise errors.RadioError(seriale)
# restore the default serial timeout
- radio.pipe.setTimeout(STIMEOUT)
+ radio.pipe.timeout = STIMEOUT
except Exception:
raise errors.RadioError("Unknown error cleaning the serial buffer")
@@ -477,8 +477,8 @@
def _do_ident(radio, status, upload=False):
"""Put the radio in PROGRAM mode & identify it"""
# set the serial discipline
- radio.pipe.setBaudrate(9600)
- radio.pipe.setParity("N")
+ radio.pipe.baudrate = 9600
+ radio.pipe.parity = "N"
# open the radio into program mode
if _start_clone_mode(radio, status) is False:
@@ -516,7 +516,7 @@
# has the check value in the _id2 var, others simply False
if radio._id2 is not False:
# lower the timeout here as this radios are reseting due to timeout
- radio.pipe.setTimeout(0.05)
+ radio.pipe.timeout = 0.05
# query & receive the extra ID
_send(radio, _make_frame("S", 0x3DF0, 16))
@@ -561,7 +561,7 @@
raise errors.RadioError("Radio didn't ACK the upload")
# restore the default serial timeout
- radio.pipe.setTimeout(STIMEOUT)
+ radio.pipe.timeout = STIMEOUT
# DEBUG
LOG.info("Positive ident, this is a %s %s" % (radio.VENDOR, radio.MODEL))
diff -r 333a280ca0c4 -r d1bc2c917785 chirp/drivers/ft2800.py
--- a/chirp/drivers/ft2800.py Wed Jun 01 17:30:31 2016 -0700
+++ b/chirp/drivers/ft2800.py Tue Jun 07 21:49:22 2016 -0700
@@ -195,7 +195,7 @@
return rf
def sync_in(self):
- self.pipe.setParity("E")
+ self.pipe.parity = "E"
start = time.time()
try:
self._mmap = _download(self)
@@ -208,7 +208,7 @@
def sync_out(self):
self.pipe.timeout = 1
- self.pipe.setParity("E")
+ self.pipe.parity = "E"
start = time.time()
try:
_upload(self)
diff -r 333a280ca0c4 -r d1bc2c917785 chirp/drivers/ic9x_ll.py
--- a/chirp/drivers/ic9x_ll.py Wed Jun 01 17:30:31 2016 -0700
+++ b/chirp/drivers/ic9x_ll.py Tue Jun 07 21:49:22 2016 -0700
@@ -439,31 +439,31 @@
def send_magic(pipe):
"""Send the magic incantation to wake up an ic9x radio"""
- if pipe.getBaudrate() == 38400:
+ if pipe.baudrate == 38400:
resp = _send_magic_38400(pipe)
if resp:
return
LOG.info("Switching from 38400 to 4800")
- pipe.setBaudrate(4800)
+ pipe.baudrate = 4800
resp = _send_magic_4800(pipe)
- pipe.setBaudrate(38400)
+ pipe.baudrate = 38400
if resp:
return
raise errors.RadioError("Radio not responding")
- elif pipe.getBaudrate() == 4800:
+ elif pipe.baudrate == 4800:
resp = _send_magic_4800(pipe)
if resp:
return
LOG.info("Switching from 4800 to 38400")
- pipe.setBaudrate(38400)
+ pipe.baudrate = 38400
resp = _send_magic_38400(pipe)
if resp:
return
- pipe.setBaudrate(4800)
+ pipe.baudrate = 4800
raise errors.RadioError("Radio not responding")
else:
raise errors.InvalidDataError("Radio in unknown state (%i)" %
- pipe.getBaudrate())
+ pipe.baudrate)
def get_memory_frame(pipe, vfo, number):
diff -r 333a280ca0c4 -r d1bc2c917785 chirp/drivers/icf.py
--- a/chirp/drivers/icf.py Wed Jun 01 17:30:31 2016 -0700
+++ b/chirp/drivers/icf.py Tue Jun 07 21:49:22 2016 -0700
@@ -251,7 +251,7 @@
LOG.debug("Response:\n%s" % util.hexprint(resp))
LOG.info("Switching to 38400 baud")
- radio.pipe.setBaudrate(38400)
+ radio.pipe.baudrate = 38400
buf = ("\xFE" * 14) + \
"\xEE\xEF" + \
diff -r 333a280ca0c4 -r d1bc2c917785 chirp/drivers/kenwood_live.py
--- a/chirp/drivers/kenwood_live.py Wed Jun 01 17:30:31 2016 -0700
+++ b/chirp/drivers/kenwood_live.py Tue Jun 07 21:49:22 2016 -0700
@@ -103,7 +103,7 @@
LAST_DELIMITER = delimiter
LOG.info("Trying ID at baud %i with delimiter \"%s\"" %
(i, repr(delimiter)))
- ser.setBaudrate(i)
+ ser.baudrate = i
ser.write(LAST_DELIMITER[0])
ser.read(25)
resp = command(ser, "ID")
diff -r 333a280ca0c4 -r d1bc2c917785 chirp/drivers/thd72.py
--- a/chirp/drivers/thd72.py Wed Jun 01 17:30:31 2016 -0700
+++ b/chirp/drivers/thd72.py Tue Jun 07 21:49:22 2016 -0700
@@ -231,7 +231,7 @@
def _detect_baud(self):
for baud in [9600, 19200, 38400, 57600]:
- self.pipe.setBaudrate(baud)
+ self.pipe.baudrate = baud
try:
self.pipe.write("\r\r")
except:
@@ -422,9 +422,11 @@
raise errors.RadioError("No response from self")
allblocks = range(self._memsize/256)
- self.pipe.setBaudrate(57600)
- self.pipe.getCTS()
- self.pipe.setRTS()
+ self.pipe.baudrate = 57600
+ try:
+ self.pipe.setRTS()
+ except AttributeError:
+ self.pipe.rts = True
self.pipe.read(1)
data = ""
LOG.debug("reading blocks %d..%d" % (blocks[0], blocks[-1]))
@@ -458,9 +460,11 @@
if self.command("0M PROGRAM") != "0M":
raise errors.RadioError("No response from self")
- self.pipe.setBaudrate(57600)
- self.pipe.getCTS()
- self.pipe.setRTS()
+ self.pipe.baudrate = 57600
+ try:
+ self.pipe.setRTS()
+ except AttributeError:
+ self.pipe.rts = True
self.pipe.read(1)
LOG.debug("writing blocks %d..%d" % (blocks[0], blocks[-1]))
total = len(blocks)
diff -r 333a280ca0c4 -r d1bc2c917785 chirp/drivers/tk270.py
--- a/chirp/drivers/tk270.py Wed Jun 01 17:30:31 2016 -0700
+++ b/chirp/drivers/tk270.py Tue Jun 07 21:49:22 2016 -0700
@@ -194,10 +194,9 @@
"""Open the radio into program mode and check if it's the correct model"""
# Set serial discipline
try:
- radio.pipe.setParity("N")
- radio.pipe.setTimeout(TIMEOUT)
- radio.pipe.flushOutput()
- radio.pipe.flushInput()
+ radio.pipe.parity = "N"
+ radio.pipe.timeout = TIMEOUT
+ radio.pipe.flush()
except:
msg = "Serial error: Can't set serial line discipline"
raise errors.RadioError(msg)
diff -r 333a280ca0c4 -r d1bc2c917785 chirp/drivers/tk760.py
--- a/chirp/drivers/tk760.py Wed Jun 01 17:30:31 2016 -0700
+++ b/chirp/drivers/tk760.py Tue Jun 07 21:49:22 2016 -0700
@@ -188,10 +188,9 @@
"""Open the radio into program mode and check if it's the correct model"""
# Set serial discipline
try:
- radio.pipe.setParity("N")
- radio.pipe.setTimeout(TIMEOUT)
- radio.pipe.flushOutput()
- radio.pipe.flushInput()
+ radio.pipe.parity = "N"
+ radio.pipe.timeout = TIMEOUT
+ radio.pipe.flush()
LOG.debug("Serial port open successful")
except:
msg = "Serial error: Can't set serial line discipline"
diff -r 333a280ca0c4 -r d1bc2c917785 chirp/drivers/tk760g.py
--- a/chirp/drivers/tk760g.py Wed Jun 01 17:30:31 2016 -0700
+++ b/chirp/drivers/tk760g.py Tue Jun 07 21:49:22 2016 -0700
@@ -441,8 +441,8 @@
def _open_radio(radio, status):
"""Open the radio into program mode and check if it's the correct model"""
# linux min is 0.13, win min is 0.25; set to bigger to be safe
- radio.pipe.setTimeout(0.25)
- radio.pipe.setParity("E")
+ radio.pipe.timeout = 0.25
+ radio.pipe.parity = "E"
# DEBUG
LOG.debug("Entering program mode.")
@@ -525,17 +525,17 @@
# set the timeout and if windows keep it bigger
if sys.platform in ["win32", "cygwin"]:
# bigger timeout
- radio.pipe.setTimeout(0.55)
+ radio.pipe.timeout = 0.55
else:
# Linux can keep up, MAC?
- radio.pipe.setTimeout(0.05)
+ radio.pipe.timeout = 0.05
# DEBUG
LOG.debug("Starting the download from radio")
for addr in MEM_BLOCKS:
# send request, but before flush the rx buffer
- radio.pipe.flushInput()
+ radio.pipe.flush()
_send(radio, _make_frame("R", addr))
# now we get the data
@@ -574,7 +574,7 @@
radio.status_fn(status)
# the default for the original soft as measured
- radio.pipe.setTimeout(0.5)
+ radio.pipe.timeout = 0.5
# DEBUG
LOG.debug("Starting the upload to the radio")
diff -r 333a280ca0c4 -r d1bc2c917785 chirp/drivers/tk8102.py
--- a/chirp/drivers/tk8102.py Wed Jun 01 17:30:31 2016 -0700
+++ b/chirp/drivers/tk8102.py Tue Jun 07 21:49:22 2016 -0700
@@ -99,7 +99,7 @@
def do_download(radio):
- radio.pipe.setParity("E")
+ radio.pipe.parity = "E"
radio.pipe.timeout = 1
do_ident(radio)
@@ -129,7 +129,7 @@
def do_upload(radio):
- radio.pipe.setParity("E")
+ radio.pipe.parity = "E"
radio.pipe.timeout = 1
do_ident(radio)
diff -r 333a280ca0c4 -r d1bc2c917785 chirp/drivers/tmv71.py
--- a/chirp/drivers/tmv71.py Wed Jun 01 17:30:31 2016 -0700
+++ b/chirp/drivers/tmv71.py Tue Jun 07 21:49:22 2016 -0700
@@ -36,7 +36,7 @@
def _detect_baud(self):
for baud in [9600, 19200, 38400, 57600]:
- self.pipe.setBaudrate(baud)
+ self.pipe.baudrate = baud
self.pipe.write("\r\r")
self.pipe.read(32)
try:
2
4
Tested changes:
[Dan Smith <dsmith(a)danplanet.com>] Add TD-M8 alias and clean up other RT22 variants
Patch from Sid Hayn on bug #4551
[Tom Hayward <tom(a)tomh.us>] [id880] Fix typo in charset definition. #281
[Tom Hayward <tom(a)tomh.us>] [thf6a] Support full charset (ASCII). Fixes #141
[Tom Hayward <tom(a)tomh.us>] [id880] Support full charset. Fixes #281
[Tom Hayward <tom(a)tomh.us>] [vx5] Support full charset (ASCII). Fixes #292
[Tom Hayward <tom(a)tomh.us>] [id31a] set used bit when creating new memory, clear when deleting. Fixes #269
[Tom Hayward <tom(a)tomh.us>] Support PyGTK < 2.22 in bank edit. Fixes #231
[Tom Hayward <tom(a)tomh.us>] [d710] [v71] [d72] Fix tone list (not all tones are supported). Fixes #212
[Dan Smith <dsmith(a)danplanet.com>] [vx7] Fix setting memory power levels on 220MHz band
Fixes #214
[Dan Smith <dsmith(a)danplanet.com>] fips: Pennsylvania FIPS code was wrong. #117
[Marco Filippi <iz3gme.marco(a)gmail.com>] Consider lower bound frequency of each valid_band as valid
Fix bug #181
[Tom Hayward <tom(a)tomh.us>] tmd700: allow 8-char names. Fixes #176
[Dan Smith <dsmith(a)danplanet.com>] Fix the "blind deletion" problem, as well as properly direct copy/paste
Fixes #172
[David Griffith <dave(a)661.org>] Bug #155 fix: VX-7 1.25m power levels
[David Griffith <dave(a)661.org>] New INSTALL and README files
Fixes #122
[Tom Hayward <tom(a)tomh.us>] thd72: only use hardware flow on OS X. Fixes #166
[Marco Filippi <iz3gme.marco(a)gmail.com>] [FT817] Tone freq not set correctly
Same as #88 for FT857, to avoid code duplication fix code have been moved from
ft857 to its ancestor class
Fix bug #163
[Tom Hayward <tom(a)tomh.us>] Fix Mac .app so paths with spaces work. Fixes Bug #145
Full log:
Started by an SCM change
Building in workspace /var/lib/jenkins/jobs/chirp-test/workspace
[workspace] $ hg showconfig paths.default
[workspace] $ hg pull --rev default
[workspace] $ hg update --clean --rev default
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
[workspace] $ hg log --rev . --template {node}
[workspace] $ hg log --rev . --template {rev}
[workspace] $ hg log --rev 0611c6c740ab74c0d939634765a52ebc2b5a8497
[workspace] $ hg log --template "<changeset node='{node}' author='{author|xmlescape}' rev='{rev}' date='{date}'><msg>{desc|xmlescape}</msg><added>{file_adds|stringify|xmlescape}</added><deleted>{file_dels|stringify|xmlescape}</deleted><files>{files|stringify|xmlescape}</files><parents>{parents}</parents></changeset>\n" --rev default:0 --follow --prune 0611c6c740ab74c0d939634765a52ebc2b5a8497
No emails were triggered.
[workspace] $ /bin/sh -xe /tmp/hudson4370910948636654752.sh
[workspace] $ /bin/sh -xe /tmp/hudson4035772512429906425.sh
+ PATH=/usr/bin:/bin:/usr/local/bin ./run_all_tests.sh
test_bit_array (tests.unit.test_bitwise.TestBitType) ... ok
test_bit_array_fail (tests.unit.test_bitwise.TestBitType) ... ok
test_bitfield_u16 (tests.unit.test_bitwise.TestBitfieldTypes) ... ok
test_bitfield_u24 (tests.unit.test_bitwise.TestBitfieldTypes) ... ok
test_bitfield_u8 (tests.unit.test_bitwise.TestBitfieldTypes) ... ok
test_bitfield_ul16 (tests.unit.test_bitwise.TestBitfieldTypes) ... ok
test_bitfield_ul24 (tests.unit.test_bitwise.TestBitfieldTypes) ... ok
test_bbcd (tests.unit.test_bitwise.TestBitwiseBCDTypes) ... ok
test_bbcd_array (tests.unit.test_bitwise.TestBitwiseBCDTypes) ... ok
test_lbcd (tests.unit.test_bitwise.TestBitwiseBCDTypes) ... ok
test_lbcd_array (tests.unit.test_bitwise.TestBitwiseBCDTypes) ... ok
test_int_array (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_u16 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_u24 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_u32 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_u8 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_ul16 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_ul24 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_ul32 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_char (tests.unit.test_bitwise.TestBitwiseCharTypes) ... ok
test_string (tests.unit.test_bitwise.TestBitwiseCharTypes) ... ok
test_string_invalid_chars (tests.unit.test_bitwise.TestBitwiseCharTypes) ... ok
test_string_wrong_length (tests.unit.test_bitwise.TestBitwiseCharTypes) ... ok
test_comment_cppstyle (tests.unit.test_bitwise.TestBitwiseComments) ... ok
test_comment_inline_cppstyle (tests.unit.test_bitwise.TestBitwiseComments) ... ok
test_missing_semicolon (tests.unit.test_bitwise.TestBitwiseErrors) ... ok
test_seek (tests.unit.test_bitwise.TestBitwiseSeek) ... ok
test_seekto (tests.unit.test_bitwise.TestBitwiseSeek) ... ok
test_struct_one_element (tests.unit.test_bitwise.TestBitwiseStructTypes) ... ok
test_struct_two_elements (tests.unit.test_bitwise.TestBitwiseStructTypes) ... ok
test_struct_writes (tests.unit.test_bitwise.TestBitwiseStructTypes) ... ok
split_tone_encode_test_cross_dtcs_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_cross_none_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_cross_none_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_cross_tone_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_cross_tone_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_none (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_tsql (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_dtcs_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_dtcs_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_none_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_none_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_tone_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_tone_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_none (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_tsql (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_fix_rounded_step_250 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_fix_rounded_step_500 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_fix_rounded_step_750 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_is_12_5 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_is_2_5 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_is_5_0 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_is_6_25 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_is_fractional_step (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_required_step (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_required_step_fail (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_format_freq (tests.unit.test_chirp_common.TestUtilityFunctions) ... ok
test_parse_freq_bad (tests.unit.test_chirp_common.TestUtilityFunctions) ... ok
test_parse_freq_decimal (tests.unit.test_chirp_common.TestUtilityFunctions) ... ok
test_parse_freq_whitespace (tests.unit.test_chirp_common.TestUtilityFunctions) ... ok
test_parse_freq_whole (tests.unit.test_chirp_common.TestUtilityFunctions) ... ok
test_ensure_has_calls_almost_full (tests.unit.test_import_logic.DstarTests) ... ok
test_ensure_has_calls_empty (tests.unit.test_import_logic.DstarTests) ... ok
test_ensure_has_calls_partial (tests.unit.test_import_logic.DstarTests) ... ok
test_ensure_has_calls_rptcall_full1 (tests.unit.test_import_logic.DstarTests) ... ok
test_ensure_has_calls_rptcall_full2 (tests.unit.test_import_logic.DstarTests) ... ok
test_ensure_has_calls_urcall_full (tests.unit.test_import_logic.DstarTests) ... ok
test_import_bank (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_dtcs_diffA_dtcs (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_dtcs_diffB_dtcs (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_duplex_negative (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_duplex_too_big_vhf (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_duplex_uhf (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_duplex_vhf (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mem (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mem_with_errors (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mem_with_warnings (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mode_invalid (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mode_valid_am (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mode_valid_fm (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_name (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_power_closest (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_power_no_dst (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_power_no_src (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_power_same (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_tone_diffA_tsql (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_tone_diffB_tsql (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_mapping (tests.unit.test_mappingmodel.TestBaseBank) ... ok
test_mapping_eq (tests.unit.test_mappingmodel.TestBaseBank) ... ok
test_base_class (tests.unit.test_mappingmodel.TestBaseBankModel) ... ok
test_get_name (tests.unit.test_mappingmodel.TestBaseBankModel) ... ok
test_mapping (tests.unit.test_mappingmodel.TestBaseMapping) ... ok
test_mapping_eq (tests.unit.test_mappingmodel.TestBaseMapping) ... ok
test_base_class (tests.unit.test_mappingmodel.TestBaseMappingModel) ... ok
test_get_name (tests.unit.test_mappingmodel.TestBaseMappingModel) ... ok
test_base_class (tests.unit.test_mappingmodel.TestBaseMappingModelIndexInterface) ... ok
test_add_memory_to_mapping (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_get_mapping_memories (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_get_mappings (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_get_memory_mappings (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_get_num_mappings (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_remove_memory_from_mapping (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_remove_memory_from_mapping_no_bank (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_remove_memory_from_mapping_wrong_bank (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_icom_bank (tests.unit.test_mappingmodel.TestIcomBanks) ... ok
test_mapping (tests.unit.test_mappingmodel.TestIcomBanks) ... ok
test_mapping_eq (tests.unit.test_mappingmodel.TestIcomBanks) ... ok
test_add_memory_to_mapping (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_index_bounds (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_mapping_memories (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_mappings (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_memory_index (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_memory_mappings (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_next_mapping_index (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_num_mappings (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_remove_memory_from_mapping (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_remove_memory_from_mapping_no_bank (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_remove_memory_from_mapping_wrong_bank (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_set_memory_index (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_set_memory_index_bad_bank (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_set_memory_index_bad_index (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_auto_tone_mode_cross (tests.unit.test_memedit_edits.TestEdits) ... ok
test_auto_tone_mode_dtcs (tests.unit.test_memedit_edits.TestEdits) ... ok
test_auto_tone_mode_dtcs_pol (tests.unit.test_memedit_edits.TestEdits) ... ok
test_auto_tone_mode_dtcs_rx (tests.unit.test_memedit_edits.TestEdits) ... ok
test_auto_tone_mode_tone (tests.unit.test_memedit_edits.TestEdits) ... ok
test_auto_tone_mode_tsql (tests.unit.test_memedit_edits.TestEdits) ... ok
test_init (tests.unit.test_platform.Win32PlatformTest) ... ok
test_serial_ports_bad_portnames (tests.unit.test_platform.Win32PlatformTest) ... ok
test_serial_ports_sorted (tests.unit.test_platform.Win32PlatformTest) ... ok
test_apply_callback (tests.unit.test_settings.TestSettingContainers) ... ok
test_radio_setting (tests.unit.test_settings.TestSettingContainers) ... ok
test_radio_setting_group (tests.unit.test_settings.TestSettingContainers) ... ok
test_radio_setting_multi (tests.unit.test_settings.TestSettingContainers) ... ok
test_changed (tests.unit.test_settings.TestSettingValues) ... ok
test_radio_setting_value_boolean (tests.unit.test_settings.TestSettingValues) ... ok
test_radio_setting_value_float (tests.unit.test_settings.TestSettingValues) ... ok
test_radio_setting_value_integer (tests.unit.test_settings.TestSettingValues) ... ok
test_radio_setting_value_list (tests.unit.test_settings.TestSettingValues) ... ok
test_radio_setting_value_string (tests.unit.test_settings.TestSettingValues) ... ok
test_validate_callback (tests.unit.test_settings.TestSettingValues) ... ok
test_delete_hole_with_all (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
test_delete_hole_with_all_full (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
test_delete_hole_with_hole (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
test_delete_hole_without_hole (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
test_insert_hole_with_space (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
test_insert_hole_without_space (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
----------------------------------------------------------------------
Ran 151 tests in 0.054s
OK
Patch 'tip' is OK
Checking for PEP8 regressions...
./chirp/platform.py:255:80: E501 line too long (82 > 79 characters)
./chirp/ui/mainapp.py:1909:80: E501 line too long (82 > 79 characters)
./chirp/ui/mainapp.py:1965:80: E501 line too long (82 > 79 characters)
real 0m7.647s
user 0m7.524s
sys 0m0.048s
================================================
Tests OK
+ cat /var/lib/jenkins/.chirp/debug.log
[2017-02-21 14:39:04,795] chirp.logger - DEBUG: CHIRP 0.3.0dev on Linux - Ubuntu 16.04.1 LTS (Python 2.7.12)
[2017-02-21 14:39:04,831] chirp.directory - INFO: Registered Kenwood_TH-D7 = THD7Radio
[2017-02-21 14:39:04,832] chirp.directory - INFO: Registered Kenwood_TH-D7G = THD7GRadio
[2017-02-21 14:39:04,832] chirp.directory - INFO: Registered Kenwood_TM-D700 = TMD700Radio
[2017-02-21 14:39:04,832] chirp.directory - INFO: Registered Kenwood_TM-V7 = TMV7Radio
[2017-02-21 14:39:04,832] chirp.directory - INFO: Registered Kenwood_TM-G707 = TMG707Radio
[2017-02-21 14:39:04,832] chirp.directory - INFO: Registered Kenwood_TH-G71 = THG71Radio
[2017-02-21 14:39:04,832] chirp.directory - INFO: Registered Kenwood_TH-F6 = THF6ARadio
[2017-02-21 14:39:04,832] chirp.directory - INFO: Registered Kenwood_TH-F7 = THF7ERadio
[2017-02-21 14:39:04,832] chirp.directory - INFO: Registered Kenwood_TM-D710 = TMD710Radio
[2017-02-21 14:39:04,832] chirp.directory - INFO: Registered Kenwood_TH-D72_live_mode = THD72Radio
[2017-02-21 14:39:04,832] chirp.directory - INFO: Registered Kenwood_TM-V71 = TMV71Radio
[2017-02-21 14:39:04,832] chirp.directory - INFO: Registered Kenwood_TM-D710G = TMD710GRadio
[2017-02-21 14:39:04,832] chirp.directory - INFO: Registered Kenwood_TH-K2 = THK2Radio
[2017-02-21 14:39:04,833] chirp.directory - INFO: Registered Kenwood_TM-271 = TM271Radio
[2017-02-21 14:39:04,833] chirp.directory - INFO: Registered Kenwood_TM-281 = TM281Radio
[2017-02-21 14:39:04,833] chirp.directory - INFO: Registered Kenwood_TM-471 = TM471Radio
[2017-02-21 14:39:04,833] chirp.directory - INFO: Registered Icom_7200 = Icom7200Radio
[2017-02-21 14:39:04,833] chirp.directory - INFO: Registered Icom_IC-7000 = Icom7000Radio
[2017-02-21 14:39:04,833] chirp.directory - INFO: Registered Icom_IC-7100 = Icom7100Radio
[2017-02-21 14:39:04,833] chirp.directory - INFO: Registered Icom_746 = Icom746Radio
[2017-02-21 14:39:04,836] chirp.directory - INFO: Registered Alinco_DR03T = DR03Radio
[2017-02-21 14:39:04,836] chirp.directory - INFO: Registered Alinco_DR06T = DR06Radio
[2017-02-21 14:39:04,836] chirp.directory - INFO: Registered Alinco_DR135T = DR135Radio
[2017-02-21 14:39:04,836] chirp.directory - INFO: Registered Alinco_DR235T = DR235Radio
[2017-02-21 14:39:04,836] chirp.directory - INFO: Registered Alinco_DR435T = DR435Radio
[2017-02-21 14:39:04,836] chirp.directory - INFO: Registered Alinco_DJ596 = DJ596Radio
[2017-02-21 14:39:04,836] chirp.directory - INFO: Registered Jetstream_JT220M = JT220MRadio
[2017-02-21 14:39:04,836] chirp.directory - INFO: Registered Alinco_DJ175 = DJ175Radio
[2017-02-21 14:39:04,837] chirp.directory - INFO: Registered Alinco_DJ-G7EG = AlincoDJG7EG
[2017-02-21 14:39:04,837] chirp.directory - INFO: Registered AnyTone_5888UV = AnyTone5888UVRadio
[2017-02-21 14:39:04,837] chirp.directory - INFO: Registered Intek_HR-2040 = IntekHR2040Radio
[2017-02-21 14:39:04,837] chirp.directory - INFO: Registered Polmar_DB-50M = PolmarDB50MRadio
[2017-02-21 14:39:04,837] chirp.directory - INFO: Registered Powerwerx_DB-750X = PowerwerxDB750XRadio
[2017-02-21 14:39:04,837] chirp.directory - INFO: Registered AnyTone_TERMN-8R = AnyToneTERMN8RRadio
[2017-02-21 14:39:04,838] chirp.directory - INFO: Registered AnyTone_OBLTR-8R = AnyToneOBLTR8RRadio
[2017-02-21 14:39:04,838] chirp.directory - INFO: Registered Baofeng_UV-3R = UV3RRadio
[2017-02-21 14:39:04,839] chirp.directory - INFO: Registered Baofeng_BF-A58 = BFA58
[2017-02-21 14:39:04,839] chirp.directory - INFO: Registered Baofeng_UV-82WP = UV82WP
[2017-02-21 14:39:04,839] chirp.directory - INFO: Registered Baofeng_GT-3WP = GT3WP
[2017-02-21 14:39:04,839] chirp.directory - INFO: Registered Retevis_RT6 = RT6
[2017-02-21 14:39:04,839] chirp.directory - INFO: Registered Baojie_BJ-9900 = BJ9900Radio
[2017-02-21 14:39:04,840] chirp.directory - INFO: Registered Baofeng_UV-5R = BaofengUV5RGeneric
[2017-02-21 14:39:04,840] chirp.directory - INFO: Registered Baofeng_F-11 = BaofengF11Radio
[2017-02-21 14:39:04,840] chirp.directory - INFO: Registered Baofeng_UV-82 = BaofengUV82Radio
[2017-02-21 14:39:04,840] chirp.directory - INFO: Registered Baofeng_UV-6 = BaofengUV6Radio
[2017-02-21 14:39:04,840] chirp.directory - INFO: Registered Intek_KT-980HP = IntekKT980Radio
[2017-02-21 14:39:04,840] chirp.directory - INFO: Registered Baofeng_BF-F8HP = BaofengBFF8HPRadio
[2017-02-21 14:39:04,840] chirp.directory - INFO: Registered Baofeng_UV-82HP = BaofengUV82HPRadio
[2017-02-21 14:39:04,841] chirp.directory - INFO: Registered Baojie_BJ-UV55 = BaojieBJUV55Radio
[2017-02-21 14:39:04,841] chirp.directory - INFO: Registered BTECH_UV-2501 = UV2501
[2017-02-21 14:39:04,841] chirp.directory - INFO: Registered BTECH_UV-2501+220 = UV2501_220
[2017-02-21 14:39:04,842] chirp.directory - INFO: Registered BTECH_UV-5001 = UV5001
[2017-02-21 14:39:04,842] chirp.directory - INFO: Registered WACCOM_MINI-8900 = MINI8900
[2017-02-21 14:39:04,842] chirp.directory - INFO: Registered QYT_KT-UV980 = KTUV980
[2017-02-21 14:39:04,842] chirp.directory - INFO: Registered QYT_KT8900 = KT9800
[2017-02-21 14:39:04,842] chirp.directory - INFO: Registered QYT_KT8900R = KT9800R
[2017-02-21 14:39:04,842] chirp.directory - INFO: Registered LUITON_LT-588UV = LT588UV
[2017-02-21 14:39:04,842] chirp.directory - INFO: Registered Feidaxin_FD-268A = FD268ARadio
[2017-02-21 14:39:04,842] chirp.directory - INFO: Registered Feidaxin_FD-268B = FD268BRadio
[2017-02-21 14:39:04,842] chirp.directory - INFO: Registered Feidaxin_FD-288A = FD288ARadio
[2017-02-21 14:39:04,842] chirp.directory - INFO: Registered Feidaxin_FD-288B = FD288BRadio
[2017-02-21 14:39:04,843] chirp.directory - INFO: Registered Feidaxin_FD-150A = FD150ARadio
[2017-02-21 14:39:04,843] chirp.directory - INFO: Registered Feidaxin_FD-160A = FD160ARadio
[2017-02-21 14:39:04,843] chirp.directory - INFO: Registered Feidaxin_FD-450A = FD450ARadio
[2017-02-21 14:39:04,843] chirp.directory - INFO: Registered Feidaxin_FD-460A = FD460ARadio
[2017-02-21 14:39:04,843] chirp.directory - INFO: Registered Feidaxin_FD-460UH = FD460UHRadio
[2017-02-21 14:39:04,843] chirp.directory - INFO: Registered Yaesu_FT-1802M = FT1802Radio
[2017-02-21 14:39:04,844] chirp.directory - INFO: Registered Yaesu_FT-1D_R = FT1Radio
[2017-02-21 14:39:04,844] chirp.directory - INFO: Registered Yaesu_FT-2800M = FT2800Radio
[2017-02-21 14:39:04,845] chirp.directory - INFO: Registered Yaesu_FT-2900R_1900R = FT2900Radio
[2017-02-21 14:39:04,845] chirp.directory - INFO: Registered Yaesu_FT-50 = FT50Radio
[2017-02-21 14:39:04,845] chirp.directory - INFO: Registered Yaesu_FT-60 = FT60Radio
[2017-02-21 14:39:04,846] chirp.directory - INFO: Registered Yaesu_FT-7800_7900 = FT7800Radio
[2017-02-21 14:39:04,846] chirp.directory - INFO: Registered Yaesu_FT-8800 = FT8800Radio
[2017-02-21 14:39:04,846] chirp.directory - INFO: Registered Yaesu_FT-8900 = FT8900Radio
[2017-02-21 14:39:04,846] chirp.directory - INFO: Registered Yaesu_FT-8100 = FT8100Radio
[2017-02-21 14:39:04,847] chirp.directory - INFO: Registered Yaesu_FT-817 = FT817Radio
[2017-02-21 14:39:04,847] chirp.directory - INFO: Registered Yaesu_FT-817ND = FT817NDRadio
[2017-02-21 14:39:04,847] chirp.directory - INFO: Registered Yaesu_FT-817ND_US = FT817NDUSRadio
[2017-02-21 14:39:04,847] chirp.directory - INFO: Registered Yaesu_FT-857_897 = FT857Radio
[2017-02-21 14:39:04,847] chirp.directory - INFO: Registered Yaesu_FT-857_897_US = FT857USRadio
[2017-02-21 14:39:04,848] chirp.directory - INFO: Registered Yaesu_FT-90 = FT90Radio
[2017-02-21 14:39:04,848] chirp.directory - INFO: Registered Yaesu_FTM-350 = FTM350Radio
[2017-02-21 14:39:04,849] chirp.directory - INFO: Registered Generic_CSV = CSVRadio
[2017-02-21 14:39:04,849] chirp.directory - INFO: Registered Commander_KG-UV = CommanderCSVRadio
[2017-02-21 14:39:04,849] chirp.directory - INFO: Registered RT_Systems_CSV = RTCSVRadio
[2017-02-21 14:39:04,849] chirp.directory - INFO: Registered ARRL_Travel_Plus = TpeRadio
[2017-02-21 14:39:04,856] chirp.directory - INFO: Registered Generic_XML = XMLRadio
[2017-02-21 14:39:04,857] chirp.directory - INFO: Registered BTECH_GMRS-V1 = GMRSV1
[2017-02-21 14:39:04,860] chirp.directory - INFO: Registered Baofeng_BF-888 = H777Radio
[2017-02-21 14:39:04,860] chirp.directory - INFO: Registered HobbyPCB_RS-UV3 = HobbyPCBRSUV3Radio
[2017-02-21 14:39:04,860] chirp.directory - INFO: Registered Icom_IC-208H = IC208Radio
[2017-02-21 14:39:04,860] chirp.directory - INFO: Registered Icom_IC-2100H = IC2100Radio
[2017-02-21 14:39:04,861] chirp.directory - INFO: Registered Icom_IC-2200H = IC2200Radio
[2017-02-21 14:39:04,861] chirp.directory - INFO: Registered Icom_IC-2720H = IC2720Radio
[2017-02-21 14:39:04,861] chirp.directory - INFO: Registered Icom_IC-2820H = IC2820Radio
[2017-02-21 14:39:04,861] chirp.directory - INFO: Registered Icom_IC-91_92AD = IC9xRadio
[2017-02-21 14:39:04,862] chirp.directory - INFO: Registered Icom_IC-Q7A = ICQ7Radio
[2017-02-21 14:39:04,862] chirp.directory - INFO: Registered Icom_IC-T70 = ICT70Radio
[2017-02-21 14:39:04,862] chirp.directory - INFO: Registered Icom_IC-T7H = ICT7HRadio
[2017-02-21 14:39:04,862] chirp.directory - INFO: Registered Icom_IC-T8A = ICT8ARadio
[2017-02-21 14:39:04,863] chirp.directory - INFO: Registered Icom_IC-W32A = ICW32ARadio
[2017-02-21 14:39:04,863] chirp.directory - INFO: Registered Icom_IC-W32E = ICW32ERadio
[2017-02-21 14:39:04,863] chirp.directory - INFO: Registered Icom_IC-V82_U82 = ICx8xRadio
[2017-02-21 14:39:04,863] chirp.directory - INFO: Registered Icom_ID-31A = ID31Radio
[2017-02-21 14:39:04,863] chirp.directory - INFO: Registered Icom_ID-51 = ID51Radio
[2017-02-21 14:39:04,864] chirp.directory - INFO: Registered Icom_ID-51_Plus = ID51PLUSRadio
[2017-02-21 14:39:04,864] chirp.directory - INFO: Registered Icom_ID-800H_v2 = ID800v2Radio
[2017-02-21 14:39:04,864] chirp.directory - INFO: Registered Icom_ID-880H = ID880Radio
[2017-02-21 14:39:04,864] chirp.directory - INFO: Registered Icom_ID-80H = ID80Radio
[2017-02-21 14:39:04,864] chirp.directory - INFO: Registered Kenwood_HMK = HMKRadio
[2017-02-21 14:39:04,865] chirp.directory - INFO: Registered Kenwood_ITM = ITMRadio
[2017-02-21 14:39:04,865] chirp.directory - INFO: Registered Wouxun_KG-UV8D = KGUV8DRadio
[2017-02-21 14:39:04,865] chirp.directory - INFO: Registered KYD_NC-630A = NC630aRadio
[2017-02-21 14:39:04,866] chirp.directory - INFO: Registered KYD_IP-620 = IP620Radio
[2017-02-21 14:39:04,866] chirp.directory - INFO: Registered Leixen_VV-898 = LeixenVV898Radio
[2017-02-21 14:39:04,866] chirp.directory - INFO: Registered Jetstream_JT270M = JetstreamJT270MRadio
[2017-02-21 14:39:04,866] chirp.directory - INFO: Registered Jetstream_JT270MH = JetstreamJT270MHRadio
[2017-02-21 14:39:04,866] chirp.directory - INFO: Registered Leixen_VV-898S = LeixenVV898SRadio
[2017-02-21 14:39:04,867] chirp.directory - INFO: Registered LUITON_LT-725UV = LT725UV
[2017-02-21 14:39:04,868] chirp.directory - INFO: Registered Wouxun_KG-UVD1P = KGUVD1PRadio
[2017-02-21 14:39:04,868] chirp.directory - INFO: Registered Wouxun_KG-UV6 = KGUV6DRadio
[2017-02-21 14:39:04,869] chirp.directory - INFO: Registered Wouxun_KG-816 = KG816Radio
[2017-02-21 14:39:04,869] chirp.directory - INFO: Registered Wouxun_KG-818 = KG818Radio
[2017-02-21 14:39:04,869] chirp.directory - INFO: Registered Puxing_PX-777 = Puxing777Radio
[2017-02-21 14:39:04,869] chirp.directory - INFO: Registered Puxing_PX-2R = Puxing2RRadio
[2017-02-21 14:39:04,870] chirp.directory - INFO: Registered Puxing_PX-888K = Puxing_PX888K_Radio
[2017-02-21 14:39:04,870] chirp.directory - INFO: Registered Retevis_RT1 = RT1Radio
[2017-02-21 14:39:04,870] chirp.directory - INFO: Registered Retevis_RT21 = RT21Radio
[2017-02-21 14:39:04,871] chirp.directory - INFO: Registered Retevis_RT22 = RT22Radio
[2017-02-21 14:39:04,871] chirp.directory - INFO: Registered TYT_TH-7800_File = TYTTH7800File
[2017-02-21 14:39:04,872] chirp.directory - INFO: Registered TYT_TH-7800 = TYTTH7800Radio
[2017-02-21 14:39:04,872] chirp.directory - INFO: Registered TYT_TH9000_220 = Th9000220Radio
[2017-02-21 14:39:04,872] chirp.directory - INFO: Registered TYT_TH9000_144 = Th9000144Radio
[2017-02-21 14:39:04,872] chirp.directory - INFO: Registered TYT_TH9000_440 = Th9000440Radio
[2017-02-21 14:39:04,872] chirp.directory - INFO: Registered TYT_TH-9800_File = TYTTH9800File
[2017-02-21 14:39:04,873] chirp.directory - INFO: Registered TYT_TH-9800 = TYTTH9800Radio
[2017-02-21 14:39:04,873] chirp.directory - INFO: Registered TYT_TH-UV3R = TYTUV3RRadio
[2017-02-21 14:39:04,873] chirp.directory - INFO: Registered TYT_TH-UV3R-25 = TYTUV3R25Radio
[2017-02-21 14:39:04,873] chirp.directory - INFO: Registered TYT_TH-UVF8D = TYTUVF8DRadio
[2017-02-21 14:39:04,874] chirp.directory - INFO: Registered Kenwood_TH-D72_clone_mode = THD72Radio
[2017-02-21 14:39:04,874] chirp.directory - INFO: Registered TYT_TH-UVF1 = TYTTHUVF1Radio
[2017-02-21 14:39:04,874] chirp.directory - INFO: Registered Kenwood_TK-260 = TK260_Radio
[2017-02-21 14:39:04,875] chirp.directory - INFO: Registered Kenwood_TK-270 = TK270_Radio
[2017-02-21 14:39:04,875] chirp.directory - INFO: Registered Kenwood_TK-272 = TK272_Radio
[2017-02-21 14:39:04,875] chirp.directory - INFO: Registered Kenwood_TK-278 = TK278_Radio
[2017-02-21 14:39:04,875] chirp.directory - INFO: Registered Kenwood_TK-360 = TK360_Radio
[2017-02-21 14:39:04,875] chirp.directory - INFO: Registered Kenwood_TK-370 = TK370_Radio
[2017-02-21 14:39:04,875] chirp.directory - INFO: Registered Kenwood_TK-372 = TK372_Radio
[2017-02-21 14:39:04,875] chirp.directory - INFO: Registered Kenwood_TK-378 = TK378_Radio
[2017-02-21 14:39:04,875] chirp.directory - INFO: Registered Kenwood_TK-760 = TK760_Radio
[2017-02-21 14:39:04,876] chirp.directory - INFO: Registered Kenwood_TK-762 = TK762_Radio
[2017-02-21 14:39:04,876] chirp.directory - INFO: Registered Kenwood_TK-768 = TK768_Radio
[2017-02-21 14:39:04,876] chirp.directory - INFO: Registered Kenwood_TK-860 = TK860_Radio
[2017-02-21 14:39:04,876] chirp.directory - INFO: Registered Kenwood_TK-862 = TK862_Radio
[2017-02-21 14:39:04,876] chirp.directory - INFO: Registered Kenwood_TK-868 = TK868_Radio
[2017-02-21 14:39:04,877] chirp.directory - INFO: Registered Kenwood_TK-868G = TK868G_Radios
[2017-02-21 14:39:04,877] chirp.directory - INFO: Registered Kenwood_TK-862G = TK862G_Radios
[2017-02-21 14:39:04,877] chirp.directory - INFO: Registered Kenwood_TK-860G = TK860G_Radios
[2017-02-21 14:39:04,877] chirp.directory - INFO: Registered Kenwood_TK-768G = TK768G_Radios
[2017-02-21 14:39:04,877] chirp.directory - INFO: Registered Kenwood_TK-762G = TK762G_Radios
[2017-02-21 14:39:04,877] chirp.directory - INFO: Registered Kenwood_TK-760G = TK760G_Radios
[2017-02-21 14:39:04,877] chirp.directory - INFO: Registered Kenwood_TK-388G = TK388G_Radios
[2017-02-21 14:39:04,877] chirp.directory - INFO: Registered Kenwood_TK-378G = TK378G_Radios
[2017-02-21 14:39:04,877] chirp.directory - INFO: Registered Kenwood_TK-372G = TK372G_Radios
[2017-02-21 14:39:04,877] chirp.directory - INFO: Registered Kenwood_TK-370G = TK370G_Radios
[2017-02-21 14:39:04,877] chirp.directory - INFO: Registered Kenwood_TK-360G = TK360G_Radios
[2017-02-21 14:39:04,878] chirp.directory - INFO: Registered Kenwood_TK-278G = TK278G_Radios
[2017-02-21 14:39:04,878] chirp.directory - INFO: Registered Kenwood_TK-272G = TK272G_Radios
[2017-02-21 14:39:04,878] chirp.directory - INFO: Registered Kenwood_TK-270G = TK270G_Radios
[2017-02-21 14:39:04,878] chirp.directory - INFO: Registered Kenwood_TK-260G = TK260G_Radios
[2017-02-21 14:39:04,878] chirp.directory - INFO: Registered Kenwood_TK-7102 = KenwoodTK7102Radio
[2017-02-21 14:39:04,878] chirp.directory - INFO: Registered Kenwood_TK-8102 = KenwoodTK8102Radio
[2017-02-21 14:39:04,878] chirp.directory - INFO: Registered Kenwood_TK-7108 = KenwoodTK7108Radio
[2017-02-21 14:39:04,878] chirp.directory - INFO: Registered Kenwood_TK-8108 = KenwoodTK8108Radio
[2017-02-21 14:39:04,879] chirp.directory - INFO: Registered Kenwood_TS-2000 = TS2000Radio
[2017-02-21 14:39:04,880] chirp.directory - INFO: Registered BTECH_UV-5X3 = UV5X3
[2017-02-21 14:39:04,880] chirp.directory - INFO: Registered Baofeng_UV-6R = UV6R
[2017-02-21 14:39:04,880] chirp.directory - INFO: Registered Baofeng_UV-B5 = BaofengUVB5
[2017-02-21 14:39:04,881] chirp.directory - INFO: Registered BTECH_UV-50X3 = UV50X3
[2017-02-21 14:39:04,881] chirp.directory - INFO: Registered Yaesu_VX-170 = VX170Radio
[2017-02-21 14:39:04,881] chirp.directory - INFO: Registered Yaesu_VX-2 = VX2Radio
[2017-02-21 14:39:04,882] chirp.directory - INFO: Registered Yaesu_VX-3 = VX3Radio
[2017-02-21 14:39:04,882] chirp.directory - INFO: Registered Yaesu_VX-5 = VX5Radio
[2017-02-21 14:39:04,882] chirp.directory - INFO: Registered Yaesu_VX-6 = VX6Radio
[2017-02-21 14:39:04,882] chirp.directory - INFO: Registered Yaesu_VX-7 = VX7Radio
[2017-02-21 14:39:04,883] chirp.directory - INFO: Registered Yaesu_VX-8_R = VX8Radio
[2017-02-21 14:39:04,883] chirp.directory - INFO: Registered Yaesu_VX-8_DR = VX8DRadio
[2017-02-21 14:39:04,883] chirp.directory - INFO: Registered Yaesu_VX-8_GE = VX8GERadio
[2017-02-21 14:39:04,884] chirp.directory - INFO: Registered Vertex_Standard_VXA-700 = VXA700Radio
Email was triggered for: Success
Sending email for trigger: Success
3
6
# HG changeset patch
# User Jim Unroe <rock.unroe(a)gmail.com>
# Date 1487725765 18000
# Node ID 56ee737ca5cfbc201a19ed6bdfa9b7891efb29f3
# Parent 0611c6c740ab74c0d939634765a52ebc2b5a8497
[New Model] TDXone TD-Q8A
This patch adds support for the TDXone TD-Q8A radio.
#2107
diff -r 0611c6c740ab -r 56ee737ca5cf chirp/drivers/tdxone_tdq8a.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chirp/drivers/tdxone_tdq8a.py Tue Feb 21 20:09:25 2017 -0500
@@ -0,0 +1,1154 @@
+# Copyright 2016:
+# * Jim Unroe KC9HI, <rock.unroe(a)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
+# 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
+
+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
+
+LOG = logging.getLogger(__name__)
+
+MEM_FORMAT = """
+#seekto 0x0010;
+struct {
+ lbcd rxfreq[4];
+ lbcd txfreq[4];
+ ul16 rxtone;
+ ul16 txtone;
+ u8 unknown1:2,
+ dtmf:1, // DTMF
+ unknown2:1,
+ bcl:1, // Busy Channel Lockout
+ unknown3:3;
+ u8 unknown4:1,
+ scan:1, // Scan Add
+ highpower:1, // TX Power Level
+ wide:1, // BandWidth
+ unknown5:4;
+ u8 unknown6[2];
+} memory[128];
+
+#seekto 0x0E17;
+struct {
+ u8 displayab:1, // Selected Display
+ unknown1:6,
+ unknown2:1;
+} settings1;
+
+#seekto 0x0E22;
+struct {
+ u8 squelcha; // menu 02a Squelch Level 0xe22
+ u8 unknown1;
+ u8 tdrab; // TDR A/B 0xe24
+ u8 roger; // menu 20 Roger Beep 0xe25
+ u8 timeout; // menu 16 TOT 0xe26
+ u8 vox; // menu 05 VOX 0xe27
+ u8 unknown2;
+ u8 mdfb; // menu 27b Memory Display Format B 0xe37
+ u8 dw; // menu 37 DW 0xe2a
+ u8 tdr; // menu 29 Dual Watch 0xe2b
+ u8 voice; // menu 03 Voice Prompts 0xe2c
+ u8 beep; // menu 01 Key Beep 0xe2d
+ u8 ani; // menu 30 ANI 0xe2e
+ u8 unknown3[4];
+ u8 pttdly; // menu 31 PTT-ID Delay 0xe33
+ u8 unknown4;
+ u8 dtmfst; // menu 33 DTMF Side Tone 0xe35
+ u8 toa; // menu 15 TOT Pre-Alert 0xe36
+ u8 mdfa; // menu 27a Memory Display Format A 0xe37
+ u8 screv; // menu 09 Scan Resume Method 0xe38
+ u8 pttid; // menu 32 PTT-ID Enable 0xe39
+ u8 ponmsg; // menu 36 Power-on Message 0xe3a
+ u8 pf1; // menu 28 Programmable Function Key 0xe3b
+ u8 unknown5;
+ u8 wtled; // menu 17 Standby LED Color 0xe3d
+ u8 rxled; // menu 18 RX LED Color 0xe3e
+ u8 txled; // menu 19 TX LED Color 0xe3f
+ u8 unknown6;
+ u8 autolk; // menu 06 Auto Key Lock 0xe41
+ u8 squelchb; // menu 02b Squelch Level 0xe42
+ u8 control; // Control Code 0xe43
+ u8 unknown7;
+ u8 ach; // Selected A channel Number 0xe45
+ u8 unknown8[4];
+ u8 password[6]; // Control Password 0xe4a-0xe4f
+ u8 unknown9[7];
+ u8 code[3]; // PTT ID Code 0xe57-0xe59
+ u8 vfomr; // Frequency/Channel Modevel 0xe5a
+ u8 keylk; // Key Lock 0xe5b
+ u8 unknown10[2];
+ u8 prioritych; // Priority Channel 0xe5e
+ u8 bch; // Selected B channel Number 0xe5f
+} settings;
+
+struct vfo {
+ u8 unknown0[8];
+ u8 freq[8];
+ u8 offset[6];
+ ul16 rxtone;
+ ul16 txtone;
+ u8 unused0:7,
+ band:1;
+ u8 unknown3;
+ u8 unknown4:2,
+ sftd:2,
+ scode:4;
+ u8 unknown5;
+ u8 unknown6:1,
+ step:3,
+ unknown7:4;
+ u8 txpower:1,
+ widenarr:1,
+ unknown8:6;
+};
+
+#seekto 0x0F10;
+struct {
+ struct vfo a;
+ struct vfo b;
+} vfo;
+
+#seekto 0x1010;
+struct {
+ u8 name[6];
+ u8 unknown[10];
+} names[128];
+
+"""
+
+##### MAGICS #########################################################
+
+# TDXone TD-Q8A magic string
+MSTRING_TDQ8A = "\x02PYNCRAM"
+
+#STIMEOUT = 2
+
+LIST_DTMF = ["QT", "QT+DTMF"]
+LIST_VOICE = ["Off", "Chinese", "English"]
+LIST_OFF1TO9 = ["Off"] + list("123456789")
+LIST_OFF1TO10 = LIST_OFF1TO9 + ["10"]
+LIST_RESUME = ["Time Operated(TO)", "Carrier Operated(CO)", "Search(SE)"]
+LIST_COLOR = ["Off", "Blue", "Orange", "Purple"]
+LIST_MODE = ["Channel", "Frequency", "Name"]
+LIST_PF1 = ["Off", "Scan", "Lamp", "FM Radio", "Alarm"]
+LIST_OFF1TO30 = ["OFF"] + ["%s" % x for x in range(1, 31)]
+LIST_DTMFST = ["Off", "DTMF Sidetone", "ANI Sidetone", "DTMF+ANI Sidetone"]
+LIST_PONMSG = ["Full", "Welcome", "Battery Voltage"]
+LIST_TIMEOUT = ["Off"] + ["%s sec" % x for x in range(15, 615, 15)]
+LIST_PTTID = ["BOT", "EOT", "Both"]
+LIST_ROGER = ["Off"] + LIST_PTTID
+LIST_PRIORITY = ["Off"] + ["%s" % x for x in range(1, 129)]
+LIST_WORKMODE = ["Frequency", "Channel"]
+LIST_AB = ["A", "B"]
+
+LIST_ALMOD = ["Site", "Tone", "Code"]
+LIST_BANDWIDTH = ["Wide", "Narrow"]
+LIST_DELAYPROCTIME = ["%s ms" % x for x in range(100, 4100, 100)]
+LIST_DTMFSPEED = ["%s ms" % x for x in range(50, 2010, 10)]
+LIST_OFFAB = ["Off"] + LIST_AB
+LIST_RESETTIME = ["%s ms" % x for x in range(100, 16100, 100)]
+LIST_SCODE = ["%s" % x for x in range(1, 16)]
+LIST_RPSTE = ["Off"] + ["%s" % x for x in range(1, 11)]
+LIST_SAVE = ["Off", "1:1", "1:2", "1:3", "1:4"]
+LIST_SHIFTD = ["Off", "+", "-"]
+LIST_STEDELAY = ["Off"] + ["%s ms" % x for x in range(100, 1100, 100)]
+#LIST_STEP = [str(x) for x in STEPS]
+LIST_TXPOWER = ["High", "Low"]
+LIST_DTMF_SPECIAL_DIGITS = [ "*", "#", "A", "B", "C", "D"]
+LIST_DTMF_SPECIAL_VALUES = [ 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00]
+
+CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ?+-*"
+STEPS = [2.5, 5.0, 6.25, 10.0, 12.5, 25.0]
+POWER_LEVELS = [chirp_common.PowerLevel("High", watts=5),
+ chirp_common.PowerLevel("Low", watts=1)]
+VALID_BANDS = [(136000000, 174000000),
+ (400000000, 520000000)]
+
+
+#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:
+ msg = "Generic error reading data from radio; check your cable."
+ raise errors.RadioError(msg)
+
+ if len(data) != amount:
+ msg = "Error reading data 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(">BHB", ord(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 """
+ # read 4 bytes of header
+ hdr = _rawrecv(radio, 4)
+
+ # read data
+ data = _rawrecv(radio, length)
+
+ # DEBUG
+ LOG.info("Response:")
+ LOG.debug(util.hexprint(hdr + data))
+
+ c, a, l = struct.unpack(">BHB", hdr)
+ if a != addr or l != length or c != ord("W"):
+ LOG.error("Invalid answer for block 0x%04x:" % addr)
+ LOG.debug("CMD: %s ADDR: %04x SIZE: %02x" % (c, a, l))
+ raise errors.RadioError("Unknown response from the radio")
+
+ return data
+
+
+def _do_ident(radio, magic):
+ """Put the radio in PROGRAM mode"""
+ # set the serial discipline
+ radio.pipe.baudrate = 9600
+ ####radio.pipe.timeout = STIMEOUT
+
+ ## flush input buffer
+ #_clean_buffer(radio)
+
+ # send request to enter program mode
+ _rawsend(radio, magic)
+
+ ack = _rawrecv(radio, 1)
+ if ack != "\x06":
+ if ack:
+ LOG.debug(repr(ack))
+ raise errors.RadioError("Radio did not respond")
+
+ _rawsend(radio, "\x02")
+
+ # Ok, get the response
+ ident = _rawrecv(radio, radio._magic_response_length)
+
+ # check if response is OK
+ if not ident.startswith("P3107"):
+ # bad response
+ msg = "Unexpected response, got this:"
+ msg += util.hexprint(ident)
+ LOG.debug(msg)
+ raise errors.RadioError("Unexpected response from radio.")
+
+ # DEBUG
+ LOG.info("Valid response, got this:")
+ LOG.debug(util.hexprint(ident))
+
+ _rawsend(radio, "\x06")
+ ack = _rawrecv(radio, 1)
+ if ack != "\x06":
+ if ack:
+ LOG.debug(repr(ack))
+ raise errors.RadioError("Radio refused clone")
+
+ return ident
+
+
+def _ident_radio(radio):
+ for magic in radio._magic:
+ error = None
+ try:
+ data = _do_ident(radio, magic)
+ return data
+ except errors.RadioError, e:
+ print e
+ error = e
+ time.sleep(2)
+ if error:
+ raise error
+ raise errors.RadioError("Radio did not respond")
+
+
+def _download(radio):
+ """Get the memory map"""
+ # put radio in program mode
+ ident = _ident_radio(radio)
+
+ # UI progress
+ status = chirp_common.Status()
+ status.cur = 0
+ status.max = radio._mem_size / radio._recv_block_size
+ status.msg = "Cloning from radio..."
+ radio.status_fn(status)
+
+ data = ""
+ for addr in range(0, radio._mem_size, radio._recv_block_size):
+ frame = _make_frame("R", addr, radio._recv_block_size)
+ # DEBUG
+ LOG.info("Request sent:")
+ LOG.debug(util.hexprint(frame))
+
+ # sending the read request
+ _rawsend(radio, frame)
+
+ # now we read
+ d = _recv(radio, addr, radio._recv_block_size)
+
+ time.sleep(0.05)
+
+ _rawsend(radio, "\x06")
+
+ ack = _rawrecv(radio, 1)
+ if ack != "\x06":
+ raise errors.RadioError(
+ "Radio refused to send block 0x%04x" % addr)
+
+ ####time.sleep(0.05)
+
+ # aggregate the data
+ data += d
+
+ # UI Update
+ status.cur = addr / radio._recv_block_size
+ status.msg = "Cloning from radio..."
+ radio.status_fn(status)
+
+ data += radio.MODEL.ljust(8)
+
+ return data
+
+
+def _upload(radio):
+ """Upload procedure"""
+ # put radio in program mode
+ _ident_radio(radio)
+
+
+
+ addr = 0x0f80
+ frame = _make_frame("R", addr, radio._recv_block_size)
+ # DEBUG
+ LOG.info("Request sent:")
+ LOG.debug(util.hexprint(frame))
+
+ # sending the read request
+ _rawsend(radio, frame)
+
+ # now we read
+ d = _recv(radio, addr, radio._recv_block_size)
+
+ time.sleep(0.05)
+
+ _rawsend(radio, "\x06")
+
+ ack = _rawrecv(radio, 1)
+ if ack != "\x06":
+ raise errors.RadioError(
+ "Radio refused to send block 0x%04x" % addr)
+
+
+
+ _ranges = radio._ranges
+
+ # UI progress
+ status = chirp_common.Status()
+ status.cur = 0
+ status.max = radio._mem_size / radio._send_block_size
+ status.msg = "Cloning to radio..."
+ radio.status_fn(status)
+
+ # the fun start here
+ for start, end in _ranges:
+ for addr in range(start, end, radio._send_block_size):
+ # sending the data
+ data = radio.get_mmap()[addr:addr + radio._send_block_size]
+
+ frame = _make_frame("W", addr, radio._send_block_size, data)
+
+ _rawsend(radio, frame)
+ #time.sleep(0.05)
+
+ # receiving the response
+ ack = _rawrecv(radio, 1)
+ if ack != "\x06":
+ msg = "Bad ack writing block 0x%04x" % addr
+ raise errors.RadioError(msg)
+
+ # UI Update
+ status.cur = addr / radio._send_block_size
+ status.msg = "Cloning to radio..."
+ radio.status_fn(status)
+
+
+def model_match(cls, data):
+ """Match the opened/downloaded image to the correct version"""
+
+ if len(data) == 0x2008:
+ rid = data[0x2000:0x2008]
+ print rid
+ return rid.startswith(cls.MODEL)
+ else:
+ return False
+
+
+def _split(rf, f1, f2):
+ """Returns False if the two freqs are in the same band (no split)
+ or True otherwise"""
+
+ # determine if the two freqs are in the same band
+ for low, high in rf.valid_bands:
+ if f1 >= low and f1 <= high and \
+ f2 >= low and f2 <= high:
+ # if the two freqs are on the same Band this is not a split
+ return False
+
+ # if you get here is because the freq pairs are split
+ return True
+
+
+(a)directory.register
+class TDXoneTDQ8A(chirp_common.CloneModeRadio,
+ chirp_common.ExperimentalRadio):
+ """TDXone TD-Q8A Radio"""
+ VENDOR = "TDXone"
+ MODEL = "TD-Q8A"
+
+ ####_fileid = [TDQ8A_fp1, ]
+
+ _magic = [MSTRING_TDQ8A, MSTRING_TDQ8A,]
+ _magic_response_length = 8
+ _fw_ver_start = 0x1EF0
+ _recv_block_size = 0x40
+ _mem_size = 0x2000
+
+ #_ranges = [(0x0000, 0x2000)]
+ # same as radio
+ #_ranges = [(0x0010, 0x0810),
+ # (0x0F10, 0x0F30),
+ # (0x1010, 0x1810),
+ # (0x0E20, 0x0E60),
+ # (0x1F10, 0x1F30)]
+ # in increasing order
+ _ranges = [(0x0010, 0x0810),
+ (0x0E20, 0x0E60),
+ (0x0F10, 0x0F30),
+ (0x1010, 0x1810),
+ (0x1F10, 0x1F30)]
+ _send_block_size = 0x10
+
+ #DTCS_CODES = sorted(chirp_common.DTCS_CODES + [645])
+ #DTCS_CODES = sorted(chirp_common.ALL_DTCS_CODES)
+ #POWER_LEVELS = [chirp_common.PowerLevel("Low", watts=1.00),
+ # chirp_common.PowerLevel("High", watts=5.00)]
+ #VALID_BANDS = [(136000000, 174000000),
+ # (400000000, 520000000)]
+
+
+ @classmethod
+ def get_prompts(cls):
+ rp = chirp_common.RadioPrompts()
+ rp.experimental = \
+ ('The TDXone TD-Q8A driver is a beta version.\n'
+ '\n'
+ 'Please save an unedited copy of your first successful\n'
+ 'download to a CHIRP Radio Images(*.img) file.'
+ )
+ rp.pre_download = _(dedent("""\
+ Follow these instructions to download your info:
+
+ 1 - Turn off your radio
+ 2 - Connect your interface cable
+ 3 - Turn on your radio
+ 4 - Do the download of your radio data
+ """))
+ rp.pre_upload = _(dedent("""\
+ Follow this instructions to upload your info:
+
+ 1 - Turn off your radio
+ 2 - Connect your interface cable
+ 3 - Turn on your radio
+ 4 - Do the upload of your radio data
+ """))
+ return rp
+
+
+ def get_features(self):
+ """Get the radio's features"""
+
+ rf = chirp_common.RadioFeatures()
+ rf.has_settings = True
+ rf.has_bank = False
+ rf.has_tuning_step = False
+ rf.can_odd_split = True
+ rf.has_name = True
+ rf.has_offset = True
+ rf.has_mode = True
+ rf.has_dtcs = False #True
+ rf.has_rx_dtcs = False #True
+ rf.has_dtcs_polarity = False #True
+ rf.has_ctone = True
+ rf.has_cross = True
+ rf.valid_modes = ["FM", "NFM"]
+ #rf.valid_characters = self.VALID_CHARS
+ rf.valid_characters = CHARSET
+ rf.valid_name_length = 6
+ rf.valid_duplexes = ["", "-", "+", "split", "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_tmodes = ['', 'Tone', 'TSQL', 'Cross']
+ rf.valid_cross_modes = [
+ "Tone->Tone",
+ "->Tone"]
+ rf.valid_skips = ["", "S"]
+ #rf.valid_dtcs_codes = self.DTCS_CODES
+ rf.memory_bounds = (1, 128)
+ rf.valid_power_levels = POWER_LEVELS
+ rf.valid_bands = VALID_BANDS
+
+ return rf
+
+
+ def process_mmap(self):
+ """Process the mem map into the mem object"""
+ self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
+
+
+ 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 _is_txinh(self, _mem):
+ raw_tx = ""
+ for i in range(0, 4):
+ raw_tx += _mem.txfreq[i].get_raw()
+ return raw_tx == "\xFF\xFF\xFF\xFF"
+
+
+ def _get_mem(self, number):
+ return self._memobj.memory[number - 1]
+
+ def _get_nam(self, number):
+ return self._memobj.names[number - 1]
+
+ def get_memory(self, number):
+ _mem = self._get_mem(number)
+ _nam = self._get_nam(number)
+
+ mem = chirp_common.Memory()
+ mem.number = number
+
+ if _mem.get_raw()[0] == "\xff":
+ mem.empty = True
+ return mem
+
+ mem.freq = int(_mem.rxfreq) * 10
+
+ if self._is_txinh(_mem):
+ # TX freq not set
+ mem.duplex = "off"
+ mem.offset = 0
+ else:
+ # TX freq set
+ offset = (int(_mem.txfreq) * 10) - mem.freq
+ if offset != 0:
+ if _split(self.get_features(), mem.freq, int(_mem.txfreq) * 10):
+ mem.duplex = "split"
+ mem.offset = int(_mem.txfreq) * 10
+ elif offset < 0:
+ mem.offset = abs(offset)
+ mem.duplex = "-"
+ elif offset > 0:
+ mem.offset = offset
+ mem.duplex = "+"
+ else:
+ mem.offset = 0
+
+ if _nam.name:
+ for char in _nam.name:
+ try:
+ mem.name += CHARSET[char]
+ except IndexError:
+ break
+ mem.name = mem.name.rstrip()
+
+ #dtcs_pol = ["N", "N"]
+
+ if _mem.txtone in [0, 0xFFFF]:
+ txmode = ""
+ elif _mem.txtone >= 0x0258:
+ txmode = "Tone"
+ mem.rtone = int(_mem.txtone) / 10.0
+ else:
+ LOG.warn("Bug: txtone is %04x" % _mem.txtone)
+
+ #elif _mem.txtone <= 0x0258:
+ # txmode = "DTCS"
+ # if _mem.txtone > 0x69:
+ # index = _mem.txtone - 0x6A
+ # dtcs_pol[0] = "R"
+ # else:
+ # index = _mem.txtone - 1
+ # mem.dtcs = self.DTCS_CODES[index]
+ #else:
+ # LOG.warn("Bug: txtone is %04x" % _mem.txtone)
+
+ if _mem.rxtone in [0, 0xFFFF]:
+ rxmode = ""
+ elif _mem.rxtone >= 0x0258:
+ rxmode = "Tone"
+ mem.ctone = int(_mem.rxtone) / 10.0
+ else:
+ LOG.warn("Bug: rxtone is %04x" % _mem.rxtone)
+
+ #elif _mem.rxtone <= 0x0258:
+ # rxmode = "DTCS"
+ # if _mem.rxtone >= 0x6A:
+ # index = _mem.rxtone - 0x6A
+ # dtcs_pol[1] = "R"
+ # else:
+ # index = _mem.rxtone - 1
+ # mem.rx_dtcs = self.DTCS_CODES[index]
+ #else:
+ # LOG.warn("Bug: rxtone is %04x" % _mem.rxtone)
+
+ if txmode == "Tone" and not rxmode:
+ mem.tmode = "Tone"
+ elif txmode == rxmode and txmode == "Tone" and mem.rtone == mem.ctone:
+ mem.tmode = "TSQL"
+ elif rxmode or txmode:
+ mem.tmode = "Cross"
+ mem.cross_mode = "%s->%s" % (txmode, rxmode)
+
+ #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)
+
+ if not _mem.scan:
+ mem.skip = "S"
+
+ mem.power = POWER_LEVELS[1 - _mem.highpower]
+
+ mem.mode = _mem.wide and "FM" or "NFM"
+
+ mem.extra = RadioSettingGroup("Extra", "extra")
+
+ rs = RadioSetting("dtmf", "DTMF",
+ RadioSettingValueList(LIST_DTMF,
+ LIST_DTMF[_mem.dtmf]))
+ mem.extra.append(rs)
+
+ rs = RadioSetting("bcl", "BCL",
+ RadioSettingValueBoolean(_mem.bcl))
+ mem.extra.append(rs)
+
+ return mem
+
+
+ def _set_mem(self, number):
+ return self._memobj.memory[number - 1]
+
+ def _set_nam(self, number):
+ return self._memobj.names[number - 1]
+
+ def set_memory(self, mem):
+ _mem = self._get_mem(mem.number)
+ _nam = self._get_nam(mem.number)
+
+ if mem.empty:
+ _mem.set_raw("\xff" * 12 + "\xbf" +"\xff" * 3)
+ _nam.set_raw("\xff" * 16)
+ return
+
+ #_mem.set_raw("\x00" * 16)
+ _mem.set_raw("\xff" * 12 + "\x9f" +"\xff" * 3)
+
+ _mem.rxfreq = mem.freq / 10
+
+ if mem.duplex == "off":
+ for i in range(0, 4):
+ _mem.txfreq[i].set_raw("\xFF")
+ elif mem.duplex == "split":
+ _mem.txfreq = mem.offset / 10
+ 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
+
+ if _nam.name:
+ for i in range(0, 6):
+ try:
+ _nam.name[i] = CHARSET.index(mem.name[i])
+ except IndexError:
+ _nam.name[i] = 0xFF
+
+ rxmode = txmode = ""
+ if mem.tmode == "Tone":
+ _mem.txtone = int(mem.rtone * 10)
+ _mem.rxtone = 0
+ elif mem.tmode == "TSQL":
+ _mem.txtone = int(mem.ctone * 10)
+ _mem.rxtone = int(mem.ctone * 10)
+ #elif mem.tmode == "DTCS":
+ # rxmode = txmode = "DTCS"
+ # _mem.txtone = self.DTCS_CODES.index(mem.dtcs) + 1
+ # _mem.rxtone = self.DTCS_CODES.index(mem.dtcs) + 1
+ elif mem.tmode == "Cross":
+ txmode, rxmode = mem.cross_mode.split("->", 1)
+ if txmode == "Tone":
+ _mem.txtone = int(mem.rtone * 10)
+ #elif txmode == "DTCS":
+ # _mem.txtone = self.DTCS_CODES.index(mem.dtcs) + 1
+ else:
+ _mem.txtone = 0
+ if rxmode == "Tone":
+ _mem.rxtone = int(mem.ctone * 10)
+ #elif rxmode == "DTCS":
+ # _mem.rxtone = self.DTCS_CODES.index(mem.rx_dtcs) + 1
+ else:
+ _mem.rxtone = 0
+ else:
+ _mem.rxtone = 0
+ _mem.txtone = 0
+
+ #if txmode == "DTCS" and mem.dtcs_polarity[0] == "R":
+ # _mem.txtone += 0x69
+ #if rxmode == "DTCS" and mem.dtcs_polarity[1] == "R":
+ # _mem.rxtone += 0x69
+
+ _mem.scan = mem.skip != "S"
+ _mem.wide = mem.mode == "FM"
+
+ _mem.highpower = mem.power == POWER_LEVELS[0]
+
+ for setting in mem.extra:
+ setattr(_mem, setting.get_name(), setting.value)
+
+
+ def get_settings(self):
+ # """Translate the bit in the mem_struct into settings in the UI"""
+ _mem = self._memobj
+ basic = RadioSettingGroup("basic", "Basic Settings")
+ advanced = RadioSettingGroup("advanced", "Advanced Settings")
+ #other = RadioSettingGroup("other", "Other Settings")
+ #work = RadioSettingGroup("work", "Work Mode Settings")
+ #fm_preset = RadioSettingGroup("fm_preset", "FM Preset")
+ #dtmfe = RadioSettingGroup("dtmfe", "DTMF Encode Settings")
+ #dtmfd = RadioSettingGroup("dtmfd", "DTMF Decode Settings")
+ #service = RadioSettingGroup("service", "Service Settings")
+ #top = RadioSettings(basic, advanced, other, work, fm_preset, dtmfe,
+ # dtmfd, service)
+ top = RadioSettings(basic, advanced, )
+
+ # Basic settings
+ rs = RadioSetting("settings.beep", "Beep",
+ RadioSettingValueBoolean(_mem.settings.beep))
+ basic.append(rs)
+
+ if _mem.settings.squelcha > 0x09:
+ val = 0x00
+ else:
+ val = _mem.settings.squelcha
+ rs = RadioSetting("squelcha", "Squelch Level A",
+ RadioSettingValueInteger(0, 9, _mem.settings.squelcha))
+ basic.append(rs)
+
+
+ if _mem.settings.squelchb > 0x09:
+ val = 0x00
+ else:
+ val = _mem.settings.squelchb
+ rs = RadioSetting("squelchb", "Squelch Level B",
+ RadioSettingValueInteger(0, 9, _mem.settings.squelchb))
+ basic.append(rs)
+
+
+ if _mem.settings.voice > 0x02:
+ val = 0x01
+ else:
+ val = _mem.settings.voice
+ rs = RadioSetting("settings.voice", "Voice Prompt",
+ RadioSettingValueList(
+ LIST_VOICE, LIST_VOICE[val]))
+ basic.append(rs)
+
+ if _mem.settings.vox > 0x0A:
+ val = 0x00
+ else:
+ val = _mem.settings.vox
+ rs = RadioSetting("settings.vox", "VOX",
+ RadioSettingValueList(
+ LIST_OFF1TO10, LIST_OFF1TO10[val]))
+ basic.append(rs)
+
+ rs = RadioSetting("settings.autolk", "Automatic Key Lock",
+ RadioSettingValueBoolean(_mem.settings.autolk))
+ basic.append(rs)
+
+ if _mem.settings.screv > 0x02:
+ val = 0x01
+ else:
+ val = _mem.settings.screv
+ rs = RadioSetting("settings.screv", "Scan Resume",
+ RadioSettingValueList(
+ LIST_RESUME, LIST_RESUME[val]))
+ basic.append(rs)
+
+ if _mem.settings.toa > 0x0A:
+ val = 0x00
+ else:
+ val = _mem.settings.toa
+ rs = RadioSetting("settings.toa", "Time-out Pre-Alert",
+ RadioSettingValueList(
+ LIST_OFF1TO10, LIST_OFF1TO10[val]))
+ basic.append(rs)
+
+ if _mem.settings.timeout > 0x28:
+ val = 0x03
+ else:
+ val = _mem.settings.timeout
+ rs = RadioSetting("settings.timeout", "Timeout Timer",
+ RadioSettingValueList(
+ LIST_TIMEOUT, LIST_TIMEOUT[val]))
+ basic.append(rs)
+
+ rs = RadioSetting("settings.wtled", "Standby LED Color",
+ RadioSettingValueList(
+ LIST_COLOR, LIST_COLOR[_mem.settings.wtled]))
+ basic.append(rs)
+
+ rs = RadioSetting("settings.rxled", "RX LED Color",
+ RadioSettingValueList(
+ LIST_COLOR, LIST_COLOR[_mem.settings.rxled]))
+ basic.append(rs)
+
+ rs = RadioSetting("settings.txled", "TX LED Color",
+ RadioSettingValueList(
+ LIST_COLOR, LIST_COLOR[_mem.settings.txled]))
+ basic.append(rs)
+
+ rs = RadioSetting("settings.roger", "Roger Beep",
+ RadioSettingValueList(LIST_ROGER, LIST_ROGER[
+ _mem.settings.roger]))
+ basic.append(rs)
+
+ rs = RadioSetting("settings.mdfa", "Display Mode (A)",
+ RadioSettingValueList(LIST_MODE, LIST_MODE[
+ _mem.settings.mdfa]))
+ basic.append(rs)
+
+ rs = RadioSetting("settings.mdfb", "Display Mode (B)",
+ RadioSettingValueList(LIST_MODE, LIST_MODE[
+ _mem.settings.mdfb]))
+ basic.append(rs)
+
+ rs = RadioSetting("settings.pf1", "PF1 Key Assignment",
+ RadioSettingValueList(LIST_PF1, LIST_PF1[
+ _mem.settings.pf1]))
+ basic.append(rs)
+
+ rs = RadioSetting("settings.tdr", "Dual Watch(TDR)",
+ RadioSettingValueBoolean(_mem.settings.tdr))
+ basic.append(rs)
+
+ rs = RadioSetting("settings.ani", "ANI",
+ RadioSettingValueBoolean(_mem.settings.ani))
+ basic.append(rs)
+
+ if _mem.settings.pttdly > 0x0A:
+ val = 0x00
+ else:
+ val = _mem.settings.pttdly
+ rs = RadioSetting("settings.pttdly", "PTT ID Delay",
+ RadioSettingValueList(
+ LIST_OFF1TO30, LIST_OFF1TO30[val]))
+ basic.append(rs)
+
+ rs = RadioSetting("settings.pttid", "When to send PTT ID",
+ RadioSettingValueList(LIST_PTTID,
+ LIST_PTTID[_mem.settings.pttid]))
+ basic.append(rs)
+
+ rs = RadioSetting("settings.dtmfst", "DTMF Sidetone",
+ RadioSettingValueList(LIST_DTMFST, LIST_DTMFST[
+ _mem.settings.dtmfst]))
+ basic.append(rs)
+
+ rs = RadioSetting("settings.ponmsg", "Power-On Message",
+ RadioSettingValueList(LIST_PONMSG, LIST_PONMSG[
+ _mem.settings.ponmsg]))
+ basic.append(rs)
+
+ rs = RadioSetting("settings.dw", "DW",
+ RadioSettingValueBoolean(_mem.settings.dw))
+ basic.append(rs)
+
+ # Advanced settings
+ rs = RadioSetting("settings.prioritych", "Priority Channel",
+ RadioSettingValueList(LIST_PRIORITY, LIST_PRIORITY[
+ _mem.settings.prioritych]))
+ advanced.append(rs)
+
+ rs = RadioSetting("settings.vfomr", "Work Mode",
+ RadioSettingValueList(LIST_WORKMODE, LIST_WORKMODE[
+ _mem.settings.vfomr]))
+ advanced.append(rs)
+
+ dtmfchars = "0123456789"
+ _codeobj = _mem.settings.code
+ _code = "".join([dtmfchars[x] for x in _codeobj if int(x) < 0x1F])
+ val = RadioSettingValueString(0, 3, _code, False)
+ val.set_charset(dtmfchars)
+ rs = RadioSetting("settings.code", "PTT-ID Code", val)
+
+ def apply_code(setting, obj):
+ code = []
+ for j in range(0, 3):
+ try:
+ code.append(dtmfchars.index(str(setting.value)[j]))
+ except IndexError:
+ code.append(0xFF)
+ obj.code = code
+ rs.set_apply_callback(apply_code, _mem.settings)
+ advanced.append(rs)
+
+ _codeobj = _mem.settings.password
+ _code = "".join([dtmfchars[x] for x in _codeobj if int(x) < 0x1F])
+ val = RadioSettingValueString(0, 6, _code, False)
+ val.set_charset(dtmfchars)
+ rs = RadioSetting("settings.password", "Control Password", val)
+
+ def apply_code(setting, obj):
+ code = []
+ for j in range(0, 6):
+ try:
+ code.append(dtmfchars.index(str(setting.value)[j]))
+ except IndexError:
+ code.append(0xFF)
+ obj.password = code
+ rs.set_apply_callback(apply_code, _mem.settings)
+ advanced.append(rs)
+
+ if _mem.settings.tdrab > 0x01:
+ val = 0x00
+ else:
+ val = _mem.settings.tdrab
+ rs = RadioSetting("settings.tdrab", "Dual Watch TX Priority",
+ RadioSettingValueList(
+ LIST_AB, LIST_AB[val]))
+ advanced.append(rs)
+
+ rs = RadioSetting("settings.keylk", "Key Lock",
+ RadioSettingValueBoolean(_mem.settings.keylk))
+ advanced.append(rs)
+
+ rs = RadioSetting("settings.control", "Control Code",
+ RadioSettingValueBoolean(_mem.settings.control))
+ advanced.append(rs)
+
+ return top
+
+
+
+ """
+ # Other settings
+ def _filter(name):
+ filtered = ""
+ for char in str(name):
+ if char in chirp_common.CHARSET_ASCII:
+ filtered += char
+ else:
+ filtered += " "
+ return filtered
+
+ _msg = _mem.sixpoweron_msg
+ val = RadioSettingValueString(0, 7, _filter(_msg.line1))
+ val.set_mutable(False)
+ rs = RadioSetting("sixpoweron_msg.line1", "6+Power-On Message 1", val)
+ other.append(rs)
+ val = RadioSettingValueString(0, 7, _filter(_msg.line2))
+ val.set_mutable(False)
+ rs = RadioSetting("sixpoweron_msg.line2", "6+Power-On Message 2", val)
+ other.append(rs)
+
+ _msg = _mem.poweron_msg
+ rs = RadioSetting("poweron_msg.line1", "Power-On Message 1",
+ RadioSettingValueString(
+ 0, 7, _filter(_msg.line1)))
+ other.append(rs)
+ rs = RadioSetting("poweron_msg.line2", "Power-On Message 2",
+ RadioSettingValueString(
+ 0, 7, _filter(_msg.line2)))
+ other.append(rs)
+
+ # DTMF encode settings
+
+ if _mem.ani.dtmfon > 0xC3:
+ val = 0x03
+ else:
+ val = _mem.ani.dtmfon
+ rs = RadioSetting("ani.dtmfon", "DTMF Speed (on)",
+ RadioSettingValueList(LIST_DTMFSPEED,
+ LIST_DTMFSPEED[val]))
+ dtmfe.append(rs)
+
+ if _mem.ani.dtmfoff > 0xC3:
+ val = 0x03
+ else:
+ val = _mem.ani.dtmfoff
+ rs = RadioSetting("ani.dtmfoff", "DTMF Speed (off)",
+ RadioSettingValueList(LIST_DTMFSPEED,
+ LIST_DTMFSPEED[val]))
+ dtmfe.append(rs)
+
+ """
+
+
+ def set_settings(self, settings):
+ _settings = self._memobj.settings
+ _mem = self._memobj
+ for element in settings:
+ if not isinstance(element, RadioSetting):
+ if element.get_name() == "fm_preset":
+ self._set_fm_preset(element)
+ else:
+ 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
+
+ def _set_fm_preset(self, settings):
+ for element in settings:
+ try:
+ val = element.value
+ if self._memobj.fm_presets <= 108.0 * 10 - 650:
+ value = int(val.get_value() * 10 - 650)
+ else:
+ value = int(val.get_value() * 10)
+ LOG.debug("Setting fm_presets = %s" % (value))
+ self._memobj.fm_presets = 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) == 0x2008:
+ match_size = True
+
+ # testing the model fingerprint
+ match_model = model_match(cls, filedata)
+
+ #if match_size and match_model:
+ if match_size and match_model:
+ return True
+ else:
+ return False
1
1
[chirp_devel] [PATCH] [KT7900D] Add Support for QYT KT7900D and KT8900D Mobile Radios
by Jim Unroe 19 Feb '17
by Jim Unroe 19 Feb '17
19 Feb '17
# HG changeset patch
# User Jim Unroe <rock.unroe(a)gmail.com>
# Date 1487549731 18000
# Node ID 90b02a91d80c80d843f3c1de6ff7dc5470030f3b
# Parent 0611c6c740ab74c0d939634765a52ebc2b5a8497
[KT7900D] Add Support for QYT KT7900D and KT8900D Mobile Radios
This patch modifies the btech.py driver to prepare it to support a
new series of mobile radios that have an OLED color display.
Radio models initially supported:
QYT KT7900D (quad band)
QYT KT8900D (dual band)
New Model #4269
diff -r 0611c6c740ab -r 90b02a91d80c chirp/drivers/btech.py
--- a/chirp/drivers/btech.py Thu Feb 16 18:28:49 2017 -0800
+++ b/chirp/drivers/btech.py Sun Feb 19 19:15:31 2017 -0500
@@ -1,4 +1,4 @@
-# Copyright 2016:
+# Copyright 2016-2017:
# * Pavel Milanes CO7WT, <pavelmc(a)gmail.com>
# * Jim Unroe KC9HI, <rock.unroe(a)gmail.com>
#
@@ -30,6 +30,2710 @@
RadioSettingValueFloat, RadioSettings, InvalidValueError
from textwrap import dedent
+# A note about the memmory in these radios
+#
+# The real memory of these radios extends to 0x4000
+# On read the factory software only uses up to 0x3200
+# On write it just uploads the contents up to 0x3100
+#
+# The mem beyond 0x3200 holds the ID data
+
+MEM_SIZE = 0x4000
+BLOCK_SIZE = 0x40
+TX_BLOCK_SIZE = 0x10
+ACK_CMD = "\x06"
+MODES = ["FM", "NFM"]
+SKIP_VALUES = ["S", ""]
+TONES = chirp_common.TONES
+DTCS = sorted(chirp_common.DTCS_CODES + [645])
+
+# lists related to "extra" settings
+PTTID_LIST = ["OFF", "BOT", "EOT", "BOTH"]
+PTTIDCODE_LIST = ["%s" % x for x in range(1, 16)]
+OPTSIG_LIST = ["OFF", "DTMF", "2TONE", "5TONE"]
+SPMUTE_LIST = ["Tone/DTCS", "Tone/DTCS and Optsig", "Tone/DTCS or Optsig"]
+
+# lists
+LIST_AB = ["A", "B"]
+LIST_ABCD = LIST_AB + ["C", "D"]
+LIST_ANIL = ["3", "4", "5"]
+LIST_APO = ["Off"] + ["%s minutes" % x for x in range(30, 330, 30)]
+LIST_COLOR4 = ["Off", "Blue", "Orange", "Purple"]
+LIST_COLOR8 = ["Black", "White", "Red", "Blue", "Green", "Yellow", "Indego",
+ "Purple", "Gray"]
+LIST_DTMFST = ["OFF", "Keyboard", "ANI", "Keyboad + ANI"]
+LIST_EMCTP = ["TX alarm sound", "TX ANI", "Both"]
+LIST_EMCTPX = ["Off"] + LIST_EMCTP
+LIST_LANGUA = ["English", "Chinese"]
+LIST_MDF = ["Frequency", "Channel", "Name"]
+LIST_OFF1TO9 = ["Off"] + ["%s seconds" % x for x in range(1, 10)]
+LIST_OFF1TO10 = ["Off"] + ["%s seconds" % x for x in range(1, 11)]
+LIST_OFF1TO50 = ["Off"] + ["%s seconds" % x for x in range(1, 51)]
+LIST_PONMSG = ["Full", "Message", "Battery voltage"]
+LIST_REPM = ["Off", "Carrier", "CTCSS or DCS", "Tone", "DTMF"]
+LIST_REPS = ["1000 Hz", "1450 Hz", "1750 Hz", "2100Hz"]
+LIST_RPTDL = ["Off"] + ["%s ms" % x for x in range(1, 10)]
+LIST_SCMODE = ["Off", "PTT-SC", "MEM-SC", "PON-SC"]
+LIST_SHIFT = ["Off", "+", "-"]
+LIST_SKIPTX = ["Off", "Skip 1", "Skip 2"]
+STEPS = [2.5, 5.0, 6.25, 10.0, 12.5, 25.0]
+LIST_STEP = [str(x) for x in STEPS]
+LIST_SYNC = ["Off", "AB", "CD", "AB+CD"]
+LIST_TMR = ["OFF", "M+A", "M+B", "M+C", "M+D", "M+A+B", "M+A+C", "M+A+D",
+ "M+B+C", "M+B+D", "M+C+D", "M+A+B+C", "M+A+B+D", "M+A+C+D",
+ "M+B+C+D", "A+B+C+D"]
+LIST_TOT = ["%s sec" % x for x in range(15, 615, 15)]
+LIST_TXDISP = ["Power", "Mic Volume"]
+LIST_TXP = ["High", "Low"]
+LIST_SCREV = ["TO (timeout)", "CO (carrier operated)", "SE (search)"]
+LIST_VFOMR = ["Frequency", "Channel"]
+LIST_WIDE = ["Wide", "Narrow"]
+
+# lists related to DTMF, 2TONE and 5TONE settings
+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_5TONE_RESET_COLOR = ["%s ms" % x for x in range(100, 20100, 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.
+STIMEOUT = 0.7
+
+# this var controls the verbosity in the debug and by default it's low (False)
+# make it True and you will to get a very verbose debug.log
+debug = False
+
+# valid chars on the LCD, Note that " " (space) is stored as "\xFF"
+VALID_CHARS = chirp_common.CHARSET_ALPHANUMERIC + \
+ "`{|}!\"#$%&'()*+,-./:;<=>?@[]^_"
+
+
+##### ID strings #####################################################
+
+# BTECH UV2501 pre-production units
+UV2501pp_fp = "M2C294"
+# BTECH UV2501 pre-production units 2 + and 1st Gen radios
+UV2501pp2_fp = "M29204"
+# B-TECH UV-2501 second generation (2G) radios
+UV2501G2_fp = "BTG214"
+# B-TECH UV-2501 third generation (3G) radios
+UV2501G3_fp = "BTG324"
+
+# B-TECH UV-2501+220 pre-production units
+UV2501_220pp_fp = "M3C281"
+# extra block read for the 2501+220 pre-production units
+# the same for all of this radios so far
+UV2501_220pp_id = " 280528"
+# B-TECH UV-2501+220
+UV2501_220_fp = "M3G201"
+# new variant, let's call it Generation 2
+UV2501_220G2_fp = "BTG211"
+# B-TECH UV-2501+220 third generation (3G)
+UV2501_220G3_fp = "BTG311"
+
+# B-TECH UV-5001 pre-production units + 1st Gen radios
+UV5001pp_fp = "V19204"
+# B-TECH UV-5001 alpha units
+UV5001alpha_fp = "V28204"
+# B-TECH UV-5001 second generation (2G) radios
+UV5001G2_fp = "BTG214"
+# B-TECH UV-5001 second generation (2G2)
+UV5001G22_fp = "V2G204"
+# B-TECH UV-5001 third generation (3G)
+UV5001G3_fp = "BTG304"
+
+# special var to know when we found a BTECH Gen 3
+BTECH3 = [UV2501G3_fp, UV2501_220G3_fp, UV5001G3_fp]
+
+
+# WACCOM Mini-8900
+MINI8900_fp = "M28854"
+
+
+# QYT KT-UV980
+KTUV980_fp = "H28854"
+
+# QYT KT8900
+KT8900_fp = "M29154"
+# New generations KT8900
+KT8900_fp1 = "M2C234"
+KT8900_fp2 = "M2G1F4"
+KT8900_fp3 = "M2G2F4"
+KT8900_fp4 = "M2G304"
+KT8900_fp5 = "M2G314"
+# this radio has an extra ID
+KT8900_id = " 303688"
+
+# KT8900R
+KT8900R_fp = "M3G1F4"
+# Second Generation
+KT8900R_fp1 = "M3G214"
+# another model
+KT8900R_fp2 = "M3C234"
+# another model G4?
+KT8900R_fp3 = "M39164"
+# another model
+KT8900R_fp4 = "M3G314"
+# this radio has an extra ID
+KT8900R_id = "280528"
+
+# KT7900D (quad band)
+KT7900D_fp = "VC4004"
+
+# KT8900D (dual band)
+KT8900D_fp = "VC2002"
+
+# LUITON LT-588UV
+LT588UV_fp = "V2G1F4"
+# Added by rstrickoff gen 2 id
+LT588UV_fp1 = "V2G214"
+
+
+#### MAGICS
+# for the Waccom Mini-8900
+MSTRING_MINI8900 = "\x55\xA5\xB5\x45\x55\x45\x4d\x02"
+# for the B-TECH UV-2501+220 (including pre production ones)
+MSTRING_220 = "\x55\x20\x15\x12\x12\x01\x4d\x02"
+# for the QYT KT8900 & R
+MSTRING_KT8900 = "\x55\x20\x15\x09\x16\x45\x4D\x02"
+MSTRING_KT8900R = "\x55\x20\x15\x09\x25\x01\x4D\x02"
+# magic string for all other models
+MSTRING = "\x55\x20\x15\x09\x20\x45\x4d\x02"
+# for the QYT KT7900D & KT8900D
+MSTRING_KT8900D = "\x55\x20\x16\x08\x01\xFF\xDC\x02"
+
+
+def _clean_buffer(radio):
+ """Cleaning the read serial buffer, hard timeout to survive an infinite
+ data stream"""
+
+ # touching the serial timeout to optimize the flushing
+ # restored at the end to the default value
+ radio.pipe.timeout = 0.1
+ dump = "1"
+ datacount = 0
+
+ try:
+ while len(dump) > 0:
+ dump = radio.pipe.read(100)
+ datacount += len(dump)
+ # hard limit to survive a infinite serial data stream
+ # 5 times bigger than a normal rx block (69 bytes)
+ if datacount > 345:
+ seriale = "Please check your serial port selection."
+ raise errors.RadioError(seriale)
+
+ # restore the default serial timeout
+ radio.pipe.timeout = STIMEOUT
+
+ except Exception:
+ raise errors.RadioError("Unknown error cleaning the serial buffer")
+
+
+def _rawrecv(radio, amount):
+ """Raw read from the radio device, less intensive way"""
+
+ data = ""
+
+ try:
+ data = radio.pipe.read(amount)
+
+ # DEBUG
+ if debug is True:
+ LOG.debug("<== (%d) bytes:\n\n%s" %
+ (len(data), util.hexprint(data)))
+
+ # fail if no data is received
+ if len(data) == 0:
+ raise errors.RadioError("No data received from radio")
+
+ # notice on the logs if short
+ if len(data) < amount:
+ LOG.warn("Short reading %d bytes from the %d requested." %
+ (len(data), amount))
+
+ except:
+ raise errors.RadioError("Error reading data from radio")
+
+ return data
+
+
+def _send(radio, data):
+ """Send data to the radio device"""
+
+ try:
+ for byte in data:
+ radio.pipe.write(byte)
+ # Some OS (mainly Linux ones) are too fast on the serial and
+ # get the MCU inside the radio stuck in the early stages, this
+ # hits some models more than others.
+ #
+ # To cope with that we introduce a delay on the writes.
+ # Many option have been tested (delaying only after error occures,
+ # after short reads, only for linux, ...)
+ # Finally, a static delay was chosen as simplest of all solutions
+ # (Michael Wagner, OE4AMW)
+ # (for details, see issue 3993)
+ sleep(0.002)
+
+ # DEBUG
+ if debug is True:
+ LOG.debug("==> (%d) bytes:\n\n%s" %
+ (len(data), util.hexprint(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 = "\x06" + struct.pack(">BHB", ord(cmd), addr, length)
+ # add the data if set
+ if len(data) != 0:
+ frame += data
+
+ return frame
+
+
+def _recv(radio, addr):
+ """Get data from the radio all at once to lower syscalls load"""
+
+ # Get the full 69 bytes at a time to reduce load
+ # 1 byte ACK + 4 bytes header + 64 bytes of data (BLOCK_SIZE)
+
+ # get the whole block
+ block = _rawrecv(radio, BLOCK_SIZE + 5)
+
+ # basic check
+ if len(block) < (BLOCK_SIZE + 5):
+ raise errors.RadioError("Short read of the block 0x%04x" % addr)
+
+ # checking for the ack
+ if block[0] != ACK_CMD:
+ raise errors.RadioError("Bad ack from radio in block 0x%04x" % addr)
+
+ # header validation
+ c, a, l = struct.unpack(">BHB", block[1:5])
+ if a != addr or l != BLOCK_SIZE or c != ord("X"):
+ LOG.debug("Invalid header for block 0x%04x" % addr)
+ LOG.debug("CMD: %s ADDR: %04x SIZE: %02x" % (c, a, l))
+ raise errors.RadioError("Invalid header for block 0x%04x:" % addr)
+
+ # return the data
+ return block[5:]
+
+
+def _start_clone_mode(radio, status):
+ """Put the radio in clone mode and get the ident string, 3 tries"""
+
+ # cleaning the serial buffer
+ _clean_buffer(radio)
+
+ # prep the data to show in the UI
+ status.cur = 0
+ status.msg = "Identifying the radio..."
+ status.max = 3
+ radio.status_fn(status)
+
+ try:
+ for a in range(0, status.max):
+ # Update the UI
+ status.cur = a + 1
+ radio.status_fn(status)
+
+ # send the magic word
+ _send(radio, radio._magic)
+
+ # Now you get a x06 of ACK if all goes well
+ ack = radio.pipe.read(1)
+
+ if ack == "\x06":
+ # DEBUG
+ LOG.info("Magic ACK received")
+ status.cur = status.max
+ radio.status_fn(status)
+
+ return True
+
+ return False
+
+ except errors.RadioError:
+ raise
+ except Exception, e:
+ raise errors.RadioError("Error sending Magic to radio:\n%s" % e)
+
+
+def _do_ident(radio, status, upload=False):
+ """Put the radio in PROGRAM mode & identify it"""
+ # set the serial discipline
+ radio.pipe.baudrate = 9600
+ radio.pipe.parity = "N"
+
+ # open the radio into program mode
+ if _start_clone_mode(radio, status) is False:
+ msg = "Radio did not enter clone mode"
+ # warning about old versions of QYT KT8900
+ if radio.MODEL == "KT8900":
+ msg += ". You may want to try it as a WACCOM MINI-8900, there is a"
+ msg += " known variant of this radios that is a clone of it."
+ raise errors.RadioError(msg)
+
+ # Ok, get the ident string
+ ident = _rawrecv(radio, 49)
+
+ # basic check for the ident
+ if len(ident) != 49:
+ raise errors.RadioError("Radio send a short ident block.")
+
+ # check if ident is OK
+ itis = False
+ for fp in radio._fileid:
+ if fp in ident:
+ # got it!
+ itis = True
+ # checking if we are dealing with a Gen 3 BTECH
+ if radio.VENDOR == "BTECH" and fp in BTECH3:
+ radio.btech3 = True
+
+ break
+
+ if itis is False:
+ LOG.debug("Incorrect model ID, got this:\n\n" + util.hexprint(ident))
+ raise errors.RadioError("Radio identification failed.")
+
+ # some radios needs a extra read and check for a code on it, this ones
+ # has the check value in the _id2 var, others simply False
+ if radio._id2 is not False:
+ # lower the timeout here as this radios are reseting due to timeout
+ radio.pipe.timeout = 0.05
+
+ # query & receive the extra ID
+ _send(radio, _make_frame("S", 0x3DF0, 16))
+ id2 = _rawrecv(radio, 21)
+
+ # WARNING !!!!!!
+ # different radios send a response with a different amount of data
+ # it seems that it's padded with \xff, \x20 and some times with \x00
+ # we just care about the first 16, our magic string is in there
+ if len(id2) < 16:
+ raise errors.RadioError("The extra ID is short, aborting.")
+
+ # ok, the correct string must be in the received data
+ if radio._id2 not in id2:
+ LOG.debug("Full *BAD* extra ID on the %s is: \n%s" %
+ (radio.MODEL, util.hexprint(id2)))
+ raise errors.RadioError("The extra ID is wrong, aborting.")
+
+ # this radios need a extra request/answer here on the upload
+ # the amount of data received depends of the radio type
+ #
+ # also the first block of TX must no have the ACK at the beginning
+ # see _upload for this.
+ if upload is True:
+ # send an ACK
+ _send(radio, ACK_CMD)
+
+ # the amount of data depend on the radio, so far we have two radios
+ # reading two bytes with an ACK at the end and just ONE with just
+ # one byte (QYT KT8900)
+ # the JT-6188 appears a clone of the last, but reads TWO bytes.
+ #
+ # we will read two bytes with a custom timeout to not penalize the
+ # users for this.
+ #
+ # we just check for a response and last byte being a ACK, that is
+ # the common stone for all radios (3 so far)
+ ack = _rawrecv(radio, 2)
+
+ # checking
+ if len(ack) == 0 or ack[-1:] != ACK_CMD:
+ raise errors.RadioError("Radio didn't ACK the upload")
+
+ # restore the default serial timeout
+ radio.pipe.timeout = STIMEOUT
+
+ # DEBUG
+ LOG.info("Positive ident, this is a %s %s" % (radio.VENDOR, radio.MODEL))
+
+ return True
+
+
+def _download(radio):
+ """Get the memory map"""
+
+ # UI progress
+ status = chirp_common.Status()
+
+ # put radio in program mode and identify it
+ _do_ident(radio, status)
+
+ # the models that doesn't have the extra ID have to make a dummy read here
+ if radio._id2 is False:
+ _send(radio, _make_frame("S", 0, BLOCK_SIZE))
+ discard = _rawrecv(radio, BLOCK_SIZE + 5)
+
+ if debug is True:
+ LOG.info("Dummy first block read done, got this:\n\n %s",
+ util.hexprint(discard))
+
+ # reset the progress bar in the UI
+ status.max = MEM_SIZE / BLOCK_SIZE
+ status.msg = "Cloning from radio..."
+ status.cur = 0
+ radio.status_fn(status)
+
+ # cleaning the serial buffer
+ _clean_buffer(radio)
+
+ data = ""
+ for addr in range(0, MEM_SIZE, BLOCK_SIZE):
+ # sending the read request
+ _send(radio, _make_frame("S", addr, BLOCK_SIZE))
+
+ # read
+ d = _recv(radio, addr)
+
+ # aggregate the data
+ data += d
+
+ # UI Update
+ status.cur = addr / BLOCK_SIZE
+ status.msg = "Cloning from radio..."
+ radio.status_fn(status)
+
+ return data
+
+
+def _upload(radio):
+ """Upload procedure"""
+
+ # The UPLOAD mem is restricted to lower than 0x3100,
+ # so we will overide that here localy
+ MEM_SIZE = 0x3100
+
+ # UI progress
+ status = chirp_common.Status()
+
+ # put radio in program mode and identify it
+ _do_ident(radio, status, True)
+
+ # get the data to upload to radio
+ data = radio.get_mmap()
+
+ # Reset the UI progress
+ status.max = MEM_SIZE / TX_BLOCK_SIZE
+ status.cur = 0
+ status.msg = "Cloning to radio..."
+ radio.status_fn(status)
+
+ # the radios that doesn't have the extra ID 'may' do a dummy write, I found
+ # that leveraging the bad ACK and NOT doing the dummy write is ok, as the
+ # dummy write is accepted (it actually writes to the mem!) by the radio.
+
+ # cleaning the serial buffer
+ _clean_buffer(radio)
+
+ # the fun start here
+ for addr in range(0, MEM_SIZE, TX_BLOCK_SIZE):
+ # getting the block of data to send
+ d = data[addr:addr + TX_BLOCK_SIZE]
+
+ # build the frame to send
+ frame = _make_frame("X", addr, TX_BLOCK_SIZE, d)
+
+ # first block must not send the ACK at the beginning for the
+ # ones that has the extra id, since this have to do a extra step
+ if addr == 0 and radio._id2 is not False:
+ frame = frame[1:]
+
+ # send the frame
+ _send(radio, frame)
+
+ # receiving the response
+ ack = _rawrecv(radio, 1)
+
+ # basic check
+ if len(ack) != 1:
+ raise errors.RadioError("No ACK when writing block 0x%04x" % addr)
+
+ if not ack in "\x06\x05":
+ raise errors.RadioError("Bad ACK writing block 0x%04x:" % addr)
+
+ # UI Update
+ status.cur = addr / TX_BLOCK_SIZE
+ status.msg = "Cloning to radio..."
+ radio.status_fn(status)
+
+
+def model_match(cls, data):
+ """Match the opened/downloaded image to the correct version"""
+ rid = data[0x3f70:0x3f76]
+
+ if rid in cls._fileid:
+ return True
+
+ return False
+
+
+def _decode_ranges(low, high):
+ """Unpack the data in the ranges zones in the memmap and return
+ a tuple with the integer corresponding to the Mhz it means"""
+ ilow = int(low[0]) * 100 + int(low[1]) * 10 + int(low[2])
+ ihigh = int(high[0]) * 100 + int(high[1]) * 10 + int(high[2])
+ ilow *= 1000000
+ ihigh *= 1000000
+
+ return (ilow, ihigh)
+
+
+def _split(rf, f1, f2):
+ """Returns False if the two freqs are in the same band (no split)
+ or True otherwise"""
+
+ # determine if the two freqs are in the same band
+ for low, high in rf.valid_bands:
+ if f1 >= low and f1 <= high and \
+ f2 >= low and f2 <= high:
+ # if the two freqs are on the same Band this is not a split
+ return False
+
+ # if you get here is because the freq pairs are split
+ return False
+
+
+class BTechMobileCommon(chirp_common.CloneModeRadio,
+ chirp_common.ExperimentalRadio):
+ """BTECH's UV-5001 and alike radios"""
+ VENDOR = "BTECH"
+ MODEL = ""
+ IDENT = ""
+ BANDS = 2
+ COLOR_LCD = False
+ NAME_LENGTH = 6
+ _power_levels = [chirp_common.PowerLevel("High", watts=25),
+ chirp_common.PowerLevel("Low", watts=10)]
+ _vhf_range = (130000000, 180000000)
+ _220_range = (200000000, 271000000)
+ _uhf_range = (400000000, 521000000)
+ _350_range = (350000000, 391000000)
+ _upper = 199
+ _magic = MSTRING
+ _fileid = None
+ _id2 = False
+ btech3 = False
+
+ @classmethod
+ def get_prompts(cls):
+ rp = chirp_common.RadioPrompts()
+ rp.experimental = \
+ ('This driver is experimental.\n'
+ '\n'
+ 'Please keep a copy of your memories with the original software '
+ 'if you treasure them, this driver is new and may contain'
+ ' bugs.\n'
+ '\n'
+ )
+ rp.pre_download = _(dedent("""\
+ Follow these instructions to download your info:
+
+ 1 - Turn off your radio
+ 2 - Connect your interface cable
+ 3 - Turn on your radio
+ 4 - Do the download of your radio data
+
+ """))
+ rp.pre_upload = _(dedent("""\
+ Follow these instructions to upload your info:
+
+ 1 - Turn off your radio
+ 2 - Connect your interface cable
+ 3 - Turn on your radio
+ 4 - Do the upload of your radio data
+
+ """))
+ return rp
+
+ def get_features(self):
+ """Get the radio's features"""
+
+ # we will use the following var as global
+ global POWER_LEVELS
+
+ rf = chirp_common.RadioFeatures()
+ rf.has_settings = True
+ rf.has_bank = False
+ rf.has_tuning_step = False
+ rf.can_odd_split = True
+ 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.valid_modes = MODES
+ rf.valid_characters = VALID_CHARS
+ rf.valid_name_length = self.NAME_LENGTH
+ rf.valid_duplexes = ["", "-", "+", "split", "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 = SKIP_VALUES
+ rf.valid_dtcs_codes = DTCS
+ rf.memory_bounds = (0, self._upper)
+
+ # power levels
+ POWER_LEVELS = self._power_levels
+ rf.valid_power_levels = POWER_LEVELS
+
+ # normal dual bands
+ rf.valid_bands = [self._vhf_range, self._uhf_range]
+
+ # 220 band
+ if self.BANDS == 3 or self.BANDS == 4:
+ rf.valid_bands.append(self._220_range)
+
+ # 350 band
+ if self.BANDS == 4:
+ rf.valid_bands.append(self._350_range)
+
+ return rf
+
+ def sync_in(self):
+ """Download from radio"""
+ data = _download(self)
+ self._mmap = memmap.MemoryMap(data)
+ self.process_mmap()
+
+ def sync_out(self):
+ """Upload to radio"""
+ try:
+ _upload(self)
+ except errors.RadioError:
+ raise
+ except Exception, e:
+ raise errors.RadioError("Error: %s" % e)
+
+ def get_raw_memory(self, number):
+ return repr(self._memobj.memory[number])
+
+ def _decode_tone(self, val):
+ """Parse the tone data to decode from mem, it returns:
+ Mode (''|DTCS|Tone), Value (None|###), Polarity (None,N,R)"""
+ pol = None
+
+ if val in [0, 65535]:
+ return '', None, None
+ elif val > 0x0258:
+ a = val / 10.0
+ return 'Tone', a, pol
+ else:
+ if val > 0x69:
+ index = val - 0x6A
+ pol = "R"
+ else:
+ index = val - 1
+ pol = "N"
+
+ tone = DTCS[index]
+ return 'DTCS', tone, pol
+
+ def _encode_tone(self, memval, mode, val, pol):
+ """Parse the tone data to encode from UI to mem"""
+ if mode == '' or mode is None:
+ memval.set_raw("\x00\x00")
+ elif mode == 'Tone':
+ memval.set_value(val * 10)
+ elif mode == 'DTCS':
+ # detect the index in the DTCS list
+ try:
+ index = DTCS.index(val)
+ if pol == "N":
+ index += 1
+ else:
+ index += 0x6A
+ memval.set_value(index)
+ except:
+ msg = "Digital Tone '%d' is not supported" % value
+ LOG.error(msg)
+ raise errors.RadioError(msg)
+ else:
+ msg = "Internal error: invalid mode '%s'" % mode
+ LOG.error(msg)
+ raise errors.InvalidDataError(msg)
+
+ def get_memory(self, number):
+ """Get the mem representation from the radio image"""
+ _mem = self._memobj.memory[number]
+ _names = self._memobj.names[number]
+
+ # Create a high-level memory object to return to the UI
+ mem = chirp_common.Memory()
+
+ # Memory number
+ mem.number = number
+
+ if _mem.get_raw()[0] == "\xFF":
+ mem.empty = True
+ return mem
+
+ # Freq and offset
+ mem.freq = int(_mem.rxfreq) * 10
+ # tx freq can be blank
+ if _mem.get_raw()[4] == "\xFF":
+ # TX freq not set
+ mem.offset = 0
+ mem.duplex = "off"
+ else:
+ # TX freq set
+ offset = (int(_mem.txfreq) * 10) - mem.freq
+ if offset != 0:
+ if _split(self.get_features(), mem.freq, int(_mem.txfreq) * 10):
+ mem.duplex = "split"
+ mem.offset = int(_mem.txfreq) * 10
+ elif offset < 0:
+ mem.offset = abs(offset)
+ mem.duplex = "-"
+ elif offset > 0:
+ mem.offset = offset
+ mem.duplex = "+"
+ else:
+ mem.offset = 0
+
+ # name TAG of the channel
+ mem.name = str(_names.name).rstrip("\xFF").replace("\xFF", " ")
+
+ # power
+ mem.power = POWER_LEVELS[int(_mem.power)]
+
+ # wide/narrow
+ mem.mode = MODES[int(_mem.wide)]
+
+ # skip
+ mem.skip = SKIP_VALUES[_mem.add]
+
+ # tone data
+ rxtone = txtone = None
+ txtone = self._decode_tone(_mem.txtone)
+ rxtone = self._decode_tone(_mem.rxtone)
+ chirp_common.split_tone_decode(mem, txtone, rxtone)
+
+ # Extra
+ mem.extra = RadioSettingGroup("extra", "Extra")
+
+ scramble = RadioSetting("scramble", "Scramble",
+ RadioSettingValueBoolean(bool(
+ _mem.scramble)))
+ mem.extra.append(scramble)
+
+ bcl = RadioSetting("bcl", "Busy channel lockout",
+ RadioSettingValueBoolean(bool(_mem.bcl)))
+ mem.extra.append(bcl)
+
+ pttid = RadioSetting("pttid", "PTT ID",
+ RadioSettingValueList(PTTID_LIST,
+ PTTID_LIST[_mem.pttid]))
+ mem.extra.append(pttid)
+
+ # validating scode
+ scode = _mem.scode if _mem.scode != 15 else 0
+ pttidcode = RadioSetting("scode", "PTT ID signal code",
+ RadioSettingValueList(
+ PTTIDCODE_LIST,
+ PTTIDCODE_LIST[scode]))
+ mem.extra.append(pttidcode)
+
+ optsig = RadioSetting("optsig", "Optional signaling",
+ RadioSettingValueList(
+ OPTSIG_LIST,
+ OPTSIG_LIST[_mem.optsig]))
+ mem.extra.append(optsig)
+
+ spmute = RadioSetting("spmute", "Speaker mute",
+ RadioSettingValueList(
+ SPMUTE_LIST,
+ SPMUTE_LIST[_mem.spmute]))
+ mem.extra.append(spmute)
+
+ return mem
+
+ def set_memory(self, mem):
+ """Set the memory data in the eeprom img from the UI"""
+ # get the eprom representation of this channel
+ _mem = self._memobj.memory[mem.number]
+ _names = self._memobj.names[mem.number]
+
+ mem_was_empty = False
+ # same method as used in get_memory for determining if mem is empty
+ # doing this BEFORE overwriting it with new values ...
+ if _mem.get_raw()[0] == "\xFF":
+ LOG.debug("This mem was empty before")
+ mem_was_empty = True
+
+ # if empty memmory
+ if mem.empty:
+ # the channel itself
+ _mem.set_raw("\xFF" * 16)
+ # the name tag
+ _names.set_raw("\xFF" * 16)
+ return
+
+ # frequency
+ _mem.rxfreq = mem.freq / 10
+
+ # duplex
+ if mem.duplex == "+":
+ _mem.txfreq = (mem.freq + mem.offset) / 10
+ elif mem.duplex == "-":
+ _mem.txfreq = (mem.freq - mem.offset) / 10
+ elif mem.duplex == "off":
+ for i in _mem.txfreq:
+ i.set_raw("\xFF")
+ elif mem.duplex == "split":
+ _mem.txfreq = mem.offset / 10
+ else:
+ _mem.txfreq = mem.freq / 10
+
+ # tone data
+ ((txmode, txtone, txpol), (rxmode, rxtone, rxpol)) = \
+ chirp_common.split_tone_encode(mem)
+ self._encode_tone(_mem.txtone, txmode, txtone, txpol)
+ self._encode_tone(_mem.rxtone, rxmode, rxtone, rxpol)
+
+ # name TAG of the channel
+ if len(mem.name) < self.NAME_LENGTH:
+ # we must pad to self.NAME_LENGTH chars, " " = "\xFF"
+ mem.name = str(mem.name).ljust(self.NAME_LENGTH, " ")
+ _names.name = str(mem.name).replace(" ", "\xFF")
+
+ # power, # default power level is high
+ _mem.power = 0 if mem.power is None else POWER_LEVELS.index(mem.power)
+
+ # wide/narrow
+ _mem.wide = MODES.index(mem.mode)
+
+ # scan add property
+ _mem.add = SKIP_VALUES.index(mem.skip)
+
+ # reseting unknowns, this have to be set by hand
+ _mem.unknown0 = 0
+ _mem.unknown1 = 0
+ _mem.unknown2 = 0
+ _mem.unknown3 = 0
+ _mem.unknown4 = 0
+ _mem.unknown5 = 0
+ _mem.unknown6 = 0
+
+ # extra settings
+ if len(mem.extra) > 0:
+ # there are setting, parse
+ LOG.debug("Extra-Setting supplied. Setting them.")
+ for setting in mem.extra:
+ setattr(_mem, setting.get_name(), setting.value)
+ else:
+ if mem.empty:
+ LOG.debug("New mem is empty.")
+ else:
+ LOG.debug("New mem is NOT empty")
+ # set extra-settings to default ONLY when apreviously empty or
+ # deleted memory was edited to prevent errors such as #4121
+ if mem_was_empty :
+ LOG.debug("old mem was empty. Setting default for extras.")
+ _mem.spmute = 0
+ _mem.optsig = 0
+ _mem.scramble = 0
+ _mem.bcl = 0
+ _mem.pttid = 0
+ _mem.scode = 0
+
+ return mem
+
+ def get_settings(self):
+ """Translate the bit in the mem_struct into settings in the UI"""
+ _mem = self._memobj
+ basic = RadioSettingGroup("basic", "Basic Settings")
+ advanced = RadioSettingGroup("advanced", "Advanced Settings")
+ other = RadioSettingGroup("other", "Other Settings")
+ work = RadioSettingGroup("work", "Work Mode Settings")
+ top = RadioSettings(basic, advanced, other, work)
+
+ # Basic
+ if self.COLOR_LCD:
+ tmr = RadioSetting("settings.tmr", "Transceiver multi-receive",
+ RadioSettingValueList(
+ LIST_TMR,
+ LIST_TMR[_mem.settings.tmr]))
+ basic.append(tmr)
+ else:
+ tdr = RadioSetting("settings.tdr", "Transceiver dual receive",
+ RadioSettingValueBoolean(_mem.settings.tdr))
+ basic.append(tdr)
+
+ sql = RadioSetting("settings.sql", "Squelch level",
+ RadioSettingValueInteger(0, 9, _mem.settings.sql))
+ basic.append(sql)
+
+ tot = RadioSetting("settings.tot", "Time out timer",
+ RadioSettingValueList(
+ LIST_TOT,
+ LIST_TOT[_mem.settings.tot]))
+ basic.append(tot)
+
+ if self.VENDOR == "BTECH" or self.COLOR_LCD:
+ apo = RadioSetting("settings.apo", "Auto power off timer",
+ RadioSettingValueList(
+ LIST_APO,
+ LIST_APO[_mem.settings.apo]))
+ basic.append(apo)
+ else:
+ toa = RadioSetting("settings.apo", "Time out alert timer",
+ RadioSettingValueList(
+ LIST_OFF1TO10,
+ LIST_OFF1TO10[_mem.settings.apo]))
+ basic.append(toa)
+
+ abr = RadioSetting("settings.abr", "Backlight timer",
+ RadioSettingValueList(
+ LIST_OFF1TO50,
+ LIST_OFF1TO50[_mem.settings.abr]))
+ basic.append(abr)
+
+ beep = RadioSetting("settings.beep", "Key beep",
+ RadioSettingValueBoolean(_mem.settings.beep))
+ basic.append(beep)
+
+ dtmfst = RadioSetting("settings.dtmfst", "DTMF side tone",
+ RadioSettingValueList(
+ LIST_DTMFST,
+ LIST_DTMFST[_mem.settings.dtmfst]))
+ basic.append(dtmfst)
+
+ if not self.COLOR_LCD:
+ prisc = RadioSetting("settings.prisc", "Priority scan",
+ RadioSettingValueBoolean(
+ _mem.settings.prisc))
+ basic.append(prisc)
+
+ prich = RadioSetting("settings.prich", "Priority channel",
+ RadioSettingValueInteger(0, 199,
+ _mem.settings.prich))
+ basic.append(prich)
+
+ screv = RadioSetting("settings.screv", "Scan resume method",
+ RadioSettingValueList(
+ LIST_SCREV,
+ LIST_SCREV[_mem.settings.screv]))
+ basic.append(screv)
+
+ pttlt = RadioSetting("settings.pttlt", "PTT transmit delay",
+ RadioSettingValueInteger(0, 30,
+ _mem.settings.pttlt))
+ basic.append(pttlt)
+
+ emctp = RadioSetting("settings.emctp", "Alarm mode",
+ RadioSettingValueList(
+ LIST_EMCTP,
+ LIST_EMCTP[_mem.settings.emctp]))
+ basic.append(emctp)
+
+ emcch = RadioSetting("settings.emcch", "Alarm channel",
+ RadioSettingValueInteger(0, 199,
+ _mem.settings.emcch))
+ basic.append(emcch)
+
+ if self.COLOR_LCD:
+ if _mem.settings.sigbp > 0x01:
+ val = 0x00
+ else:
+ val = _mem.settings.sigbp
+ sigbp = RadioSetting("settings.sigbp", "Roger beep",
+ RadioSettingValueBoolean(val))
+ basic.append(sigbp)
+ else:
+ ringt = RadioSetting("settings.ringt", "Ring time",
+ RadioSettingValueList(
+ LIST_OFF1TO9,
+ LIST_OFF1TO9[_mem.settings.ringt]))
+ basic.append(ringt)
+
+ camdf = RadioSetting("settings.camdf", "Display mode A",
+ RadioSettingValueList(
+ LIST_MDF,
+ LIST_MDF[_mem.settings.camdf]))
+ basic.append(camdf)
+
+ cbmdf = RadioSetting("settings.cbmdf", "Display mode B",
+ RadioSettingValueList(
+ LIST_MDF,
+ LIST_MDF[_mem.settings.cbmdf]))
+ basic.append(cbmdf)
+
+ if self.COLOR_LCD:
+ ccmdf = RadioSetting("settings.ccmdf", "Display mode C",
+ RadioSettingValueList(
+ LIST_MDF,
+ LIST_MDF[_mem.settings.ccmdf]))
+ basic.append(ccmdf)
+
+ cdmdf = RadioSetting("settings.cdmdf", "Display mode D",
+ RadioSettingValueList(
+ LIST_MDF,
+ LIST_MDF[_mem.settings.cdmdf]))
+ basic.append(cdmdf)
+
+ langua = RadioSetting("settings.langua", "Language",
+ RadioSettingValueList(
+ LIST_LANGUA,
+ LIST_LANGUA[_mem.settings.langua]))
+ basic.append(langua)
+
+ if self.VENDOR == "BTECH":
+ sync = RadioSetting("settings.sync", "A/B channel sync",
+ RadioSettingValueBoolean(
+ _mem.settings.sync))
+ basic.append(sync)
+ else:
+ autolk = RadioSetting("settings.sync", "Auto keylock",
+ RadioSettingValueBoolean(
+ _mem.settings.sync))
+ basic.append(autolk)
+
+ if not self.COLOR_LCD:
+ ponmsg = RadioSetting("settings.ponmsg", "Power-on message",
+ RadioSettingValueList(
+ LIST_PONMSG,
+ LIST_PONMSG[_mem.settings.ponmsg]))
+ basic.append(ponmsg)
+
+ if self.COLOR_LCD:
+ mainfc = RadioSetting("settings.mainfc",
+ "Main LCD foreground color",
+ RadioSettingValueList(
+ LIST_COLOR8,
+ LIST_COLOR8[_mem.settings.mainfc]))
+ basic.append(mainfc)
+
+ mainbc = RadioSetting("settings.mainbc",
+ "Main LCD background color",
+ RadioSettingValueList(
+ LIST_COLOR8,
+ LIST_COLOR8[_mem.settings.mainbc]))
+ basic.append(mainbc)
+
+ menufc = RadioSetting("settings.menufc", "Menu foreground color",
+ RadioSettingValueList(
+ LIST_COLOR8,
+ LIST_COLOR8[_mem.settings.menufc]))
+ basic.append(menufc)
+
+ menubc = RadioSetting("settings.menubc", "Menu background color",
+ RadioSettingValueList(
+ LIST_COLOR8,
+ LIST_COLOR8[_mem.settings.menubc]))
+ basic.append(menubc)
+
+ stafc = RadioSetting("settings.stafc",
+ "Top status foreground color",
+ RadioSettingValueList(
+ LIST_COLOR8,
+ LIST_COLOR8[_mem.settings.stafc]))
+ basic.append(stafc)
+
+ stabc = RadioSetting("settings.stabc",
+ "Top status background color",
+ RadioSettingValueList(
+ LIST_COLOR8,
+ LIST_COLOR8[_mem.settings.stabc]))
+ basic.append(stabc)
+
+ sigfc = RadioSetting("settings.sigfc",
+ "Bottom status foreground color",
+ RadioSettingValueList(
+ LIST_COLOR8,
+ LIST_COLOR8[_mem.settings.sigfc]))
+ basic.append(sigfc)
+
+ sigbc = RadioSetting("settings.sigbc",
+ "Bottom status background color",
+ RadioSettingValueList(
+ LIST_COLOR8,
+ LIST_COLOR8[_mem.settings.sigbc]))
+ basic.append(sigbc)
+
+ rxfc = RadioSetting("settings.rxfc", "Receiving character color",
+ RadioSettingValueList(
+ LIST_COLOR8,
+ LIST_COLOR8[_mem.settings.rxfc]))
+ basic.append(rxfc)
+
+ txfc = RadioSetting("settings.txfc",
+ "Transmitting character color",
+ RadioSettingValueList(
+ LIST_COLOR8,
+ LIST_COLOR8[_mem.settings.txfc]))
+ basic.append(txfc)
+
+ txdisp = RadioSetting("settings.txdisp",
+ "Transmitting status display",
+ RadioSettingValueList(
+ LIST_TXDISP,
+ LIST_TXDISP[_mem.settings.txdisp]))
+ basic.append(txdisp)
+ else:
+ wtled = RadioSetting("settings.wtled", "Standby backlight Color",
+ RadioSettingValueList(
+ LIST_COLOR4,
+ LIST_COLOR4[_mem.settings.wtled]))
+ basic.append(wtled)
+
+ rxled = RadioSetting("settings.rxled", "RX backlight Color",
+ RadioSettingValueList(
+ LIST_COLOR4,
+ LIST_COLOR4[_mem.settings.rxled]))
+ basic.append(rxled)
+
+ txled = RadioSetting("settings.txled", "TX backlight Color",
+ RadioSettingValueList(
+ LIST_COLOR4,
+ LIST_COLOR4[_mem.settings.txled]))
+ basic.append(txled)
+
+ anil = RadioSetting("settings.anil", "ANI length",
+ RadioSettingValueList(
+ LIST_ANIL,
+ LIST_ANIL[_mem.settings.anil]))
+ basic.append(anil)
+
+ reps = RadioSetting("settings.reps", "Relay signal (tone burst)",
+ RadioSettingValueList(
+ LIST_REPS,
+ LIST_REPS[_mem.settings.reps]))
+ basic.append(reps)
+
+ repm = RadioSetting("settings.repm", "Relay condition",
+ RadioSettingValueList(
+ LIST_REPM,
+ LIST_REPM[_mem.settings.repm]))
+ basic.append(repm)
+
+ if self.VENDOR == "BTECH" or self.COLOR_LCD:
+ if self.COLOR_LCD:
+ tmrmr = RadioSetting("settings.tmrmr", "TMR return time",
+ RadioSettingValueList(
+ LIST_OFF1TO50,
+ LIST_OFF1TO50[_mem.settings.tmrmr]))
+ basic.append(tmrmr)
+ else:
+ tdrab = RadioSetting("settings.tdrab", "TDR return time",
+ RadioSettingValueList(
+ LIST_OFF1TO50,
+ LIST_OFF1TO50[_mem.settings.tdrab]))
+ basic.append(tdrab)
+
+ ste = RadioSetting("settings.ste", "Squelch tail eliminate",
+ RadioSettingValueBoolean(_mem.settings.ste))
+ basic.append(ste)
+
+ rpste = RadioSetting("settings.rpste", "Repeater STE",
+ RadioSettingValueList(
+ LIST_OFF1TO9,
+ LIST_OFF1TO9[_mem.settings.rpste]))
+ basic.append(rpste)
+
+ rptdl = RadioSetting("settings.rptdl", "Repeater STE delay",
+ RadioSettingValueList(
+ LIST_RPTDL,
+ LIST_RPTDL[_mem.settings.rptdl]))
+ basic.append(rptdl)
+
+ if str(_mem.fingerprint.fp) in BTECH3:
+ mgain = RadioSetting("settings.mgain", "Mic gain",
+ RadioSettingValueInteger(0, 120,
+ _mem.settings.mgain))
+ basic.append(mgain)
+
+ if str(_mem.fingerprint.fp) in BTECH3 or self.COLOR_LCD:
+ dtmfg = RadioSetting("settings.dtmfg", "DTMF gain",
+ RadioSettingValueInteger(0, 60,
+ _mem.settings.dtmfg))
+ basic.append(dtmfg)
+
+ # Advanced
+ def _filter(name):
+ filtered = ""
+ for char in str(name):
+ if char in VALID_CHARS:
+ filtered += char
+ else:
+ filtered += " "
+ return filtered
+
+ _msg = self._memobj.poweron_msg
+ if self.COLOR_LCD:
+ line1 = RadioSetting("poweron_msg.line1",
+ "Power-on message line 1",
+ RadioSettingValueString(0, 8, _filter(
+ _msg.line1)))
+ advanced.append(line1)
+ line2 = RadioSetting("poweron_msg.line2",
+ "Power-on message line 2",
+ RadioSettingValueString(0, 8, _filter(
+ _msg.line2)))
+ advanced.append(line2)
+ line3 = RadioSetting("poweron_msg.line3",
+ "Power-on message line 3",
+ RadioSettingValueString(0, 8, _filter(
+ _msg.line3)))
+ advanced.append(line3)
+ line4 = RadioSetting("poweron_msg.line4",
+ "Power-on message line 4",
+ RadioSettingValueString(0, 8, _filter(
+ _msg.line4)))
+ advanced.append(line4)
+ line5 = RadioSetting("poweron_msg.line5",
+ "Power-on message line 5",
+ RadioSettingValueString(0, 8, _filter(
+ _msg.line5)))
+ advanced.append(line5)
+ line6 = RadioSetting("poweron_msg.line6",
+ "Power-on message line 6",
+ RadioSettingValueString(0, 8, _filter(
+ _msg.line6)))
+ advanced.append(line6)
+ line7 = RadioSetting("poweron_msg.line7",
+ "Power-on message line 7",
+ RadioSettingValueString(0, 8, _filter(
+ _msg.line7)))
+ advanced.append(line7)
+ line8 = RadioSetting("poweron_msg.line8", "Static message",
+ RadioSettingValueString(0, 8, _filter(
+ _msg.line8)))
+ advanced.append(line8)
+ else:
+ line1 = RadioSetting("poweron_msg.line1",
+ "Power-on message line 1",
+ RadioSettingValueString(0, 6, _filter(
+ _msg.line1)))
+ advanced.append(line1)
+ line2 = RadioSetting("poweron_msg.line2",
+ "Power-on message line 2",
+ RadioSettingValueString(0, 6, _filter(
+ _msg.line2)))
+ advanced.append(line2)
+
+ if self.MODEL in ("UV-2501", "UV-5001"):
+ vfomren = RadioSetting("settings2.vfomren", "VFO/MR switching",
+ RadioSettingValueBoolean(
+ _mem.settings2.vfomren))
+ advanced.append(vfomren)
+
+ reseten = RadioSetting("settings2.reseten", "RESET",
+ RadioSettingValueBoolean(
+ _mem.settings2.reseten))
+ advanced.append(reseten)
+
+ menuen = RadioSetting("settings2.menuen", "Menu",
+ RadioSettingValueBoolean(
+ _mem.settings2.menuen))
+ advanced.append(menuen)
+
+ # Other
+ def convert_bytes_to_limit(bytes):
+ limit = ""
+ for byte in bytes:
+ if byte < 10:
+ limit += chr(byte + 0x30)
+ else:
+ break
+ return limit
+
+ if self.MODEL in ["UV-2501+220", "KT8900R"]:
+ _ranges = self._memobj.ranges220
+ ranges = "ranges220"
+ else:
+ _ranges = self._memobj.ranges
+ ranges = "ranges"
+
+ _limit = convert_bytes_to_limit(_ranges.vhf_low)
+ val = RadioSettingValueString(0, 3, _limit)
+ val.set_mutable(False)
+ vhf_low = RadioSetting("%s.vhf_low" % ranges, "VHF low", val)
+ other.append(vhf_low)
+
+ _limit = convert_bytes_to_limit(_ranges.vhf_high)
+ val = RadioSettingValueString(0, 3, _limit)
+ val.set_mutable(False)
+ vhf_high = RadioSetting("%s.vhf_high" % ranges, "VHF high", val)
+ other.append(vhf_high)
+
+ if self.BANDS == 3 or self.BANDS == 4:
+ _limit = convert_bytes_to_limit(_ranges.vhf2_low)
+ val = RadioSettingValueString(0, 3, _limit)
+ val.set_mutable(False)
+ vhf2_low = RadioSetting("%s.vhf2_low" % ranges, "VHF2 low", val)
+ other.append(vhf2_low)
+
+ _limit = convert_bytes_to_limit(_ranges.vhf2_high)
+ val = RadioSettingValueString(0, 3, _limit)
+ val.set_mutable(False)
+ vhf2_high = RadioSetting("%s.vhf2_high" % ranges, "VHF2 high", val)
+ other.append(vhf2_high)
+
+ _limit = convert_bytes_to_limit(_ranges.uhf_low)
+ val = RadioSettingValueString(0, 3, _limit)
+ val.set_mutable(False)
+ uhf_low = RadioSetting("%s.uhf_low" % ranges, "UHF low", val)
+ other.append(uhf_low)
+
+ _limit = convert_bytes_to_limit(_ranges.uhf_high)
+ val = RadioSettingValueString(0, 3, _limit)
+ val.set_mutable(False)
+ uhf_high = RadioSetting("%s.uhf_high" % ranges, "UHF high", val)
+ other.append(uhf_high)
+
+ if self.BANDS == 4:
+ _limit = convert_bytes_to_limit(_ranges.uhf2_low)
+ val = RadioSettingValueString(0, 3, _limit)
+ val.set_mutable(False)
+ uhf2_low = RadioSetting("%s.uhf2_low" % ranges, "UHF2 low", val)
+ other.append(uhf2_low)
+
+ _limit = convert_bytes_to_limit(_ranges.uhf2_high)
+ val = RadioSettingValueString(0, 3, _limit)
+ val.set_mutable(False)
+ uhf2_high = RadioSetting("%s.uhf2_high" % ranges, "UHF2 high", val)
+ other.append(uhf2_high)
+
+ val = RadioSettingValueString(0, 6, _filter(_mem.fingerprint.fp))
+ val.set_mutable(False)
+ fp = RadioSetting("fingerprint.fp", "Fingerprint", val)
+ other.append(fp)
+
+
+ # Work
+ if self.COLOR_LCD:
+ dispab = RadioSetting("settings2.dispab", "Display",
+ RadioSettingValueList(
+ LIST_ABCD,
+ LIST_ABCD[_mem.settings2.dispab]))
+ work.append(dispab)
+ else:
+ dispab = RadioSetting("settings2.dispab", "Display",
+ RadioSettingValueList(
+ LIST_AB,
+ LIST_AB[_mem.settings2.dispab]))
+ work.append(dispab)
+
+ if self.COLOR_LCD:
+ vfomra = RadioSetting("settings2.vfomra", "VFO/MR A mode",
+ RadioSettingValueList(
+ LIST_VFOMR,
+ LIST_VFOMR[_mem.settings2.vfomra]))
+ work.append(vfomra)
+
+ vfomrb = RadioSetting("settings2.vfomrb", "VFO/MR B mode",
+ RadioSettingValueList(
+ LIST_VFOMR,
+ LIST_VFOMR[_mem.settings2.vfomrb]))
+ work.append(vfomrb)
+
+ vfomrc = RadioSetting("settings2.vfomrc", "VFO/MR C mode",
+ RadioSettingValueList(
+ LIST_VFOMR,
+ LIST_VFOMR[_mem.settings2.vfomrc]))
+ work.append(vfomrc)
+
+ vfomrd = RadioSetting("settings2.vfomrd", "VFO/MR D mode",
+ RadioSettingValueList(
+ LIST_VFOMR,
+ LIST_VFOMR[_mem.settings2.vfomrd]))
+ work.append(vfomrd)
+ else:
+ vfomr = RadioSetting("settings2.vfomr", "VFO/MR mode",
+ RadioSettingValueList(
+ LIST_VFOMR,
+ LIST_VFOMR[_mem.settings2.vfomr]))
+ work.append(vfomr)
+
+
+ keylock = RadioSetting("settings2.keylock", "Keypad lock",
+ RadioSettingValueBoolean(_mem.settings2.keylock))
+ work.append(keylock)
+
+ mrcha = RadioSetting("settings2.mrcha", "MR A channel",
+ RadioSettingValueInteger(0, 199,
+ _mem.settings2.mrcha))
+ work.append(mrcha)
+
+ mrchb = RadioSetting("settings2.mrchb", "MR B channel",
+ RadioSettingValueInteger(0, 199,
+ _mem.settings2.mrchb))
+ work.append(mrchb)
+
+ if self.COLOR_LCD:
+ mrchc = RadioSetting("settings2.mrchc", "MR C channel",
+ RadioSettingValueInteger(0, 199,
+ _mem.settings2.mrchc))
+ work.append(mrchc)
+
+ mrchd = RadioSetting("settings2.mrchd", "MR D channel",
+ RadioSettingValueInteger(0, 199,
+ _mem.settings2.mrchd))
+ work.append(mrchd)
+
+ def convert_bytes_to_freq(bytes):
+ real_freq = 0
+ for byte in bytes:
+ real_freq = (real_freq * 10) + byte
+ return chirp_common.format_freq(real_freq * 10)
+
+ def my_validate(value):
+ _vhf_lower = int(convert_bytes_to_limit(_ranges.vhf_low))
+ _vhf_upper = int(convert_bytes_to_limit(_ranges.vhf_high))
+ _uhf_lower = int(convert_bytes_to_limit(_ranges.uhf_low))
+ _uhf_upper = int(convert_bytes_to_limit(_ranges.uhf_high))
+ if self.BANDS == 3 or self.BANDS == 4:
+ _vhf2_lower = int(convert_bytes_to_limit(_ranges.vhf2_low))
+ _vhf2_upper = int(convert_bytes_to_limit(_ranges.vhf2_high))
+ if self.BANDS == 4:
+ _uhf2_lower = int(convert_bytes_to_limit(_ranges.uhf2_low))
+ _uhf2_upper = int(convert_bytes_to_limit(_ranges.uhf2_high))
+
+ value = chirp_common.parse_freq(value)
+ msg = ("Can't be less then %i.0000")
+ if value > 99000000 and value < _vhf_lower * 1000000:
+ raise InvalidValueError(msg % (_vhf_lower))
+ msg = ("Can't be betweeb %i.9975-%i.0000")
+ if self.BANDS == 2:
+ if (_vhf_upper + 1) * 1000000 <= value and \
+ value < _uhf_lower * 1000000:
+ raise InvalidValueError(msg % (_vhf_upper, _uhf_lower))
+ if self.BANDS == 3:
+ if (_vhf_upper + 1) * 1000000 <= value and \
+ value < _vhf2_lower * 1000000:
+ raise InvalidValueError(msg % (_vhf_upper, _vhf2_lower))
+ if (_vhf2_upper + 1) * 1000000 <= value and \
+ value < _uhf_lower * 1000000:
+ raise InvalidValueError(msg % (_vhf2_upper, _uhf_lower))
+ if self.BANDS == 4:
+ if (_vhf_upper + 1) * 1000000 <= value and \
+ value < _vhf2_lower * 1000000:
+ raise InvalidValueError(msg % (_vhf_upper, _vhf2_lower))
+ if (_vhf2_upper + 1) * 1000000 <= value and \
+ value < _uhf2_lower * 1000000:
+ raise InvalidValueError(msg % (_vhf2_upper, _uhf2_lower))
+ if (_uhf2_upper + 1) * 1000000 <= value and \
+ value < _uhf_lower * 1000000:
+ raise InvalidValueError(msg % (_uhf2_upper, _uhf_lower))
+ msg = ("Can't be greater then %i.9975")
+ if value > 99000000 and value >= _uhf_upper * 1000000:
+ raise InvalidValueError(msg % (_uhf_upper))
+ return chirp_common.format_freq(value)
+
+ def apply_freq(setting, obj):
+ value = chirp_common.parse_freq(str(setting.value)) / 10
+ for i in range(7, -1, -1):
+ obj.freq[i] = value % 10
+ value /= 10
+
+ val1a = RadioSettingValueString(0, 10, convert_bytes_to_freq(
+ _mem.vfo.a.freq))
+ val1a.set_validate_callback(my_validate)
+ vfoafreq = RadioSetting("vfo.a.freq", "VFO A frequency", val1a)
+ vfoafreq.set_apply_callback(apply_freq, _mem.vfo.a)
+ work.append(vfoafreq)
+
+ val1b = RadioSettingValueString(0, 10, convert_bytes_to_freq(
+ _mem.vfo.b.freq))
+ val1b.set_validate_callback(my_validate)
+ vfobfreq = RadioSetting("vfo.b.freq", "VFO B frequency", val1b)
+ vfobfreq.set_apply_callback(apply_freq, _mem.vfo.b)
+ work.append(vfobfreq)
+
+ if self.COLOR_LCD:
+ val1c = RadioSettingValueString(0, 10, convert_bytes_to_freq(
+ _mem.vfo.c.freq))
+ val1c.set_validate_callback(my_validate)
+ vfocfreq = RadioSetting("vfo.c.freq", "VFO C frequency", val1c)
+ vfocfreq.set_apply_callback(apply_freq, _mem.vfo.c)
+ work.append(vfocfreq)
+
+ val1d = RadioSettingValueString(0, 10, convert_bytes_to_freq(
+ _mem.vfo.d.freq))
+ val1d.set_validate_callback(my_validate)
+ vfodfreq = RadioSetting("vfo.d.freq", "VFO D frequency", val1d)
+ vfodfreq.set_apply_callback(apply_freq, _mem.vfo.d)
+ work.append(vfodfreq)
+
+ vfoashiftd = RadioSetting("vfo.a.shiftd", "VFO A shift",
+ RadioSettingValueList(
+ LIST_SHIFT,
+ LIST_SHIFT[_mem.vfo.a.shiftd]))
+ work.append(vfoashiftd)
+
+ vfobshiftd = RadioSetting("vfo.b.shiftd", "VFO B shift",
+ RadioSettingValueList(
+ LIST_SHIFT,
+ LIST_SHIFT[_mem.vfo.b.shiftd]))
+ work.append(vfobshiftd)
+
+ if self.COLOR_LCD:
+ vfocshiftd = RadioSetting("vfo.c.shiftd", "VFO C shift",
+ RadioSettingValueList(
+ LIST_SHIFT,
+ LIST_SHIFT[_mem.vfo.c.shiftd]))
+ work.append(vfocshiftd)
+
+ vfodshiftd = RadioSetting("vfo.d.shiftd", "VFO D shift",
+ RadioSettingValueList(
+ LIST_SHIFT,
+ LIST_SHIFT[_mem.vfo.d.shiftd]))
+ work.append(vfodshiftd)
+
+ def convert_bytes_to_offset(bytes):
+ real_offset = 0
+ for byte in bytes:
+ real_offset = (real_offset * 10) + byte
+ return chirp_common.format_freq(real_offset * 1000)
+
+ def apply_offset(setting, obj):
+ value = chirp_common.parse_freq(str(setting.value)) / 1000
+ for i in range(5, -1, -1):
+ obj.offset[i] = value % 10
+ value /= 10
+
+ if self.COLOR_LCD:
+ val1a = RadioSettingValueString(0, 10, convert_bytes_to_offset(
+ _mem.vfo.a.offset))
+ vfoaoffset = RadioSetting("vfo.a.offset",
+ "VFO A offset (0.000-999.999)", val1a)
+ vfoaoffset.set_apply_callback(apply_offset, _mem.vfo.a)
+ work.append(vfoaoffset)
+
+ val1b = RadioSettingValueString(0, 10, convert_bytes_to_offset(
+ _mem.vfo.b.offset))
+ vfoboffset = RadioSetting("vfo.b.offset",
+ "VFO B offset (0.000-999.999)", val1b)
+ vfoboffset.set_apply_callback(apply_offset, _mem.vfo.b)
+ work.append(vfoboffset)
+
+ val1c = RadioSettingValueString(0, 10, convert_bytes_to_offset(
+ _mem.vfo.c.offset))
+ vfocoffset = RadioSetting("vfo.c.offset",
+ "VFO C offset (0.000-999.999)", val1c)
+ vfocoffset.set_apply_callback(apply_offset, _mem.vfo.c)
+ work.append(vfocoffset)
+
+ val1d = RadioSettingValueString(0, 10, convert_bytes_to_offset(
+ _mem.vfo.d.offset))
+ vfodoffset = RadioSetting("vfo.d.offset",
+ "VFO D offset (0.000-999.999)", val1d)
+ vfodoffset.set_apply_callback(apply_offset, _mem.vfo.d)
+ work.append(vfodoffset)
+ else:
+ val1a = RadioSettingValueString(0, 10, convert_bytes_to_offset(
+ _mem.vfo.a.offset))
+ vfoaoffset = RadioSetting("vfo.a.offset",
+ "VFO A offset (0.000-99.999)", val1a)
+ vfoaoffset.set_apply_callback(apply_offset, _mem.vfo.a)
+ work.append(vfoaoffset)
+
+ val1b = RadioSettingValueString(0, 10, convert_bytes_to_offset(
+ _mem.vfo.b.offset))
+ vfoboffset = RadioSetting("vfo.b.offset",
+ "VFO B offset (0.000-99.999)", val1b)
+ vfoboffset.set_apply_callback(apply_offset, _mem.vfo.b)
+ work.append(vfoboffset)
+
+
+ vfoatxp = RadioSetting("vfo.a.power", "VFO A power",
+ RadioSettingValueList(
+ LIST_TXP,
+ LIST_TXP[_mem.vfo.a.power]))
+ work.append(vfoatxp)
+
+ vfobtxp = RadioSetting("vfo.b.power", "VFO B power",
+ RadioSettingValueList(
+ LIST_TXP,
+ LIST_TXP[_mem.vfo.b.power]))
+ work.append(vfobtxp)
+
+ if self.COLOR_LCD:
+ vfoctxp = RadioSetting("vfo.c.power", "VFO C power",
+ RadioSettingValueList(
+ LIST_TXP,
+ LIST_TXP[_mem.vfo.c.power]))
+ work.append(vfoctxp)
+
+ vfodtxp = RadioSetting("vfo.d.power", "VFO D power",
+ RadioSettingValueList(
+ LIST_TXP,
+ LIST_TXP[_mem.vfo.d.power]))
+ work.append(vfodtxp)
+
+ vfoawide = RadioSetting("vfo.a.wide", "VFO A bandwidth",
+ RadioSettingValueList(
+ LIST_WIDE,
+ LIST_WIDE[_mem.vfo.a.wide]))
+ work.append(vfoawide)
+
+ vfobwide = RadioSetting("vfo.b.wide", "VFO B bandwidth",
+ RadioSettingValueList(
+ LIST_WIDE,
+ LIST_WIDE[_mem.vfo.b.wide]))
+ work.append(vfobwide)
+
+ if self.COLOR_LCD:
+ vfocwide = RadioSetting("vfo.c.wide", "VFO C bandwidth",
+ RadioSettingValueList(
+ LIST_WIDE,
+ LIST_WIDE[_mem.vfo.c.wide]))
+ work.append(vfocwide)
+
+ vfodwide = RadioSetting("vfo.d.wide", "VFO D bandwidth",
+ RadioSettingValueList(
+ LIST_WIDE,
+ LIST_WIDE[_mem.vfo.d.wide]))
+ work.append(vfodwide)
+
+ vfoastep = RadioSetting("vfo.a.step", "VFO A step",
+ RadioSettingValueList(
+ LIST_STEP,
+ LIST_STEP[_mem.vfo.a.step]))
+ work.append(vfoastep)
+
+ vfobstep = RadioSetting("vfo.b.step", "VFO B step",
+ RadioSettingValueList(
+ LIST_STEP,
+ LIST_STEP[_mem.vfo.b.step]))
+ work.append(vfobstep)
+
+ if self.COLOR_LCD:
+ vfocstep = RadioSetting("vfo.c.step", "VFO C step",
+ RadioSettingValueList(
+ LIST_STEP,
+ LIST_STEP[_mem.vfo.c.step]))
+ work.append(vfocstep)
+
+ vfodstep = RadioSetting("vfo.d.step", "VFO D step",
+ RadioSettingValueList(
+ LIST_STEP,
+ LIST_STEP[_mem.vfo.d.step]))
+ work.append(vfodstep)
+
+ vfoaoptsig = RadioSetting("vfo.a.optsig", "VFO A optional signal",
+ RadioSettingValueList(
+ OPTSIG_LIST,
+ OPTSIG_LIST[_mem.vfo.a.optsig]))
+ work.append(vfoaoptsig)
+
+ vfoboptsig = RadioSetting("vfo.b.optsig", "VFO B optional signal",
+ RadioSettingValueList(
+ OPTSIG_LIST,
+ OPTSIG_LIST[_mem.vfo.b.optsig]))
+ work.append(vfoboptsig)
+
+ if self.COLOR_LCD:
+ vfocoptsig = RadioSetting("vfo.c.optsig", "VFO C optional signal",
+ RadioSettingValueList(
+ OPTSIG_LIST,
+ OPTSIG_LIST[_mem.vfo.c.optsig]))
+ work.append(vfocoptsig)
+
+ vfodoptsig = RadioSetting("vfo.d.optsig", "VFO D optional signal",
+ RadioSettingValueList(
+ OPTSIG_LIST,
+ OPTSIG_LIST[_mem.vfo.d.optsig]))
+ work.append(vfodoptsig)
+
+ vfoaspmute = RadioSetting("vfo.a.spmute", "VFO A speaker mute",
+ RadioSettingValueList(
+ SPMUTE_LIST,
+ SPMUTE_LIST[_mem.vfo.a.spmute]))
+ work.append(vfoaspmute)
+
+ vfobspmute = RadioSetting("vfo.b.spmute", "VFO B speaker mute",
+ RadioSettingValueList(
+ SPMUTE_LIST,
+ SPMUTE_LIST[_mem.vfo.b.spmute]))
+ work.append(vfobspmute)
+
+ if self.COLOR_LCD:
+ vfocspmute = RadioSetting("vfo.c.spmute", "VFO C speaker mute",
+ RadioSettingValueList(
+ SPMUTE_LIST,
+ SPMUTE_LIST[_mem.vfo.c.spmute]))
+ work.append(vfocspmute)
+
+ vfodspmute = RadioSetting("vfo.d.spmute", "VFO D speaker mute",
+ RadioSettingValueList(
+ SPMUTE_LIST,
+ SPMUTE_LIST[_mem.vfo.d.spmute]))
+ work.append(vfodspmute)
+
+ vfoascr = RadioSetting("vfo.a.scramble", "VFO A scramble",
+ RadioSettingValueBoolean(
+ _mem.vfo.a.scramble))
+ work.append(vfoascr)
+
+ vfobscr = RadioSetting("vfo.b.scramble", "VFO B scramble",
+ RadioSettingValueBoolean(
+ _mem.vfo.b.scramble))
+ work.append(vfobscr)
+
+ if self.COLOR_LCD:
+ vfocscr = RadioSetting("vfo.c.scramble", "VFO C scramble",
+ RadioSettingValueBoolean(
+ _mem.vfo.c.scramble))
+ work.append(vfocscr)
+
+ vfodscr = RadioSetting("vfo.d.scramble", "VFO D scramble",
+ RadioSettingValueBoolean(
+ _mem.vfo.d.scramble))
+ work.append(vfodscr)
+
+ vfoascode = RadioSetting("vfo.a.scode", "VFO A PTT-ID",
+ RadioSettingValueList(
+ PTTIDCODE_LIST,
+ PTTIDCODE_LIST[_mem.vfo.a.scode]))
+ work.append(vfoascode)
+
+ vfobscode = RadioSetting("vfo.b.scode", "VFO B PTT-ID",
+ RadioSettingValueList(
+ PTTIDCODE_LIST,
+ PTTIDCODE_LIST[_mem.vfo.b.scode]))
+ work.append(vfobscode)
+
+ if self.COLOR_LCD:
+ vfocscode = RadioSetting("vfo.c.scode", "VFO C PTT-ID",
+ RadioSettingValueList(
+ PTTIDCODE_LIST,
+ PTTIDCODE_LIST[_mem.vfo.c.scode]))
+ work.append(vfocscode)
+
+ vfodscode = RadioSetting("vfo.d.scode", "VFO D PTT-ID",
+ RadioSettingValueList(
+ PTTIDCODE_LIST,
+ PTTIDCODE_LIST[_mem.vfo.d.scode]))
+ work.append(vfodscode)
+
+ pttid = RadioSetting("settings.pttid", "PTT ID",
+ RadioSettingValueList(
+ PTTID_LIST,
+ PTTID_LIST[_mem.settings.pttid]))
+ work.append(pttid)
+
+ if not self.COLOR_LCD:
+ #FM presets
+ fm_presets = RadioSettingGroup("fm_presets", "FM Presets")
+ top.append(fm_presets)
+
+ def fm_validate(value):
+ if value == 0:
+ return chirp_common.format_freq(value)
+ if not (87.5 <= value and value <= 108.0): # 87.5-108MHz
+ msg = ("FM-Preset-Frequency: Must be between 87.5 and 108 MHz")
+ raise InvalidValueError(msg)
+ return value
+
+ def apply_fm_preset_name(setting, obj):
+ valstring = str (setting.value)
+ for i in range(0,6):
+ if valstring[i] in VALID_CHARS:
+ obj[i] = valstring[i]
+ else:
+ obj[i] = '0xff'
+
+ def apply_fm_freq(setting, obj):
+ value = chirp_common.parse_freq(str(setting.value)) / 10
+ for i in range(7, -1, -1):
+ obj.freq[i] = value % 10
+ value /= 10
+
+ _presets = self._memobj.fm_radio_preset
+ i = 1
+ for preset in _presets:
+ line = RadioSetting("fm_presets_"+ str(i),
+ "Station name " + str(i),
+ RadioSettingValueString(0, 6, _filter(
+ preset.broadcast_station_name)))
+ line.set_apply_callback(apply_fm_preset_name,
+ preset.broadcast_station_name)
+
+ val = RadioSettingValueFloat(0, 108,
+ convert_bytes_to_freq(
+ preset.freq))
+ fmfreq = RadioSetting("fm_presets_"+ str(i) + "_freq",
+ "Frequency "+ str(i), val)
+ val.set_validate_callback(fm_validate)
+ fmfreq.set_apply_callback(apply_fm_freq, preset)
+ fm_presets.append(line)
+ 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)
+
+ if self.COLOR_LCD:
+ line = RadioSetting(
+ "dtmf_settings.resettime",
+ "Reset time",
+ RadioSettingValueList(LIST_5TONE_RESET_COLOR,
+ LIST_5TONE_RESET_COLOR[
+ _mem.dtmf_settings.resettime]))
+ dtmf_dec_settings.append(line)
+ else:
+ 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):
+ _settings = self._memobj.settings
+ for element in settings:
+ if not isinstance(element, RadioSetting):
+ if element.get_name() == "fm_preset":
+ self._set_fm_preset(element)
+ else:
+ 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:
+ 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
+
+
MEM_FORMAT = """
#seekto 0x0000;
struct {
@@ -127,9 +2831,8 @@
struct settings_vfo {
u8 freq[8];
- u8 unknown1;
- u8 offset[4];
- u8 unknown2[3];
+ u8 offset[6];
+ u8 unknown2[2];
ul16 rxtone;
ul16 txtone;
u8 scode;
@@ -316,696 +3019,12 @@
"""
-# A note about the memmory in these radios
-#
-# The real memory of these radios extends to 0x4000
-# On read the factory software only uses up to 0x3200
-# On write it just uploads the contents up to 0x3100
-#
-# The mem beyond 0x3200 holds the ID data
-
-MEM_SIZE = 0x4000
-BLOCK_SIZE = 0x40
-TX_BLOCK_SIZE = 0x10
-ACK_CMD = "\x06"
-MODES = ["FM", "NFM"]
-SKIP_VALUES = ["S", ""]
-TONES = chirp_common.TONES
-DTCS = sorted(chirp_common.DTCS_CODES + [645])
-NAME_LENGTH = 6
-PTTID_LIST = ["OFF", "BOT", "EOT", "BOTH"]
-PTTIDCODE_LIST = ["%s" % x for x in range(1, 16)]
-OPTSIG_LIST = ["OFF", "DTMF", "2TONE", "5TONE"]
-SPMUTE_LIST = ["Tone/DTCS", "Tone/DTCS and Optsig", "Tone/DTCS or Optsig"]
-
-LIST_TOT = ["%s sec" % x for x in range(15, 615, 15)]
-LIST_TOA = ["Off"] + ["%s seconds" % x for x in range(1, 11)]
-LIST_APO = ["Off"] + ["%s minutes" % x for x in range(30, 330, 30)]
-LIST_ABR = ["Off"] + ["%s seconds" % x for x in range(1, 51)]
-LIST_DTMFST = ["OFF", "Keyboard", "ANI", "Keyboad + ANI"]
-LIST_SCREV = ["TO (timeout)", "CO (carrier operated)", "SE (search)"]
-LIST_EMCTP = ["TX alarm sound", "TX ANI", "Both"]
-LIST_RINGT = ["Off"] + ["%s seconds" % x for x in range(1, 10)]
-LIST_MDF = ["Frequency", "Channel", "Name"]
-LIST_PONMSG = ["Full", "Message", "Battery voltage"]
-LIST_COLOR = ["Off", "Blue", "Orange", "Purple"]
-LIST_REPS = ["1000 Hz", "1450 Hz", "1750 Hz", "2100Hz"]
-LIST_REPM = ["Off", "Carrier", "CTCSS or DCS", "Tone", "DTMF"]
-LIST_RPTDL = ["Off"] + ["%s ms" % x for x in range(1, 10)]
-LIST_ANIL = ["3", "4", "5"]
-LIST_AB = ["A", "B"]
-LIST_VFOMR = ["Frequency", "Channel"]
-LIST_SHIFT = ["Off", "+", "-"]
-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.
-STIMEOUT = 0.7
-
-# this var controls the verbosity in the debug and by default it's low (False)
-# make it True and you will to get a very verbose debug.log
-debug = False
-
-# Power Levels
-NORMAL_POWER_LEVELS = [chirp_common.PowerLevel("High", watts=25),
- chirp_common.PowerLevel("Low", watts=10)]
-UV5001_POWER_LEVELS = [chirp_common.PowerLevel("High", watts=50),
- chirp_common.PowerLevel("Low", watts=10)]
-
-# this must be defined globaly
-POWER_LEVELS = None
-
-# valid chars on the LCD, Note that " " (space) is stored as "\xFF"
-VALID_CHARS = chirp_common.CHARSET_ALPHANUMERIC + \
- "`{|}!\"#$%&'()*+,-./:;<=>?@[]^_"
-
-
-##### ID strings #####################################################
-
-# BTECH UV2501 pre-production units
-UV2501pp_fp = "M2C294"
-# BTECH UV2501 pre-production units 2 + and 1st Gen radios
-UV2501pp2_fp = "M29204"
-# B-TECH UV-2501 second generation (2G) radios
-UV2501G2_fp = "BTG214"
-# B-TECH UV-2501 third generation (3G) radios
-UV2501G3_fp = "BTG324"
-
-# B-TECH UV-2501+220 pre-production units
-UV2501_220pp_fp = "M3C281"
-# extra block read for the 2501+220 pre-production units
-# the same for all of this radios so far
-UV2501_220pp_id = " 280528"
-# B-TECH UV-2501+220
-UV2501_220_fp = "M3G201"
-# new variant, let's call it Generation 2
-UV2501_220G2_fp = "BTG211"
-# B-TECH UV-2501+220 third generation (3G)
-UV2501_220G3_fp = "BTG311"
-
-# B-TECH UV-5001 pre-production units + 1st Gen radios
-UV5001pp_fp = "V19204"
-# B-TECH UV-5001 alpha units
-UV5001alpha_fp = "V28204"
-# B-TECH UV-5001 second generation (2G) radios
-UV5001G2_fp = "BTG214"
-# B-TECH UV-5001 second generation (2G2)
-UV5001G22_fp = "V2G204"
-# B-TECH UV-5001 third generation (3G)
-UV5001G3_fp = "BTG304"
-
-# special var to know when we found a BTECH Gen 3
-BTECH3 = [UV2501G3_fp, UV2501_220G3_fp, UV5001G3_fp]
-
-
-# WACCOM Mini-8900
-MINI8900_fp = "M28854"
-
-
-# QYT KT-UV980
-KTUV980_fp = "H28854"
-
-# QYT KT8900
-KT8900_fp = "M29154"
-# New generations KT8900
-KT8900_fp1 = "M2C234"
-KT8900_fp2 = "M2G1F4"
-KT8900_fp3 = "M2G2F4"
-KT8900_fp4 = "M2G304"
-KT8900_fp5 = "M2G314"
-# this radio has an extra ID
-KT8900_id = " 303688"
-
-# KT8900R
-KT8900R_fp = "M3G1F4"
-# Second Generation
-KT8900R_fp1 = "M3G214"
-# another model
-KT8900R_fp2 = "M3C234"
-# another model G4?
-KT8900R_fp3 = "M39164"
-# another model
-KT8900R_fp4 = "M3G314"
-# this radio has an extra ID
-KT8900R_id = "280528"
-
-
-# LUITON LT-588UV
-LT588UV_fp = "V2G1F4"
-# Added by rstrickoff gen 2 id
-LT588UV_fp1 = "V2G214"
-
-
-#### MAGICS
-# for the Waccom Mini-8900
-MSTRING_MINI8900 = "\x55\xA5\xB5\x45\x55\x45\x4d\x02"
-# for the B-TECH UV-2501+220 (including pre production ones)
-MSTRING_220 = "\x55\x20\x15\x12\x12\x01\x4d\x02"
-# for the QYT KT8900 & R
-MSTRING_KT8900 = "\x55\x20\x15\x09\x16\x45\x4D\x02"
-MSTRING_KT8900R = "\x55\x20\x15\x09\x25\x01\x4D\x02"
-# magic string for all other models
-MSTRING = "\x55\x20\x15\x09\x20\x45\x4d\x02"
-
-
-def _clean_buffer(radio):
- """Cleaning the read serial buffer, hard timeout to survive an infinite
- data stream"""
-
- # touching the serial timeout to optimize the flushing
- # restored at the end to the default value
- radio.pipe.timeout = 0.1
- dump = "1"
- datacount = 0
-
- try:
- while len(dump) > 0:
- dump = radio.pipe.read(100)
- datacount += len(dump)
- # hard limit to survive a infinite serial data stream
- # 5 times bigger than a normal rx block (69 bytes)
- if datacount > 345:
- seriale = "Please check your serial port selection."
- raise errors.RadioError(seriale)
-
- # restore the default serial timeout
- radio.pipe.timeout = STIMEOUT
-
- except Exception:
- raise errors.RadioError("Unknown error cleaning the serial buffer")
-
-
-def _rawrecv(radio, amount):
- """Raw read from the radio device, less intensive way"""
-
- data = ""
-
- try:
- data = radio.pipe.read(amount)
-
- # DEBUG
- if debug is True:
- LOG.debug("<== (%d) bytes:\n\n%s" %
- (len(data), util.hexprint(data)))
-
- # fail if no data is received
- if len(data) == 0:
- raise errors.RadioError("No data received from radio")
-
- # notice on the logs if short
- if len(data) < amount:
- LOG.warn("Short reading %d bytes from the %d requested." %
- (len(data), amount))
-
- except:
- raise errors.RadioError("Error reading data from radio")
-
- return data
-
-
-def _send(radio, data):
- """Send data to the radio device"""
-
- try:
- for byte in data:
- radio.pipe.write(byte)
- # Some OS (mainly Linux ones) are too fast on the serial and
- # get the MCU inside the radio stuck in the early stages, this
- # hits some models more than others.
- #
- # To cope with that we introduce a delay on the writes.
- # Many option have been tested (delaying only after error occures, after short reads, only for linux, ...)
- # Finally, a static delay was chosen as simplest of all solutions (Michael Wagner, OE4AMW)
- # (for details, see issue 3993)
- sleep(0.002)
-
- # DEBUG
- if debug is True:
- LOG.debug("==> (%d) bytes:\n\n%s" %
- (len(data), util.hexprint(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 = "\x06" + struct.pack(">BHB", ord(cmd), addr, length)
- # add the data if set
- if len(data) != 0:
- frame += data
-
- return frame
-
-
-def _recv(radio, addr):
- """Get data from the radio all at once to lower syscalls load"""
-
- # Get the full 69 bytes at a time to reduce load
- # 1 byte ACK + 4 bytes header + 64 bytes of data (BLOCK_SIZE)
-
- # get the whole block
- block = _rawrecv(radio, BLOCK_SIZE + 5)
-
- # basic check
- if len(block) < (BLOCK_SIZE + 5):
- raise errors.RadioError("Short read of the block 0x%04x" % addr)
-
- # checking for the ack
- if block[0] != ACK_CMD:
- raise errors.RadioError("Bad ack from radio in block 0x%04x" % addr)
-
- # header validation
- c, a, l = struct.unpack(">BHB", block[1:5])
- if a != addr or l != BLOCK_SIZE or c != ord("X"):
- LOG.debug("Invalid header for block 0x%04x" % addr)
- LOG.debug("CMD: %s ADDR: %04x SIZE: %02x" % (c, a, l))
- raise errors.RadioError("Invalid header for block 0x%04x:" % addr)
-
- # return the data
- return block[5:]
-
-
-def _start_clone_mode(radio, status):
- """Put the radio in clone mode and get the ident string, 3 tries"""
-
- # cleaning the serial buffer
- _clean_buffer(radio)
-
- # prep the data to show in the UI
- status.cur = 0
- status.msg = "Identifying the radio..."
- status.max = 3
- radio.status_fn(status)
-
- try:
- for a in range(0, status.max):
- # Update the UI
- status.cur = a + 1
- radio.status_fn(status)
-
- # send the magic word
- _send(radio, radio._magic)
-
- # Now you get a x06 of ACK if all goes well
- ack = radio.pipe.read(1)
-
- if ack == "\x06":
- # DEBUG
- LOG.info("Magic ACK received")
- status.cur = status.max
- radio.status_fn(status)
-
- return True
-
- return False
-
- except errors.RadioError:
- raise
- except Exception, e:
- raise errors.RadioError("Error sending Magic to radio:\n%s" % e)
-
-
-def _do_ident(radio, status, upload=False):
- """Put the radio in PROGRAM mode & identify it"""
- # set the serial discipline
- radio.pipe.baudrate = 9600
- radio.pipe.parity = "N"
-
- # open the radio into program mode
- if _start_clone_mode(radio, status) is False:
- msg = "Radio did not enter clone mode"
- # warning about old versions of QYT KT8900
- if radio.MODEL == "KT8900":
- msg += ". You may want to try it as a WACCOM MINI-8900, there is a"
- msg += " known variant of this radios that is a clone of it."
- raise errors.RadioError(msg)
-
- # Ok, get the ident string
- ident = _rawrecv(radio, 49)
-
- # basic check for the ident
- if len(ident) != 49:
- raise errors.RadioError("Radio send a short ident block.")
-
- # check if ident is OK
- itis = False
- for fp in radio._fileid:
- if fp in ident:
- # got it!
- itis = True
- # checking if we are dealing with a Gen 3 BTECH
- if radio.VENDOR == "BTECH" and fp in BTECH3:
- radio.btech3 = True
-
- break
-
- if itis is False:
- LOG.debug("Incorrect model ID, got this:\n\n" + util.hexprint(ident))
- raise errors.RadioError("Radio identification failed.")
-
- # some radios needs a extra read and check for a code on it, this ones
- # has the check value in the _id2 var, others simply False
- if radio._id2 is not False:
- # lower the timeout here as this radios are reseting due to timeout
- radio.pipe.timeout = 0.05
-
- # query & receive the extra ID
- _send(radio, _make_frame("S", 0x3DF0, 16))
- id2 = _rawrecv(radio, 21)
-
- # WARNING !!!!!!
- # different radios send a response with a different amount of data
- # it seems that it's padded with \xff, \x20 and some times with \x00
- # we just care about the first 16, our magic string is in there
- if len(id2) < 16:
- raise errors.RadioError("The extra ID is short, aborting.")
-
- # ok, the correct string must be in the received data
- if radio._id2 not in id2:
- LOG.debug("Full *BAD* extra ID on the %s is: \n%s" %
- (radio.MODEL, util.hexprint(id2)))
- raise errors.RadioError("The extra ID is wrong, aborting.")
-
- # this radios need a extra request/answer here on the upload
- # the amount of data received depends of the radio type
- #
- # also the first block of TX must no have the ACK at the beginning
- # see _upload for this.
- if upload is True:
- # send an ACK
- _send(radio, ACK_CMD)
-
- # the amount of data depend on the radio, so far we have two radios
- # reading two bytes with an ACK at the end and just ONE with just
- # one byte (QYT KT8900)
- # the JT-6188 appears a clone of the last, but reads TWO bytes.
- #
- # we will read two bytes with a custom timeout to not penalize the
- # users for this.
- #
- # we just check for a response and last byte being a ACK, that is
- # the common stone for all radios (3 so far)
- ack = _rawrecv(radio, 2)
-
- # checking
- if len(ack) == 0 or ack[-1:] != ACK_CMD:
- raise errors.RadioError("Radio didn't ACK the upload")
-
- # restore the default serial timeout
- radio.pipe.timeout = STIMEOUT
-
- # DEBUG
- LOG.info("Positive ident, this is a %s %s" % (radio.VENDOR, radio.MODEL))
-
- return True
-
-
-def _download(radio):
- """Get the memory map"""
-
- # UI progress
- status = chirp_common.Status()
-
- # put radio in program mode and identify it
- _do_ident(radio, status)
-
- # the models that doesn't have the extra ID have to make a dummy read here
- if radio._id2 is False:
- _send(radio, _make_frame("S", 0, BLOCK_SIZE))
- discard = _rawrecv(radio, BLOCK_SIZE + 5)
-
- if debug is True:
- LOG.info("Dummy first block read done, got this:\n\n %s",
- util.hexprint(discard))
-
- # reset the progress bar in the UI
- status.max = MEM_SIZE / BLOCK_SIZE
- status.msg = "Cloning from radio..."
- status.cur = 0
- radio.status_fn(status)
-
- # cleaning the serial buffer
- _clean_buffer(radio)
-
- data = ""
- for addr in range(0, MEM_SIZE, BLOCK_SIZE):
- # sending the read request
- _send(radio, _make_frame("S", addr, BLOCK_SIZE))
-
- # read
- d = _recv(radio, addr)
-
- # aggregate the data
- data += d
-
- # UI Update
- status.cur = addr / BLOCK_SIZE
- status.msg = "Cloning from radio..."
- radio.status_fn(status)
-
- return data
-
-
-def _upload(radio):
- """Upload procedure"""
-
- # The UPLOAD mem is restricted to lower than 0x3100,
- # so we will overide that here localy
- MEM_SIZE = 0x3100
-
- # UI progress
- status = chirp_common.Status()
-
- # put radio in program mode and identify it
- _do_ident(radio, status, True)
-
- # get the data to upload to radio
- data = radio.get_mmap()
-
- # Reset the UI progress
- status.max = MEM_SIZE / TX_BLOCK_SIZE
- status.cur = 0
- status.msg = "Cloning to radio..."
- radio.status_fn(status)
-
- # the radios that doesn't have the extra ID 'may' do a dummy write, I found
- # that leveraging the bad ACK and NOT doing the dummy write is ok, as the
- # dummy write is accepted (it actually writes to the mem!) by the radio.
-
- # cleaning the serial buffer
- _clean_buffer(radio)
-
- # the fun start here
- for addr in range(0, MEM_SIZE, TX_BLOCK_SIZE):
- # getting the block of data to send
- d = data[addr:addr + TX_BLOCK_SIZE]
-
- # build the frame to send
- frame = _make_frame("X", addr, TX_BLOCK_SIZE, d)
-
- # first block must not send the ACK at the beginning for the
- # ones that has the extra id, since this have to do a extra step
- if addr == 0 and radio._id2 is not False:
- frame = frame[1:]
-
- # send the frame
- _send(radio, frame)
-
- # receiving the response
- ack = _rawrecv(radio, 1)
-
- # basic check
- if len(ack) != 1:
- raise errors.RadioError("No ACK when writing block 0x%04x" % addr)
-
- if not ack in "\x06\x05":
- raise errors.RadioError("Bad ACK writing block 0x%04x:" % addr)
-
- # UI Update
- status.cur = addr / TX_BLOCK_SIZE
- status.msg = "Cloning to radio..."
- radio.status_fn(status)
-
-
-def model_match(cls, data):
- """Match the opened/downloaded image to the correct version"""
- rid = data[0x3f70:0x3f76]
-
- if rid in cls._fileid:
- return True
-
- return False
-
-
-def _decode_ranges(low, high):
- """Unpack the data in the ranges zones in the memmap and return
- a tuple with the integer corresponding to the Mhz it means"""
- ilow = int(low[0]) * 100 + int(low[1]) * 10 + int(low[2])
- ihigh = int(high[0]) * 100 + int(high[1]) * 10 + int(high[2])
- ilow *= 1000000
- ihigh *= 1000000
-
- return (ilow, ihigh)
-
-
-def _split(rf, f1, f2):
- """Returns False if the two freqs are in the same band (no split)
- or True otherwise"""
-
- # determine if the two freqs are in the same band
- for low, high in rf.valid_bands:
- if f1 >= low and f1 <= high and \
- f2 >= low and f2 <= high:
- # if the two freqs are on the same Band this is not a split
- return False
-
- # if you get here is because the freq pairs are split
- return False
-
-
-class BTech(chirp_common.CloneModeRadio, chirp_common.ExperimentalRadio):
+
+class BTech(BTechMobileCommon):
"""BTECH's UV-5001 and alike radios"""
- VENDOR = "BTECH"
- MODEL = ""
- IDENT = ""
- _vhf_range = (130000000, 180000000)
- _220_range = (210000000, 231000000)
- _uhf_range = (400000000, 521000000)
- _upper = 199
- _magic = MSTRING
- _fileid = None
- _id2 = False
- btech3 = False
-
- @classmethod
- def get_prompts(cls):
- rp = chirp_common.RadioPrompts()
- rp.experimental = \
- ('This driver is experimental.\n'
- '\n'
- 'Please keep a copy of your memories with the original software '
- 'if you treasure them, this driver is new and may contain'
- ' bugs.\n'
- '\n'
- )
- rp.pre_download = _(dedent("""\
- Follow these instructions to download your info:
-
- 1 - Turn off your radio
- 2 - Connect your interface cable
- 3 - Turn on your radio
- 4 - Do the download of your radio data
-
- """))
- rp.pre_upload = _(dedent("""\
- Follow these instructions to upload your info:
-
- 1 - Turn off your radio
- 2 - Connect your interface cable
- 3 - Turn on your radio
- 4 - Do the upload of your radio data
-
- """))
- return rp
-
- def get_features(self):
- """Get the radio's features"""
-
- # we will use the following var as global
- global POWER_LEVELS
-
- rf = chirp_common.RadioFeatures()
- rf.has_settings = True
- rf.has_bank = False
- rf.has_tuning_step = False
- rf.can_odd_split = True
- 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.valid_modes = MODES
- rf.valid_characters = VALID_CHARS
- rf.valid_name_length = NAME_LENGTH
- rf.valid_duplexes = ["", "-", "+", "split", "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 = SKIP_VALUES
- rf.valid_dtcs_codes = DTCS
- rf.memory_bounds = (0, self._upper)
-
- # power levels
- if self.MODEL == "UV-5001":
- POWER_LEVELS = UV5001_POWER_LEVELS # Higher power (50W)
- else:
- POWER_LEVELS = NORMAL_POWER_LEVELS # Lower power (25W)
-
- rf.valid_power_levels = POWER_LEVELS
-
- # bands
- rf.valid_bands = [self._vhf_range, self._uhf_range]
-
- # 2501+220 & KT8900R
- if self.MODEL in ["UV-2501+220", "KT8900R"]:
- rf.valid_bands.append(self._220_range)
-
- return rf
-
- def sync_in(self):
- """Download from radio"""
- data = _download(self)
- self._mmap = memmap.MemoryMap(data)
- self.process_mmap()
-
- def sync_out(self):
- """Upload to radio"""
- try:
- _upload(self)
- except errors.RadioError:
- raise
- except Exception, e:
- raise errors.RadioError("Error: %s" % e)
+ BANDS = 2
+ COLOR_LCD = False
+ NAME_LENGTH = 6
def set_options(self):
"""This is to read the options from the image and set it in the
@@ -1048,1546 +3067,6 @@
# load specific parameters from the radio image
self.set_options()
- def get_raw_memory(self, number):
- return repr(self._memobj.memory[number])
-
- def _decode_tone(self, val):
- """Parse the tone data to decode from mem, it returns:
- Mode (''|DTCS|Tone), Value (None|###), Polarity (None,N,R)"""
- pol = None
-
- if val in [0, 65535]:
- return '', None, None
- elif val > 0x0258:
- a = val / 10.0
- return 'Tone', a, pol
- else:
- if val > 0x69:
- index = val - 0x6A
- pol = "R"
- else:
- index = val - 1
- pol = "N"
-
- tone = DTCS[index]
- return 'DTCS', tone, pol
-
- def _encode_tone(self, memval, mode, val, pol):
- """Parse the tone data to encode from UI to mem"""
- if mode == '' or mode is None:
- memval.set_raw("\x00\x00")
- elif mode == 'Tone':
- memval.set_value(val * 10)
- elif mode == 'DTCS':
- # detect the index in the DTCS list
- try:
- index = DTCS.index(val)
- if pol == "N":
- index += 1
- else:
- index += 0x6A
- memval.set_value(index)
- except:
- msg = "Digital Tone '%d' is not supported" % value
- LOG.error(msg)
- raise errors.RadioError(msg)
- else:
- msg = "Internal error: invalid mode '%s'" % mode
- LOG.error(msg)
- raise errors.InvalidDataError(msg)
-
- def get_memory(self, number):
- """Get the mem representation from the radio image"""
- _mem = self._memobj.memory[number]
- _names = self._memobj.names[number]
-
- # Create a high-level memory object to return to the UI
- mem = chirp_common.Memory()
-
- # Memory number
- mem.number = number
-
- if _mem.get_raw()[0] == "\xFF":
- mem.empty = True
- return mem
-
- # Freq and offset
- mem.freq = int(_mem.rxfreq) * 10
- # tx freq can be blank
- if _mem.get_raw()[4] == "\xFF":
- # TX freq not set
- mem.offset = 0
- mem.duplex = "off"
- else:
- # TX freq set
- offset = (int(_mem.txfreq) * 10) - mem.freq
- if offset != 0:
- if _split(self.get_features(), mem.freq, int(_mem.txfreq) * 10):
- mem.duplex = "split"
- mem.offset = int(_mem.txfreq) * 10
- elif offset < 0:
- mem.offset = abs(offset)
- mem.duplex = "-"
- elif offset > 0:
- mem.offset = offset
- mem.duplex = "+"
- else:
- mem.offset = 0
-
- # name TAG of the channel
- mem.name = str(_names.name).rstrip("\xFF").replace("\xFF", " ")
-
- # power
- mem.power = POWER_LEVELS[int(_mem.power)]
-
- # wide/narrow
- mem.mode = MODES[int(_mem.wide)]
-
- # skip
- mem.skip = SKIP_VALUES[_mem.add]
-
- # tone data
- rxtone = txtone = None
- txtone = self._decode_tone(_mem.txtone)
- rxtone = self._decode_tone(_mem.rxtone)
- chirp_common.split_tone_decode(mem, txtone, rxtone)
-
- # Extra
- mem.extra = RadioSettingGroup("extra", "Extra")
-
- scramble = RadioSetting("scramble", "Scramble",
- RadioSettingValueBoolean(bool(_mem.scramble)))
- mem.extra.append(scramble)
-
- bcl = RadioSetting("bcl", "Busy channel lockout",
- RadioSettingValueBoolean(bool(_mem.bcl)))
- mem.extra.append(bcl)
-
- pttid = RadioSetting("pttid", "PTT ID",
- RadioSettingValueList(PTTID_LIST,
- PTTID_LIST[_mem.pttid]))
- mem.extra.append(pttid)
-
- # validating scode
- scode = _mem.scode if _mem.scode != 15 else 0
- pttidcode = RadioSetting("scode", "PTT ID signal code",
- RadioSettingValueList(
- PTTIDCODE_LIST,
- PTTIDCODE_LIST[scode]))
- mem.extra.append(pttidcode)
-
- optsig = RadioSetting("optsig", "Optional signaling",
- RadioSettingValueList(
- OPTSIG_LIST,
- OPTSIG_LIST[_mem.optsig]))
- mem.extra.append(optsig)
-
- spmute = RadioSetting("spmute", "Speaker mute",
- RadioSettingValueList(
- SPMUTE_LIST,
- SPMUTE_LIST[_mem.spmute]))
- mem.extra.append(spmute)
-
- return mem
-
- def set_memory(self, mem):
- """Set the memory data in the eeprom img from the UI"""
- # get the eprom representation of this channel
- _mem = self._memobj.memory[mem.number]
- _names = self._memobj.names[mem.number]
-
- mem_was_empty = False
- # same method as used in get_memory for determining if mem is empty
- # doing this BEFORE overwriting it with new values ...
- if _mem.get_raw()[0] == "\xFF":
- LOG.debug("This mem was empty before")
- mem_was_empty = True
-
- # if empty memmory
- if mem.empty:
- # the channel itself
- _mem.set_raw("\xFF" * 16)
- # the name tag
- _names.set_raw("\xFF" * 16)
- return
-
- # frequency
- _mem.rxfreq = mem.freq / 10
-
- # duplex
- if mem.duplex == "+":
- _mem.txfreq = (mem.freq + mem.offset) / 10
- elif mem.duplex == "-":
- _mem.txfreq = (mem.freq - mem.offset) / 10
- elif mem.duplex == "off":
- for i in _mem.txfreq:
- i.set_raw("\xFF")
- elif mem.duplex == "split":
- _mem.txfreq = mem.offset / 10
- else:
- _mem.txfreq = mem.freq / 10
-
- # tone data
- ((txmode, txtone, txpol), (rxmode, rxtone, rxpol)) = \
- chirp_common.split_tone_encode(mem)
- self._encode_tone(_mem.txtone, txmode, txtone, txpol)
- self._encode_tone(_mem.rxtone, rxmode, rxtone, rxpol)
-
- # name TAG of the channel
- if len(mem.name) < NAME_LENGTH:
- # we must pad to NAME_LENGTH chars, " " = "\xFF"
- mem.name = str(mem.name).ljust(NAME_LENGTH, " ")
- _names.name = str(mem.name).replace(" ", "\xFF")
-
- # power, # default power level is high
- _mem.power = 0 if mem.power is None else POWER_LEVELS.index(mem.power)
-
- # wide/narrow
- _mem.wide = MODES.index(mem.mode)
-
- # scan add property
- _mem.add = SKIP_VALUES.index(mem.skip)
-
- # reseting unknowns, this have to be set by hand
- _mem.unknown0 = 0
- _mem.unknown1 = 0
- _mem.unknown2 = 0
- _mem.unknown3 = 0
- _mem.unknown4 = 0
- _mem.unknown5 = 0
- _mem.unknown6 = 0
-
- # extra settings
- if len(mem.extra) > 0:
- # there are setting, parse
- LOG.debug("Extra-Setting supplied. Setting them.")
- for setting in mem.extra:
- setattr(_mem, setting.get_name(), setting.value)
- else:
- if mem.empty:
- LOG.debug("New mem is empty.")
- else:
- LOG.debug("New mem is NOT empty")
- # set extra-settings to default ONLY when apreviously empty or
- # deleted memory was edited to prevent errors such as #4121
- if mem_was_empty :
- LOG.debug("old mem was empty. Setting default for extras.")
- _mem.spmute = 0
- _mem.optsig = 0
- _mem.scramble = 0
- _mem.bcl = 0
- _mem.pttid = 0
- _mem.scode = 0
-
- return mem
-
- def get_settings(self):
- """Translate the bit in the mem_struct into settings in the UI"""
- _mem = self._memobj
- basic = RadioSettingGroup("basic", "Basic Settings")
- advanced = RadioSettingGroup("advanced", "Advanced Settings")
- other = RadioSettingGroup("other", "Other Settings")
- work = RadioSettingGroup("work", "Work Mode Settings")
- fm_presets = RadioSettingGroup("fm_presets", "FM Presets")
- top = RadioSettings(basic, advanced, other, work, fm_presets)
-
- # Basic
- tdr = RadioSetting("settings.tdr", "Transceiver dual receive",
- RadioSettingValueBoolean(_mem.settings.tdr))
- basic.append(tdr)
-
- sql = RadioSetting("settings.sql", "Squelch level",
- RadioSettingValueInteger(0, 9, _mem.settings.sql))
- basic.append(sql)
-
- tot = RadioSetting("settings.tot", "Time out timer",
- RadioSettingValueList(LIST_TOT, LIST_TOT[
- _mem.settings.tot]))
- basic.append(tot)
-
- if self.MODEL in ("UV-2501", "UV-2501+220", "UV-5001"):
- apo = RadioSetting("settings.apo", "Auto power off timer",
- RadioSettingValueList(LIST_APO, LIST_APO[
- _mem.settings.apo]))
- basic.append(apo)
- else:
- toa = RadioSetting("settings.apo", "Time out alert timer",
- RadioSettingValueList(LIST_TOA, LIST_TOA[
- _mem.settings.apo]))
- basic.append(toa)
-
- abr = RadioSetting("settings.abr", "Backlight timer",
- RadioSettingValueList(LIST_ABR, LIST_ABR[
- _mem.settings.abr]))
- basic.append(abr)
-
- beep = RadioSetting("settings.beep", "Key beep",
- RadioSettingValueBoolean(_mem.settings.beep))
- basic.append(beep)
-
- dtmfst = RadioSetting("settings.dtmfst", "DTMF side tone",
- RadioSettingValueList(LIST_DTMFST, LIST_DTMFST[
- _mem.settings.dtmfst]))
- basic.append(dtmfst)
-
- prisc = RadioSetting("settings.prisc", "Priority scan",
- RadioSettingValueBoolean(_mem.settings.prisc))
- basic.append(prisc)
-
- prich = RadioSetting("settings.prich", "Priority channel",
- RadioSettingValueInteger(0, 199,
- _mem.settings.prich))
- basic.append(prich)
-
- screv = RadioSetting("settings.screv", "Scan resume method",
- RadioSettingValueList(LIST_SCREV, LIST_SCREV[
- _mem.settings.screv]))
- basic.append(screv)
-
- pttlt = RadioSetting("settings.pttlt", "PTT transmit delay",
- RadioSettingValueInteger(0, 30,
- _mem.settings.pttlt))
- basic.append(pttlt)
-
- emctp = RadioSetting("settings.emctp", "Alarm mode",
- RadioSettingValueList(LIST_EMCTP, LIST_EMCTP[
- _mem.settings.emctp]))
- basic.append(emctp)
-
- emcch = RadioSetting("settings.emcch", "Alarm channel",
- RadioSettingValueInteger(0, 199,
- _mem.settings.emcch))
- basic.append(emcch)
-
- ringt = RadioSetting("settings.ringt", "Ring time",
- RadioSettingValueList(LIST_RINGT, LIST_RINGT[
- _mem.settings.ringt]))
- basic.append(ringt)
-
- camdf = RadioSetting("settings.camdf", "Display mode A",
- RadioSettingValueList(LIST_MDF, LIST_MDF[
- _mem.settings.camdf]))
- basic.append(camdf)
-
- cbmdf = RadioSetting("settings.cbmdf", "Display mode B",
- RadioSettingValueList(LIST_MDF, LIST_MDF[
- _mem.settings.cbmdf]))
- basic.append(cbmdf)
-
- if self.MODEL in ("UV-2501", "UV-2501+220", "UV-5001"):
- sync = RadioSetting("settings.sync", "A/B channel sync",
- RadioSettingValueBoolean(_mem.settings.sync))
- basic.append(sync)
- else:
- autolk = RadioSetting("settings.sync", "Auto keylock",
- RadioSettingValueBoolean(_mem.settings.sync))
- basic.append(autolk)
-
- ponmsg = RadioSetting("settings.ponmsg", "Power-on message",
- RadioSettingValueList(LIST_PONMSG, LIST_PONMSG[
- _mem.settings.ponmsg]))
- basic.append(ponmsg)
-
- wtled = RadioSetting("settings.wtled", "Standby backlight Color",
- RadioSettingValueList(LIST_COLOR, LIST_COLOR[
- _mem.settings.wtled]))
- basic.append(wtled)
-
- rxled = RadioSetting("settings.rxled", "RX backlight Color",
- RadioSettingValueList(LIST_COLOR, LIST_COLOR[
- _mem.settings.rxled]))
- basic.append(rxled)
-
- txled = RadioSetting("settings.txled", "TX backlight Color",
- RadioSettingValueList(LIST_COLOR, LIST_COLOR[
- _mem.settings.txled]))
- basic.append(txled)
-
- anil = RadioSetting("settings.anil", "ANI length",
- RadioSettingValueList(LIST_ANIL, LIST_ANIL[
- _mem.settings.anil]))
- basic.append(anil)
-
- reps = RadioSetting("settings.reps", "Relay signal (tone burst)",
- RadioSettingValueList(LIST_REPS, LIST_REPS[
- _mem.settings.reps]))
- basic.append(reps)
-
- repm = RadioSetting("settings.repm", "Relay condition",
- RadioSettingValueList(LIST_REPM, LIST_REPM[
- _mem.settings.repm]))
- basic.append(repm)
-
- if self.MODEL in ("UV-2501", "UV-2501+220", "UV-5001"):
- tdrab = RadioSetting("settings.tdrab", "TDR return time",
- RadioSettingValueList(LIST_ABR, LIST_ABR[
- _mem.settings.tdrab]))
- basic.append(tdrab)
-
- ste = RadioSetting("settings.ste", "Squelch tail eliminate",
- RadioSettingValueBoolean(_mem.settings.ste))
- basic.append(ste)
-
- rpste = RadioSetting("settings.rpste", "Repeater STE",
- RadioSettingValueList(LIST_RINGT, LIST_RINGT[
- _mem.settings.rpste]))
- basic.append(rpste)
-
- rptdl = RadioSetting("settings.rptdl", "Repeater STE delay",
- RadioSettingValueList(LIST_RPTDL, LIST_RPTDL[
- _mem.settings.rptdl]))
- basic.append(rptdl)
-
- if str(_mem.fingerprint.fp) in BTECH3:
-
- mgain = RadioSetting("settings.mgain", "Mic gain",
- RadioSettingValueInteger(0, 120,
- _mem.settings.mgain))
- basic.append(mgain)
-
- dtmfg = RadioSetting("settings.dtmfg", "DTMF gain",
- RadioSettingValueInteger(0, 60,
- _mem.settings.dtmfg))
- basic.append(dtmfg)
-
- # Advanced
- def _filter(name):
- filtered = ""
- for char in str(name):
- if char in VALID_CHARS:
- filtered += char
- else:
- filtered += " "
- return filtered
-
- _msg = self._memobj.poweron_msg
- line1 = RadioSetting("poweron_msg.line1", "Power-on message line 1",
- RadioSettingValueString(0, 6, _filter(
- _msg.line1)))
- advanced.append(line1)
- line2 = RadioSetting("poweron_msg.line2", "Power-on message line 2",
- RadioSettingValueString(0, 6, _filter(
- _msg.line2)))
- advanced.append(line2)
-
- if self.MODEL in ("UV-2501", "UV-5001"):
- vfomren = RadioSetting("settings2.vfomren", "VFO/MR switching",
- RadioSettingValueBoolean(
- _mem.settings2.vfomren))
- advanced.append(vfomren)
-
- reseten = RadioSetting("settings2.reseten", "RESET",
- RadioSettingValueBoolean(
- _mem.settings2.reseten))
- advanced.append(reseten)
-
- menuen = RadioSetting("settings2.menuen", "Menu",
- RadioSettingValueBoolean(
- _mem.settings2.menuen))
- advanced.append(menuen)
-
- # Other
- def convert_bytes_to_limit(bytes):
- limit = ""
- for byte in bytes:
- if byte < 10:
- limit += chr(byte + 0x30)
- else:
- break
- return limit
-
- if self.MODEL in ["UV-2501+220", "KT8900R"]:
- _ranges = self._memobj.ranges220
- ranges = "ranges220"
- else:
- _ranges = self._memobj.ranges
- ranges = "ranges"
-
- _limit = convert_bytes_to_limit(_ranges.vhf_low)
- val = RadioSettingValueString(0, 3, _limit)
- val.set_mutable(False)
- vhf_low = RadioSetting("%s.vhf_low" % ranges, "VHF low", val)
- other.append(vhf_low)
-
- _limit = convert_bytes_to_limit(_ranges.vhf_high)
- val = RadioSettingValueString(0, 3, _limit)
- val.set_mutable(False)
- vhf_high = RadioSetting("%s.vhf_high" % ranges, "VHF high", val)
- other.append(vhf_high)
-
- if self.MODEL in ["UV-2501+220", "KT8900R"]:
- _limit = convert_bytes_to_limit(_ranges.vhf2_low)
- val = RadioSettingValueString(0, 3, _limit)
- val.set_mutable(False)
- vhf2_low = RadioSetting("%s.vhf2_low" % ranges, "VHF2 low", val)
- other.append(vhf2_low)
-
- _limit = convert_bytes_to_limit(_ranges.vhf2_high)
- val = RadioSettingValueString(0, 3, _limit)
- val.set_mutable(False)
- vhf2_high = RadioSetting("%s.vhf2_high" % ranges, "VHF2 high", val)
- other.append(vhf2_high)
-
- _limit = convert_bytes_to_limit(_ranges.uhf_low)
- val = RadioSettingValueString(0, 3, _limit)
- val.set_mutable(False)
- uhf_low = RadioSetting("%s.uhf_low" % ranges, "UHF low", val)
- other.append(uhf_low)
-
- _limit = convert_bytes_to_limit(_ranges.uhf_high)
- val = RadioSettingValueString(0, 3, _limit)
- val.set_mutable(False)
- uhf_high = RadioSetting("%s.uhf_high" % ranges, "UHF high", val)
- other.append(uhf_high)
-
- val = RadioSettingValueString(0, 6, _filter(_mem.fingerprint.fp))
- val.set_mutable(False)
- fp = RadioSetting("fingerprint.fp", "Fingerprint", val)
- other.append(fp)
-
- # Work
- dispab = RadioSetting("settings2.dispab", "Display",
- RadioSettingValueList(LIST_AB,LIST_AB[
- _mem.settings2.dispab]))
- work.append(dispab)
-
- vfomr = RadioSetting("settings2.vfomr", "VFO/MR mode",
- RadioSettingValueList(LIST_VFOMR,LIST_VFOMR[
- _mem.settings2.vfomr]))
- work.append(vfomr)
-
- keylock = RadioSetting("settings2.keylock", "Keypad lock",
- RadioSettingValueBoolean(_mem.settings2.keylock))
- work.append(keylock)
-
- mrcha = RadioSetting("settings2.mrcha", "MR A channel",
- RadioSettingValueInteger(0, 199,
- _mem.settings2.mrcha))
- work.append(mrcha)
-
- mrchb = RadioSetting("settings2.mrchb", "MR B channel",
- RadioSettingValueInteger(0, 199,
- _mem.settings2.mrchb))
- work.append(mrchb)
-
- def convert_bytes_to_freq(bytes):
- real_freq = 0
- for byte in bytes:
- real_freq = (real_freq * 10) + byte
- return chirp_common.format_freq(real_freq * 10)
-
- def my_validate(value):
- value = chirp_common.parse_freq(value)
- if "+220" in self.MODEL:
- if 180000000 <= value and value < 210000000:
- msg = ("Can't be between 180.00000-210.00000")
- raise InvalidValueError(msg)
- elif 231000000 <= value and value < 400000000:
- msg = ("Can't be between 231.00000-400.00000")
- raise InvalidValueError(msg)
- elif "8900R" in self.MODEL:
- if 180000000 <= value and value < 240000000:
- msg = ("Can't be between 180.00000-240.00000")
- raise InvalidValueError(msg)
- elif 271000000 <= value and value < 400000000:
- msg = ("Can't be between 271.00000-400.00000")
- raise InvalidValueError(msg)
- elif 180000000 <= value and value < 400000000:
- msg = ("Can't be between 180.00000-400.00000")
- raise InvalidValueError(msg)
- return chirp_common.format_freq(value)
-
- def apply_freq(setting, obj):
- value = chirp_common.parse_freq(str(setting.value)) / 10
- for i in range(7, -1, -1):
- obj.freq[i] = value % 10
- value /= 10
-
- val1a = RadioSettingValueString(0, 10, convert_bytes_to_freq(
- _mem.vfo.a.freq))
- val1a.set_validate_callback(my_validate)
- vfoafreq = RadioSetting("vfo.a.freq", "VFO A frequency", val1a)
- vfoafreq.set_apply_callback(apply_freq, _mem.vfo.a)
- work.append(vfoafreq)
-
- val1b = RadioSettingValueString(0, 10, convert_bytes_to_freq(
- _mem.vfo.b.freq))
- val1b.set_validate_callback(my_validate)
- vfobfreq = RadioSetting("vfo.b.freq", "VFO B frequency", val1b)
- vfobfreq.set_apply_callback(apply_freq, _mem.vfo.b)
- work.append(vfobfreq)
-
- vfoashiftd = RadioSetting("vfo.a.shiftd", "VFO A shift",
- RadioSettingValueList(LIST_SHIFT, LIST_SHIFT[
- _mem.vfo.a.shiftd]))
- work.append(vfoashiftd)
-
- vfobshiftd = RadioSetting("vfo.b.shiftd", "VFO B shift",
- RadioSettingValueList(LIST_SHIFT, LIST_SHIFT[
- _mem.vfo.b.shiftd]))
- work.append(vfobshiftd)
-
- def convert_bytes_to_offset(bytes):
- real_offset = 0
- for byte in bytes:
- real_offset = (real_offset * 10) + byte
- return chirp_common.format_freq(real_offset * 10000)
-
- def apply_offset(setting, obj):
- value = chirp_common.parse_freq(str(setting.value)) / 10000
- for i in range(3, -1, -1):
- obj.offset[i] = value % 10
- value /= 10
-
- val1a = RadioSettingValueString(0, 10, convert_bytes_to_offset(
- _mem.vfo.a.offset))
- vfoaoffset = RadioSetting("vfo.a.offset",
- "VFO A offset (0.00-99.95)", val1a)
- vfoaoffset.set_apply_callback(apply_offset, _mem.vfo.a)
- work.append(vfoaoffset)
-
- val1b = RadioSettingValueString(0, 10, convert_bytes_to_offset(
- _mem.vfo.b.offset))
- vfoboffset = RadioSetting("vfo.b.offset",
- "VFO B offset (0.00-99.95)", val1b)
- vfoboffset.set_apply_callback(apply_offset, _mem.vfo.b)
- work.append(vfoboffset)
-
- vfoatxp = RadioSetting("vfo.a.power", "VFO A power",
- RadioSettingValueList(LIST_TXP,LIST_TXP[
- _mem.vfo.a.power]))
- work.append(vfoatxp)
-
- vfobtxp = RadioSetting("vfo.b.power", "VFO B power",
- RadioSettingValueList(LIST_TXP,LIST_TXP[
- _mem.vfo.b.power]))
- work.append(vfobtxp)
-
- vfoawide = RadioSetting("vfo.a.wide", "VFO A bandwidth",
- RadioSettingValueList(LIST_WIDE,LIST_WIDE[
- _mem.vfo.a.wide]))
- work.append(vfoawide)
-
- vfobwide = RadioSetting("vfo.b.wide", "VFO B bandwidth",
- RadioSettingValueList(LIST_WIDE,LIST_WIDE[
- _mem.vfo.b.wide]))
- work.append(vfobwide)
-
- vfoastep = RadioSetting("vfo.a.step", "VFO A step",
- RadioSettingValueList(LIST_STEP,LIST_STEP[
- _mem.vfo.a.step]))
- work.append(vfoastep)
-
- vfobstep = RadioSetting("vfo.b.step", "VFO B step",
- RadioSettingValueList(LIST_STEP,LIST_STEP[
- _mem.vfo.b.step]))
- work.append(vfobstep)
-
- vfoaoptsig = RadioSetting("vfo.a.optsig", "VFO A optional signal",
- RadioSettingValueList(OPTSIG_LIST,
- OPTSIG_LIST[_mem.vfo.a.optsig]))
- work.append(vfoaoptsig)
-
- vfoboptsig = RadioSetting("vfo.b.optsig", "VFO B optional signal",
- RadioSettingValueList(OPTSIG_LIST,
- OPTSIG_LIST[_mem.vfo.b.optsig]))
- work.append(vfoboptsig)
-
- vfoaspmute = RadioSetting("vfo.a.spmute", "VFO A speaker mute",
- RadioSettingValueList(SPMUTE_LIST,
- SPMUTE_LIST[_mem.vfo.a.spmute]))
- work.append(vfoaspmute)
-
- vfobspmute = RadioSetting("vfo.b.spmute", "VFO B speaker mute",
- RadioSettingValueList(SPMUTE_LIST,
- SPMUTE_LIST[_mem.vfo.b.spmute]))
- work.append(vfobspmute)
-
- vfoascr = RadioSetting("vfo.a.scramble", "VFO A scramble",
- RadioSettingValueBoolean(_mem.vfo.a.scramble))
- work.append(vfoascr)
-
- vfobscr = RadioSetting("vfo.b.scramble", "VFO B scramble",
- RadioSettingValueBoolean(_mem.vfo.b.scramble))
- work.append(vfobscr)
-
- vfoascode = RadioSetting("vfo.a.scode", "VFO A PTT-ID",
- RadioSettingValueList(PTTIDCODE_LIST,
- PTTIDCODE_LIST[_mem.vfo.a.scode]))
- work.append(vfoascode)
-
- vfobscode = RadioSetting("vfo.b.scode", "VFO B PTT-ID",
- RadioSettingValueList(PTTIDCODE_LIST,
- PTTIDCODE_LIST[_mem.vfo.b.scode]))
- work.append(vfobscode)
-
- pttid = RadioSetting("settings.pttid", "PTT ID",
- RadioSettingValueList(PTTID_LIST,
- PTTID_LIST[_mem.settings.pttid]))
- work.append(pttid)
-
- #FM presets
- def fm_validate(value):
- if value == 0:
- return chirp_common.format_freq(value)
- if not (87.5 <= value and value <= 108.0): # 87.5-108MHz
- msg = ("FM-Preset-Frequency: Must be between 87.5 and 108 MHz")
- raise InvalidValueError(msg)
- return value
-
- def apply_fm_preset_name(setting, obj):
- valstring = str (setting.value)
- for i in range(0,6):
- if valstring[i] in VALID_CHARS:
- obj[i] = valstring[i]
- else:
- obj[i] = '0xff'
-
- def apply_fm_freq(setting, obj):
- value = chirp_common.parse_freq(str(setting.value)) / 10
- for i in range(7, -1, -1):
- obj.freq[i] = value % 10
- value /= 10
-
- _presets = self._memobj.fm_radio_preset
- i = 1
- for preset in _presets:
- line = RadioSetting("fm_presets_"+ str(i), "Station name " + str(i),
- RadioSettingValueString(0, 6, _filter(
- preset.broadcast_station_name)))
- line.set_apply_callback(apply_fm_preset_name,
- preset.broadcast_station_name)
-
- val = RadioSettingValueFloat(0, 108, convert_bytes_to_freq(preset.freq))
- fmfreq = RadioSetting("fm_presets_"+ str(i) + "_freq", "Frequency "+ str(i), val)
- val.set_validate_callback(fm_validate)
- fmfreq.set_apply_callback(apply_fm_freq, preset)
- fm_presets.append(line)
- 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):
- _settings = self._memobj.settings
- for element in settings:
- if not isinstance(element, RadioSetting):
- if element.get_name() == "fm_preset":
- self._set_fm_preset(element)
- else:
- 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:
- 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
-
# Declaring Aliases (Clones of the real radios)
class JT2705M(chirp_common.Alias):
@@ -2630,6 +3109,7 @@
class UV2501_220(BTech):
"""Baofeng Tech UV2501+220"""
MODEL = "UV-2501+220"
+ BANDS = 3
_magic = MSTRING_220
_id2 = UV2501_220pp_id
_fileid = [UV2501_220G3_fp,
@@ -2647,6 +3127,8 @@
UV5001G2_fp,
UV5001alpha_fp,
UV5001pp_fp]
+ _power_levels = [chirp_common.PowerLevel("High", watts=50),
+ chirp_common.PowerLevel("Low", watts=10)]
@directory.register
@@ -2698,6 +3180,7 @@
"""QYT KT8900R"""
VENDOR = "QYT"
MODEL = "KT8900R"
+ BANDS = 3
_vhf_range = (136000000, 175000000)
_220_range = (240000000, 271000000)
_uhf_range = (400000000, 481000000)
@@ -2720,3 +3203,377 @@
_magic = MSTRING_KT8900
_fileid = [LT588UV_fp,
LT588UV_fp1]
+ _power_levels = [chirp_common.PowerLevel("High", watts=60),
+ chirp_common.PowerLevel("Low", watts=10)]
+
+
+COLOR_MEM_FORMAT = """
+#seekto 0x0000;
+struct {
+ lbcd rxfreq[4];
+ lbcd txfreq[4];
+ ul16 rxtone;
+ ul16 txtone;
+ u8 unknown0:4,
+ scode:4;
+ u8 unknown1:2,
+ spmute:1,
+ unknown2:3,
+ optsig:2;
+ u8 unknown3:3,
+ scramble:1,
+ unknown4:3,
+ power:1;
+ u8 unknown5:1,
+ wide:1,
+ unknown6:2,
+ bcl:1,
+ add:1,
+ pttid:2;
+} memory[200];
+
+#seekto 0x0E00;
+struct {
+ u8 tmr;
+ u8 unknown1;
+ u8 sql;
+ u8 unknown2[2];
+ u8 tot;
+ u8 apo;
+ u8 unknown3;
+ u8 abr;
+ u8 beep;
+ u8 unknown4[4];
+ u8 dtmfst;
+ u8 unknown5[2];
+ u8 screv;
+ u8 unknown6[2];
+ u8 pttid;
+ u8 pttlt;
+ u8 unknown7;
+ u8 emctp;
+ u8 emcch;
+ u8 sigbp;
+ u8 unknown8;
+ u8 camdf;
+ u8 cbmdf;
+ u8 ccmdf;
+ u8 cdmdf;
+ u8 langua;
+ u8 sync; // BTech radios use this as the display sync
+ // setting, other radios use this as the auto
+ // keypad lock setting
+ u8 mainfc;
+ u8 mainbc;
+ u8 menufc;
+ u8 menubc;
+ u8 stafc;
+ u8 stabc;
+ u8 sigfc;
+ u8 sigbc;
+ u8 rxfc;
+ u8 txfc;
+ u8 txdisp;
+ u8 unknown9[5];
+ u8 anil;
+ u8 reps;
+ u8 repm;
+ u8 tmrmr;
+ u8 ste;
+ u8 rpste;
+ u8 rptdl;
+ u8 dtmfg;
+ u8 mgain;
+ u8 skiptx;
+ u8 scmode;
+} settings;
+
+#seekto 0x0E80;
+struct {
+ u8 unknown1;
+ u8 vfomr;
+ u8 keylock;
+ u8 unknown2;
+ u8 unknown3:4,
+ vfomren:1,
+ unknown4:1,
+ reseten:1,
+ menuen:1;
+ u8 unknown5[11];
+ u8 dispab;
+ u8 unknown6[2];
+ u8 menu;
+ u8 unknown7[7];
+ u8 vfomra;
+ u8 vfomrb;
+ u8 vfomrc;
+ u8 vfomrd;
+ u8 mrcha;
+ u8 mrchb;
+ u8 mrchc;
+ u8 mrchd;
+} settings2;
+
+struct settings_vfo {
+ u8 freq[8];
+ u8 offset[6];
+ u8 unknown2[2];
+ ul16 rxtone;
+ ul16 txtone;
+ u8 scode;
+ u8 spmute;
+ u8 optsig;
+ u8 scramble;
+ u8 wide;
+ u8 power;
+ u8 shiftd;
+ u8 step;
+ u8 unknown3[4];
+};
+
+#seekto 0x0F00;
+struct {
+ struct settings_vfo a;
+ struct settings_vfo b;
+ struct settings_vfo c;
+ struct settings_vfo d;
+} vfo;
+
+#seekto 0x0F80;
+struct {
+ char line1[8];
+ char line2[8];
+ char line3[8];
+ char line4[8];
+ char line5[8];
+ char line6[8];
+ char line7[8];
+ char line8[8];
+} poweron_msg;
+
+#seekto 0x1000;
+struct {
+ char name[8];
+ u8 unknown1[8];
+} 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 0x3D80;
+struct {
+ u8 vhf_low[3];
+ u8 vhf_high[3];
+ u8 unknown1[4];
+ u8 unknown2[6];
+ u8 vhf2_low[3];
+ u8 vhf2_high[3];
+ u8 unknown3[4];
+ u8 unknown4[6];
+ u8 uhf_low[3];
+ u8 uhf_high[3];
+ u8 unknown5[4];
+ u8 unknown6[6];
+ u8 uhf2_low[3];
+ u8 uhf2_high[3];
+} ranges;
+
+#seekto 0x3F70;
+struct {
+ char fp[6];
+} fingerprint;
+
+"""
+
+
+class BTechColor(BTechMobileCommon):
+ """BTECH's Color LCD Mobile and alike radios"""
+ COLOR_LCD = True
+ NAME_LENGTH = 8
+
+ def process_mmap(self):
+ """Process the mem map into the mem object"""
+
+ # Get it
+ self._memobj = bitwise.parse(COLOR_MEM_FORMAT, self._mmap)
+
+ # load specific parameters from the radio image
+ self.set_options()
+
+ def set_options(self):
+ """This is to read the options from the image and set it in the
+ environment, for now just the limits of the freqs in the VHF/UHF
+ ranges"""
+
+ # setting the correct ranges for each radio type
+ ranges = self._memobj.ranges
+
+ # the normal dual bands
+ vhf = _decode_ranges(ranges.vhf_low, ranges.vhf_high)
+ uhf = _decode_ranges(ranges.uhf_low, ranges.uhf_high)
+
+ # DEBUG
+ LOG.info("Radio ranges: VHF %d to %d" % vhf)
+ LOG.info("Radio ranges: UHF %d to %d" % uhf)
+
+ # the additional bands
+ if self.MODEL in ["KT8900D", ]:
+ # 200Mhz band
+ vhf2 = _decode_ranges(ranges.vhf2_low, ranges.vhf2_high)
+ LOG.info("Radio ranges: VHF(220) %d to %d" % vhf2)
+ self._220_range = vhf2
+
+ # 350Mhz band
+ uhf2 = _decode_ranges(ranges.uhf2_low, ranges.uhf2_high)
+ LOG.info("Radio ranges: UHF(350) %d to %d" % uhf2)
+ self._350_range = uhf2
+
+ # set the class with the real data
+ self._vhf_range = vhf
+ self._uhf_range = uhf
+
+
+(a)directory.register
+class KT7900D(BTechColor):
+ """QYT KT7900D"""
+ VENDOR = "QYT"
+ MODEL = "KT7900D"
+ BANDS = 4
+ _vhf_range = (136000000, 175000000)
+ _220_range = (200000000, 271000000)
+ _uhf_range = (400000000, 481000000)
+ _350_range = (350000000, 371000000)
+ _magic = MSTRING_KT8900D
+ _fileid = [KT7900D_fp, ]
+
+
+(a)directory.register
+class KT8900D(BTechColor):
+ """QYT KT8900D"""
+ VENDOR = "QYT"
+ MODEL = "KT8900D"
+ BANDS = 2
+ _vhf_range = (136000000, 175000000)
+ _uhf_range = (400000000, 481000000)
+ _magic = MSTRING_KT8900D
+ _fileid = [KT8900D_fp, ]
1
1
Tested changes:
[Dan Smith <dsmith(a)danplanet.com>] Avoid confusing BTECH UV-5X3 users with UV-5X driver
Reportedly people that are buying the (new) BTECH UV-5X3 radio
are confused and choosing the Baofeng UV-5X model from the menus,
which won't work. Many are just outright returning the radio as
a result, assuming it's broken.
Since there are a million UV-5R variants and this is likely to
get worse, this patch adds a blacklist of similar magic strings
from radios that may be confused easily. If we fail to probe the
radio that was selected, we can probe for the blacklist magics,
and if any reply, raise a specific error to the user indicating
that they chose the wrong model.
#4539
[Tom Hayward <tom(a)tomh.us>] [id880] Fix typo in charset definition. #281
[Tom Hayward <tom(a)tomh.us>] [thf6a] Support full charset (ASCII). Fixes #141
[Tom Hayward <tom(a)tomh.us>] [id880] Support full charset. Fixes #281
[Tom Hayward <tom(a)tomh.us>] [vx5] Support full charset (ASCII). Fixes #292
[Tom Hayward <tom(a)tomh.us>] [id31a] set used bit when creating new memory, clear when deleting. Fixes #269
[Tom Hayward <tom(a)tomh.us>] Support PyGTK < 2.22 in bank edit. Fixes #231
[Tom Hayward <tom(a)tomh.us>] [d710] [v71] [d72] Fix tone list (not all tones are supported). Fixes #212
[Dan Smith <dsmith(a)danplanet.com>] [vx7] Fix setting memory power levels on 220MHz band
Fixes #214
[Dan Smith <dsmith(a)danplanet.com>] fips: Pennsylvania FIPS code was wrong. #117
[Marco Filippi <iz3gme.marco(a)gmail.com>] Consider lower bound frequency of each valid_band as valid
Fix bug #181
[Tom Hayward <tom(a)tomh.us>] tmd700: allow 8-char names. Fixes #176
[Dan Smith <dsmith(a)danplanet.com>] Fix the "blind deletion" problem, as well as properly direct copy/paste
Fixes #172
[David Griffith <dave(a)661.org>] Bug #155 fix: VX-7 1.25m power levels
[David Griffith <dave(a)661.org>] New INSTALL and README files
Fixes #122
[Tom Hayward <tom(a)tomh.us>] thd72: only use hardware flow on OS X. Fixes #166
[Marco Filippi <iz3gme.marco(a)gmail.com>] [FT817] Tone freq not set correctly
Same as #88 for FT857, to avoid code duplication fix code have been moved from
ft857 to its ancestor class
Fix bug #163
[Tom Hayward <tom(a)tomh.us>] Fix Mac .app so paths with spaces work. Fixes Bug #145
Full log:
Started by an SCM change
Building in workspace /var/lib/jenkins/jobs/chirp-test/workspace
[workspace] $ hg showconfig paths.default
[workspace] $ hg pull --rev default
[workspace] $ hg update --clean --rev default
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
[workspace] $ hg log --rev . --template {node}
[workspace] $ hg log --rev . --template {rev}
[workspace] $ hg log --rev 4569107adfccc72db9d12d8ecfcb7b97cfe06c65
[workspace] $ hg log --template "<changeset node='{node}' author='{author|xmlescape}' rev='{rev}' date='{date}'><msg>{desc|xmlescape}</msg><added>{file_adds|stringify|xmlescape}</added><deleted>{file_dels|stringify|xmlescape}</deleted><files>{files|stringify|xmlescape}</files><parents>{parents}</parents></changeset>\n" --rev default:0 --follow --prune 4569107adfccc72db9d12d8ecfcb7b97cfe06c65
No emails were triggered.
[workspace] $ /bin/sh -xe /tmp/hudson2387810259790317580.sh
[workspace] $ /bin/sh -xe /tmp/hudson1038875639807407219.sh
+ PATH=/usr/bin:/bin:/usr/local/bin ./run_all_tests.sh
test_bit_array (tests.unit.test_bitwise.TestBitType) ... ok
test_bit_array_fail (tests.unit.test_bitwise.TestBitType) ... ok
test_bitfield_u16 (tests.unit.test_bitwise.TestBitfieldTypes) ... ok
test_bitfield_u24 (tests.unit.test_bitwise.TestBitfieldTypes) ... ok
test_bitfield_u8 (tests.unit.test_bitwise.TestBitfieldTypes) ... ok
test_bitfield_ul16 (tests.unit.test_bitwise.TestBitfieldTypes) ... ok
test_bitfield_ul24 (tests.unit.test_bitwise.TestBitfieldTypes) ... ok
test_bbcd (tests.unit.test_bitwise.TestBitwiseBCDTypes) ... ok
test_bbcd_array (tests.unit.test_bitwise.TestBitwiseBCDTypes) ... ok
test_lbcd (tests.unit.test_bitwise.TestBitwiseBCDTypes) ... ok
test_lbcd_array (tests.unit.test_bitwise.TestBitwiseBCDTypes) ... ok
test_int_array (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_u16 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_u24 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_u32 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_u8 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_ul16 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_ul24 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_ul32 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_char (tests.unit.test_bitwise.TestBitwiseCharTypes) ... ok
test_string (tests.unit.test_bitwise.TestBitwiseCharTypes) ... ok
test_string_invalid_chars (tests.unit.test_bitwise.TestBitwiseCharTypes) ... ok
test_string_wrong_length (tests.unit.test_bitwise.TestBitwiseCharTypes) ... ok
test_comment_cppstyle (tests.unit.test_bitwise.TestBitwiseComments) ... ok
test_comment_inline_cppstyle (tests.unit.test_bitwise.TestBitwiseComments) ... ok
test_missing_semicolon (tests.unit.test_bitwise.TestBitwiseErrors) ... ok
test_seek (tests.unit.test_bitwise.TestBitwiseSeek) ... ok
test_seekto (tests.unit.test_bitwise.TestBitwiseSeek) ... ok
test_struct_one_element (tests.unit.test_bitwise.TestBitwiseStructTypes) ... ok
test_struct_two_elements (tests.unit.test_bitwise.TestBitwiseStructTypes) ... ok
test_struct_writes (tests.unit.test_bitwise.TestBitwiseStructTypes) ... ok
split_tone_encode_test_cross_dtcs_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_cross_none_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_cross_none_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_cross_tone_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_cross_tone_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_none (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_tsql (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_dtcs_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_dtcs_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_none_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_none_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_tone_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_tone_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_none (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_tsql (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_fix_rounded_step_250 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_fix_rounded_step_500 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_fix_rounded_step_750 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_is_12_5 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_is_2_5 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_is_5_0 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_is_6_25 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_is_fractional_step (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_required_step (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_required_step_fail (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_format_freq (tests.unit.test_chirp_common.TestUtilityFunctions) ... ok
test_parse_freq_bad (tests.unit.test_chirp_common.TestUtilityFunctions) ... ok
test_parse_freq_decimal (tests.unit.test_chirp_common.TestUtilityFunctions) ... ok
test_parse_freq_whitespace (tests.unit.test_chirp_common.TestUtilityFunctions) ... ok
test_parse_freq_whole (tests.unit.test_chirp_common.TestUtilityFunctions) ... ok
test_ensure_has_calls_almost_full (tests.unit.test_import_logic.DstarTests) ... ok
test_ensure_has_calls_empty (tests.unit.test_import_logic.DstarTests) ... ok
test_ensure_has_calls_partial (tests.unit.test_import_logic.DstarTests) ... ok
test_ensure_has_calls_rptcall_full1 (tests.unit.test_import_logic.DstarTests) ... ok
test_ensure_has_calls_rptcall_full2 (tests.unit.test_import_logic.DstarTests) ... ok
test_ensure_has_calls_urcall_full (tests.unit.test_import_logic.DstarTests) ... ok
test_import_bank (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_dtcs_diffA_dtcs (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_dtcs_diffB_dtcs (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_duplex_negative (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_duplex_too_big_vhf (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_duplex_uhf (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_duplex_vhf (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mem (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mem_with_errors (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mem_with_warnings (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mode_invalid (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mode_valid_am (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mode_valid_fm (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_name (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_power_closest (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_power_no_dst (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_power_no_src (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_power_same (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_tone_diffA_tsql (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_tone_diffB_tsql (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_mapping (tests.unit.test_mappingmodel.TestBaseBank) ... ok
test_mapping_eq (tests.unit.test_mappingmodel.TestBaseBank) ... ok
test_base_class (tests.unit.test_mappingmodel.TestBaseBankModel) ... ok
test_get_name (tests.unit.test_mappingmodel.TestBaseBankModel) ... ok
test_mapping (tests.unit.test_mappingmodel.TestBaseMapping) ... ok
test_mapping_eq (tests.unit.test_mappingmodel.TestBaseMapping) ... ok
test_base_class (tests.unit.test_mappingmodel.TestBaseMappingModel) ... ok
test_get_name (tests.unit.test_mappingmodel.TestBaseMappingModel) ... ok
test_base_class (tests.unit.test_mappingmodel.TestBaseMappingModelIndexInterface) ... ok
test_add_memory_to_mapping (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_get_mapping_memories (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_get_mappings (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_get_memory_mappings (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_get_num_mappings (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_remove_memory_from_mapping (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_remove_memory_from_mapping_no_bank (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_remove_memory_from_mapping_wrong_bank (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_icom_bank (tests.unit.test_mappingmodel.TestIcomBanks) ... ok
test_mapping (tests.unit.test_mappingmodel.TestIcomBanks) ... ok
test_mapping_eq (tests.unit.test_mappingmodel.TestIcomBanks) ... ok
test_add_memory_to_mapping (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_index_bounds (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_mapping_memories (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_mappings (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_memory_index (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_memory_mappings (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_next_mapping_index (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_num_mappings (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_remove_memory_from_mapping (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_remove_memory_from_mapping_no_bank (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_remove_memory_from_mapping_wrong_bank (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_set_memory_index (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_set_memory_index_bad_bank (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_set_memory_index_bad_index (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_auto_tone_mode_cross (tests.unit.test_memedit_edits.TestEdits) ... ok
test_auto_tone_mode_dtcs (tests.unit.test_memedit_edits.TestEdits) ... ok
test_auto_tone_mode_dtcs_pol (tests.unit.test_memedit_edits.TestEdits) ... ok
test_auto_tone_mode_dtcs_rx (tests.unit.test_memedit_edits.TestEdits) ... ok
test_auto_tone_mode_tone (tests.unit.test_memedit_edits.TestEdits) ... ok
test_auto_tone_mode_tsql (tests.unit.test_memedit_edits.TestEdits) ... ok
test_init (tests.unit.test_platform.Win32PlatformTest) ... ok
test_serial_ports_bad_portnames (tests.unit.test_platform.Win32PlatformTest) ... ok
test_serial_ports_sorted (tests.unit.test_platform.Win32PlatformTest) ... ok
test_apply_callback (tests.unit.test_settings.TestSettingContainers) ... ok
test_radio_setting (tests.unit.test_settings.TestSettingContainers) ... ok
test_radio_setting_group (tests.unit.test_settings.TestSettingContainers) ... ok
test_radio_setting_multi (tests.unit.test_settings.TestSettingContainers) ... ok
test_changed (tests.unit.test_settings.TestSettingValues) ... ok
test_radio_setting_value_boolean (tests.unit.test_settings.TestSettingValues) ... ok
test_radio_setting_value_float (tests.unit.test_settings.TestSettingValues) ... ok
test_radio_setting_value_integer (tests.unit.test_settings.TestSettingValues) ... ok
test_radio_setting_value_list (tests.unit.test_settings.TestSettingValues) ... ok
test_radio_setting_value_string (tests.unit.test_settings.TestSettingValues) ... ok
test_validate_callback (tests.unit.test_settings.TestSettingValues) ... ok
test_delete_hole_with_all (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
test_delete_hole_with_all_full (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
test_delete_hole_with_hole (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
test_delete_hole_without_hole (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
test_insert_hole_with_space (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
test_insert_hole_without_space (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
----------------------------------------------------------------------
Ran 151 tests in 0.053s
OK
Patch 'tip' is OK
Checking for PEP8 regressions...
./chirp/platform.py:255:80: E501 line too long (82 > 79 characters)
./chirp/ui/mainapp.py:1909:80: E501 line too long (82 > 79 characters)
./chirp/ui/mainapp.py:1965:80: E501 line too long (82 > 79 characters)
real 0m7.716s
user 0m7.608s
sys 0m0.032s
================================================
Tests OK
+ cat /var/lib/jenkins/.chirp/debug.log
[2017-02-16 19:29:04,296] chirp.logger - DEBUG: CHIRP 0.3.0dev on Linux - Ubuntu 16.04.1 LTS (Python 2.7.12)
[2017-02-16 19:29:04,332] chirp.directory - INFO: Registered Kenwood_TH-D7 = THD7Radio
[2017-02-16 19:29:04,332] chirp.directory - INFO: Registered Kenwood_TH-D7G = THD7GRadio
[2017-02-16 19:29:04,333] chirp.directory - INFO: Registered Kenwood_TM-D700 = TMD700Radio
[2017-02-16 19:29:04,333] chirp.directory - INFO: Registered Kenwood_TM-V7 = TMV7Radio
[2017-02-16 19:29:04,333] chirp.directory - INFO: Registered Kenwood_TM-G707 = TMG707Radio
[2017-02-16 19:29:04,333] chirp.directory - INFO: Registered Kenwood_TH-G71 = THG71Radio
[2017-02-16 19:29:04,333] chirp.directory - INFO: Registered Kenwood_TH-F6 = THF6ARadio
[2017-02-16 19:29:04,333] chirp.directory - INFO: Registered Kenwood_TH-F7 = THF7ERadio
[2017-02-16 19:29:04,333] chirp.directory - INFO: Registered Kenwood_TM-D710 = TMD710Radio
[2017-02-16 19:29:04,333] chirp.directory - INFO: Registered Kenwood_TH-D72_live_mode = THD72Radio
[2017-02-16 19:29:04,333] chirp.directory - INFO: Registered Kenwood_TM-V71 = TMV71Radio
[2017-02-16 19:29:04,333] chirp.directory - INFO: Registered Kenwood_TM-D710G = TMD710GRadio
[2017-02-16 19:29:04,333] chirp.directory - INFO: Registered Kenwood_TH-K2 = THK2Radio
[2017-02-16 19:29:04,334] chirp.directory - INFO: Registered Kenwood_TM-271 = TM271Radio
[2017-02-16 19:29:04,334] chirp.directory - INFO: Registered Kenwood_TM-281 = TM281Radio
[2017-02-16 19:29:04,334] chirp.directory - INFO: Registered Kenwood_TM-471 = TM471Radio
[2017-02-16 19:29:04,334] chirp.directory - INFO: Registered Icom_7200 = Icom7200Radio
[2017-02-16 19:29:04,334] chirp.directory - INFO: Registered Icom_IC-7000 = Icom7000Radio
[2017-02-16 19:29:04,334] chirp.directory - INFO: Registered Icom_IC-7100 = Icom7100Radio
[2017-02-16 19:29:04,334] chirp.directory - INFO: Registered Icom_746 = Icom746Radio
[2017-02-16 19:29:04,337] chirp.directory - INFO: Registered Alinco_DR03T = DR03Radio
[2017-02-16 19:29:04,337] chirp.directory - INFO: Registered Alinco_DR06T = DR06Radio
[2017-02-16 19:29:04,337] chirp.directory - INFO: Registered Alinco_DR135T = DR135Radio
[2017-02-16 19:29:04,337] chirp.directory - INFO: Registered Alinco_DR235T = DR235Radio
[2017-02-16 19:29:04,337] chirp.directory - INFO: Registered Alinco_DR435T = DR435Radio
[2017-02-16 19:29:04,337] chirp.directory - INFO: Registered Alinco_DJ596 = DJ596Radio
[2017-02-16 19:29:04,337] chirp.directory - INFO: Registered Jetstream_JT220M = JT220MRadio
[2017-02-16 19:29:04,337] chirp.directory - INFO: Registered Alinco_DJ175 = DJ175Radio
[2017-02-16 19:29:04,337] chirp.directory - INFO: Registered Alinco_DJ-G7EG = AlincoDJG7EG
[2017-02-16 19:29:04,338] chirp.directory - INFO: Registered AnyTone_5888UV = AnyTone5888UVRadio
[2017-02-16 19:29:04,338] chirp.directory - INFO: Registered Intek_HR-2040 = IntekHR2040Radio
[2017-02-16 19:29:04,338] chirp.directory - INFO: Registered Polmar_DB-50M = PolmarDB50MRadio
[2017-02-16 19:29:04,338] chirp.directory - INFO: Registered Powerwerx_DB-750X = PowerwerxDB750XRadio
[2017-02-16 19:29:04,338] chirp.directory - INFO: Registered AnyTone_TERMN-8R = AnyToneTERMN8RRadio
[2017-02-16 19:29:04,338] chirp.directory - INFO: Registered AnyTone_OBLTR-8R = AnyToneOBLTR8RRadio
[2017-02-16 19:29:04,339] chirp.directory - INFO: Registered Baofeng_UV-3R = UV3RRadio
[2017-02-16 19:29:04,340] chirp.directory - INFO: Registered Baofeng_BF-A58 = BFA58
[2017-02-16 19:29:04,340] chirp.directory - INFO: Registered Baofeng_UV-82WP = UV82WP
[2017-02-16 19:29:04,340] chirp.directory - INFO: Registered Baofeng_GT-3WP = GT3WP
[2017-02-16 19:29:04,340] chirp.directory - INFO: Registered Retevis_RT6 = RT6
[2017-02-16 19:29:04,340] chirp.directory - INFO: Registered Baojie_BJ-9900 = BJ9900Radio
[2017-02-16 19:29:04,342] chirp.directory - INFO: Registered Baofeng_UV-5R = BaofengUV5RGeneric
[2017-02-16 19:29:04,342] chirp.directory - INFO: Registered Baofeng_F-11 = BaofengF11Radio
[2017-02-16 19:29:04,342] chirp.directory - INFO: Registered Baofeng_UV-82 = BaofengUV82Radio
[2017-02-16 19:29:04,342] chirp.directory - INFO: Registered Baofeng_UV-6 = BaofengUV6Radio
[2017-02-16 19:29:04,342] chirp.directory - INFO: Registered Intek_KT-980HP = IntekKT980Radio
[2017-02-16 19:29:04,342] chirp.directory - INFO: Registered Baofeng_BF-F8HP = BaofengBFF8HPRadio
[2017-02-16 19:29:04,342] chirp.directory - INFO: Registered Baofeng_UV-82HP = BaofengUV82HPRadio
[2017-02-16 19:29:04,342] chirp.directory - INFO: Registered Baojie_BJ-UV55 = BaojieBJUV55Radio
[2017-02-16 19:29:04,344] chirp.directory - INFO: Registered BTECH_UV-2501 = UV2501
[2017-02-16 19:29:04,344] chirp.directory - INFO: Registered BTECH_UV-2501+220 = UV2501_220
[2017-02-16 19:29:04,344] chirp.directory - INFO: Registered BTECH_UV-5001 = UV5001
[2017-02-16 19:29:04,344] chirp.directory - INFO: Registered WACCOM_MINI-8900 = MINI8900
[2017-02-16 19:29:04,344] chirp.directory - INFO: Registered QYT_KT-UV980 = KTUV980
[2017-02-16 19:29:04,344] chirp.directory - INFO: Registered QYT_KT8900 = KT9800
[2017-02-16 19:29:04,344] chirp.directory - INFO: Registered QYT_KT8900R = KT9800R
[2017-02-16 19:29:04,345] chirp.directory - INFO: Registered LUITON_LT-588UV = LT588UV
[2017-02-16 19:29:04,345] chirp.directory - INFO: Registered Feidaxin_FD-268A = FD268ARadio
[2017-02-16 19:29:04,345] chirp.directory - INFO: Registered Feidaxin_FD-268B = FD268BRadio
[2017-02-16 19:29:04,345] chirp.directory - INFO: Registered Feidaxin_FD-288A = FD288ARadio
[2017-02-16 19:29:04,345] chirp.directory - INFO: Registered Feidaxin_FD-288B = FD288BRadio
[2017-02-16 19:29:04,345] chirp.directory - INFO: Registered Feidaxin_FD-150A = FD150ARadio
[2017-02-16 19:29:04,345] chirp.directory - INFO: Registered Feidaxin_FD-160A = FD160ARadio
[2017-02-16 19:29:04,345] chirp.directory - INFO: Registered Feidaxin_FD-450A = FD450ARadio
[2017-02-16 19:29:04,345] chirp.directory - INFO: Registered Feidaxin_FD-460A = FD460ARadio
[2017-02-16 19:29:04,345] chirp.directory - INFO: Registered Feidaxin_FD-460UH = FD460UHRadio
[2017-02-16 19:29:04,346] chirp.directory - INFO: Registered Yaesu_FT-1802M = FT1802Radio
[2017-02-16 19:29:04,347] chirp.directory - INFO: Registered Yaesu_FT-1D_R = FT1Radio
[2017-02-16 19:29:04,348] chirp.directory - INFO: Registered Yaesu_FT-2800M = FT2800Radio
[2017-02-16 19:29:04,348] chirp.directory - INFO: Registered Yaesu_FT-2900R_1900R = FT2900Radio
[2017-02-16 19:29:04,350] chirp.directory - INFO: Registered Yaesu_FT-50 = FT50Radio
[2017-02-16 19:29:04,352] chirp.directory - INFO: Registered Yaesu_FT-60 = FT60Radio
[2017-02-16 19:29:04,352] chirp.directory - INFO: Registered Yaesu_FT-7800_7900 = FT7800Radio
[2017-02-16 19:29:04,353] chirp.directory - INFO: Registered Yaesu_FT-8800 = FT8800Radio
[2017-02-16 19:29:04,353] chirp.directory - INFO: Registered Yaesu_FT-8900 = FT8900Radio
[2017-02-16 19:29:04,354] chirp.directory - INFO: Registered Yaesu_FT-8100 = FT8100Radio
[2017-02-16 19:29:04,355] chirp.directory - INFO: Registered Yaesu_FT-817 = FT817Radio
[2017-02-16 19:29:04,355] chirp.directory - INFO: Registered Yaesu_FT-817ND = FT817NDRadio
[2017-02-16 19:29:04,355] chirp.directory - INFO: Registered Yaesu_FT-817ND_US = FT817NDUSRadio
[2017-02-16 19:29:04,357] chirp.directory - INFO: Registered Yaesu_FT-857_897 = FT857Radio
[2017-02-16 19:29:04,357] chirp.directory - INFO: Registered Yaesu_FT-857_897_US = FT857USRadio
[2017-02-16 19:29:04,357] chirp.directory - INFO: Registered Yaesu_FT-90 = FT90Radio
[2017-02-16 19:29:04,357] chirp.directory - INFO: Registered Yaesu_FTM-350 = FTM350Radio
[2017-02-16 19:29:04,358] chirp.directory - INFO: Registered Generic_CSV = CSVRadio
[2017-02-16 19:29:04,358] chirp.directory - INFO: Registered Commander_KG-UV = CommanderCSVRadio
[2017-02-16 19:29:04,358] chirp.directory - INFO: Registered RT_Systems_CSV = RTCSVRadio
[2017-02-16 19:29:04,359] chirp.directory - INFO: Registered ARRL_Travel_Plus = TpeRadio
[2017-02-16 19:29:04,368] chirp.directory - INFO: Registered Generic_XML = XMLRadio
[2017-02-16 19:29:04,368] chirp.directory - INFO: Registered BTECH_GMRS-V1 = GMRSV1
[2017-02-16 19:29:04,371] chirp.directory - INFO: Registered Baofeng_BF-888 = H777Radio
[2017-02-16 19:29:04,371] chirp.directory - INFO: Registered HobbyPCB_RS-UV3 = HobbyPCBRSUV3Radio
[2017-02-16 19:29:04,372] chirp.directory - INFO: Registered Icom_IC-208H = IC208Radio
[2017-02-16 19:29:04,372] chirp.directory - INFO: Registered Icom_IC-2100H = IC2100Radio
[2017-02-16 19:29:04,372] chirp.directory - INFO: Registered Icom_IC-2200H = IC2200Radio
[2017-02-16 19:29:04,372] chirp.directory - INFO: Registered Icom_IC-2720H = IC2720Radio
[2017-02-16 19:29:04,372] chirp.directory - INFO: Registered Icom_IC-2820H = IC2820Radio
[2017-02-16 19:29:04,373] chirp.directory - INFO: Registered Icom_IC-91_92AD = IC9xRadio
[2017-02-16 19:29:04,373] chirp.directory - INFO: Registered Icom_IC-Q7A = ICQ7Radio
[2017-02-16 19:29:04,373] chirp.directory - INFO: Registered Icom_IC-T70 = ICT70Radio
[2017-02-16 19:29:04,374] chirp.directory - INFO: Registered Icom_IC-T7H = ICT7HRadio
[2017-02-16 19:29:04,374] chirp.directory - INFO: Registered Icom_IC-T8A = ICT8ARadio
[2017-02-16 19:29:04,374] chirp.directory - INFO: Registered Icom_IC-W32A = ICW32ARadio
[2017-02-16 19:29:04,374] chirp.directory - INFO: Registered Icom_IC-W32E = ICW32ERadio
[2017-02-16 19:29:04,374] chirp.directory - INFO: Registered Icom_IC-V82_U82 = ICx8xRadio
[2017-02-16 19:29:04,375] chirp.directory - INFO: Registered Icom_ID-31A = ID31Radio
[2017-02-16 19:29:04,375] chirp.directory - INFO: Registered Icom_ID-51 = ID51Radio
[2017-02-16 19:29:04,375] chirp.directory - INFO: Registered Icom_ID-51_Plus = ID51PLUSRadio
[2017-02-16 19:29:04,375] chirp.directory - INFO: Registered Icom_ID-800H_v2 = ID800v2Radio
[2017-02-16 19:29:04,375] chirp.directory - INFO: Registered Icom_ID-880H = ID880Radio
[2017-02-16 19:29:04,375] chirp.directory - INFO: Registered Icom_ID-80H = ID80Radio
[2017-02-16 19:29:04,376] chirp.directory - INFO: Registered Kenwood_HMK = HMKRadio
[2017-02-16 19:29:04,376] chirp.directory - INFO: Registered Kenwood_ITM = ITMRadio
[2017-02-16 19:29:04,376] chirp.directory - INFO: Registered Wouxun_KG-UV8D = KGUV8DRadio
[2017-02-16 19:29:04,377] chirp.directory - INFO: Registered KYD_NC-630A = NC630aRadio
[2017-02-16 19:29:04,377] chirp.directory - INFO: Registered KYD_IP-620 = IP620Radio
[2017-02-16 19:29:04,377] chirp.directory - INFO: Registered Leixen_VV-898 = LeixenVV898Radio
[2017-02-16 19:29:04,377] chirp.directory - INFO: Registered Jetstream_JT270M = JetstreamJT270MRadio
[2017-02-16 19:29:04,377] chirp.directory - INFO: Registered Jetstream_JT270MH = JetstreamJT270MHRadio
[2017-02-16 19:29:04,378] chirp.directory - INFO: Registered Leixen_VV-898S = LeixenVV898SRadio
[2017-02-16 19:29:04,378] chirp.directory - INFO: Registered LUITON_LT-725UV = LT725UV
[2017-02-16 19:29:04,379] chirp.directory - INFO: Registered Wouxun_KG-UVD1P = KGUVD1PRadio
[2017-02-16 19:29:04,379] chirp.directory - INFO: Registered Wouxun_KG-UV6 = KGUV6DRadio
[2017-02-16 19:29:04,379] chirp.directory - INFO: Registered Wouxun_KG-816 = KG816Radio
[2017-02-16 19:29:04,379] chirp.directory - INFO: Registered Wouxun_KG-818 = KG818Radio
[2017-02-16 19:29:04,379] chirp.directory - INFO: Registered Puxing_PX-777 = Puxing777Radio
[2017-02-16 19:29:04,380] chirp.directory - INFO: Registered Puxing_PX-2R = Puxing2RRadio
[2017-02-16 19:29:04,380] chirp.directory - INFO: Registered Puxing_PX-888K = Puxing_PX888K_Radio
[2017-02-16 19:29:04,381] chirp.directory - INFO: Registered Retevis_RT1 = RT1Radio
[2017-02-16 19:29:04,381] chirp.directory - INFO: Registered Retevis_RT21 = RT21Radio
[2017-02-16 19:29:04,381] chirp.directory - INFO: Registered Retevis_RT22 = RT22Radio
[2017-02-16 19:29:04,381] chirp.directory - INFO: Registered WLN_KD-C1 = KDC1
[2017-02-16 19:29:04,381] chirp.directory - INFO: Registered Zastone_ZT-X6 = ZTX6
[2017-02-16 19:29:04,381] chirp.directory - INFO: Registered LUITON_LT-316 = LT316
[2017-02-16 19:29:04,382] chirp.directory - INFO: Registered TYT_TH-7800_File = TYTTH7800File
[2017-02-16 19:29:04,382] chirp.directory - INFO: Registered TYT_TH-7800 = TYTTH7800Radio
[2017-02-16 19:29:04,382] chirp.directory - INFO: Registered TYT_TH9000_220 = Th9000220Radio
[2017-02-16 19:29:04,382] chirp.directory - INFO: Registered TYT_TH9000_144 = Th9000144Radio
[2017-02-16 19:29:04,382] chirp.directory - INFO: Registered TYT_TH9000_440 = Th9000440Radio
[2017-02-16 19:29:04,383] chirp.directory - INFO: Registered TYT_TH-9800_File = TYTTH9800File
[2017-02-16 19:29:04,383] chirp.directory - INFO: Registered TYT_TH-9800 = TYTTH9800Radio
[2017-02-16 19:29:04,383] chirp.directory - INFO: Registered TYT_TH-UV3R = TYTUV3RRadio
[2017-02-16 19:29:04,383] chirp.directory - INFO: Registered TYT_TH-UV3R-25 = TYTUV3R25Radio
[2017-02-16 19:29:04,384] chirp.directory - INFO: Registered TYT_TH-UVF8D = TYTUVF8DRadio
[2017-02-16 19:29:04,384] chirp.directory - INFO: Registered Kenwood_TH-D72_clone_mode = THD72Radio
[2017-02-16 19:29:04,384] chirp.directory - INFO: Registered TYT_TH-UVF1 = TYTTHUVF1Radio
[2017-02-16 19:29:04,385] chirp.directory - INFO: Registered Kenwood_TK-260 = TK260_Radio
[2017-02-16 19:29:04,385] chirp.directory - INFO: Registered Kenwood_TK-270 = TK270_Radio
[2017-02-16 19:29:04,385] chirp.directory - INFO: Registered Kenwood_TK-272 = TK272_Radio
[2017-02-16 19:29:04,385] chirp.directory - INFO: Registered Kenwood_TK-278 = TK278_Radio
[2017-02-16 19:29:04,385] chirp.directory - INFO: Registered Kenwood_TK-360 = TK360_Radio
[2017-02-16 19:29:04,385] chirp.directory - INFO: Registered Kenwood_TK-370 = TK370_Radio
[2017-02-16 19:29:04,385] chirp.directory - INFO: Registered Kenwood_TK-372 = TK372_Radio
[2017-02-16 19:29:04,385] chirp.directory - INFO: Registered Kenwood_TK-378 = TK378_Radio
[2017-02-16 19:29:04,385] chirp.directory - INFO: Registered Kenwood_TK-760 = TK760_Radio
[2017-02-16 19:29:04,386] chirp.directory - INFO: Registered Kenwood_TK-762 = TK762_Radio
[2017-02-16 19:29:04,386] chirp.directory - INFO: Registered Kenwood_TK-768 = TK768_Radio
[2017-02-16 19:29:04,386] chirp.directory - INFO: Registered Kenwood_TK-860 = TK860_Radio
[2017-02-16 19:29:04,386] chirp.directory - INFO: Registered Kenwood_TK-862 = TK862_Radio
[2017-02-16 19:29:04,386] chirp.directory - INFO: Registered Kenwood_TK-868 = TK868_Radio
[2017-02-16 19:29:04,386] chirp.directory - INFO: Registered Kenwood_TK-868G = TK868G_Radios
[2017-02-16 19:29:04,387] chirp.directory - INFO: Registered Kenwood_TK-862G = TK862G_Radios
[2017-02-16 19:29:04,387] chirp.directory - INFO: Registered Kenwood_TK-860G = TK860G_Radios
[2017-02-16 19:29:04,387] chirp.directory - INFO: Registered Kenwood_TK-768G = TK768G_Radios
[2017-02-16 19:29:04,387] chirp.directory - INFO: Registered Kenwood_TK-762G = TK762G_Radios
[2017-02-16 19:29:04,387] chirp.directory - INFO: Registered Kenwood_TK-760G = TK760G_Radios
[2017-02-16 19:29:04,387] chirp.directory - INFO: Registered Kenwood_TK-388G = TK388G_Radios
[2017-02-16 19:29:04,387] chirp.directory - INFO: Registered Kenwood_TK-378G = TK378G_Radios
[2017-02-16 19:29:04,387] chirp.directory - INFO: Registered Kenwood_TK-372G = TK372G_Radios
[2017-02-16 19:29:04,387] chirp.directory - INFO: Registered Kenwood_TK-370G = TK370G_Radios
[2017-02-16 19:29:04,387] chirp.directory - INFO: Registered Kenwood_TK-360G = TK360G_Radios
[2017-02-16 19:29:04,387] chirp.directory - INFO: Registered Kenwood_TK-278G = TK278G_Radios
[2017-02-16 19:29:04,387] chirp.directory - INFO: Registered Kenwood_TK-272G = TK272G_Radios
[2017-02-16 19:29:04,388] chirp.directory - INFO: Registered Kenwood_TK-270G = TK270G_Radios
[2017-02-16 19:29:04,388] chirp.directory - INFO: Registered Kenwood_TK-260G = TK260G_Radios
[2017-02-16 19:29:04,388] chirp.directory - INFO: Registered Kenwood_TK-7102 = KenwoodTK7102Radio
[2017-02-16 19:29:04,388] chirp.directory - INFO: Registered Kenwood_TK-8102 = KenwoodTK8102Radio
[2017-02-16 19:29:04,388] chirp.directory - INFO: Registered Kenwood_TK-7108 = KenwoodTK7108Radio
[2017-02-16 19:29:04,388] chirp.directory - INFO: Registered Kenwood_TK-8108 = KenwoodTK8108Radio
[2017-02-16 19:29:04,389] chirp.directory - INFO: Registered Kenwood_TS-2000 = TS2000Radio
[2017-02-16 19:29:04,389] chirp.directory - INFO: Registered BTECH_UV-5X3 = UV5X3
[2017-02-16 19:29:04,389] chirp.directory - INFO: Registered Baofeng_UV-6R = UV6R
[2017-02-16 19:29:04,390] chirp.directory - INFO: Registered Baofeng_UV-B5 = BaofengUVB5
[2017-02-16 19:29:04,390] chirp.directory - INFO: Registered BTECH_UV-50X3 = UV50X3
[2017-02-16 19:29:04,390] chirp.directory - INFO: Registered Yaesu_VX-170 = VX170Radio
[2017-02-16 19:29:04,391] chirp.directory - INFO: Registered Yaesu_VX-2 = VX2Radio
[2017-02-16 19:29:04,391] chirp.directory - INFO: Registered Yaesu_VX-3 = VX3Radio
[2017-02-16 19:29:04,391] chirp.directory - INFO: Registered Yaesu_VX-5 = VX5Radio
[2017-02-16 19:29:04,392] chirp.directory - INFO: Registered Yaesu_VX-6 = VX6Radio
[2017-02-16 19:29:04,392] chirp.directory - INFO: Registered Yaesu_VX-7 = VX7Radio
[2017-02-16 19:29:04,392] chirp.directory - INFO: Registered Yaesu_VX-8_R = VX8Radio
[2017-02-16 19:29:04,393] chirp.directory - INFO: Registered Yaesu_VX-8_DR = VX8DRadio
[2017-02-16 19:29:04,393] chirp.directory - INFO: Registered Yaesu_VX-8_GE = VX8GERadio
[2017-02-16 19:29:04,393] chirp.directory - INFO: Registered Vertex_Standard_VXA-700 = VXA700Radio
Email was triggered for: Success
Sending email for trigger: Success
1
0
16 Feb '17
# HG changeset patch
# User Dan Smith <dsmith(a)danplanet.com>
# Date 1487298529 28800
# Thu Feb 16 18:28:49 2017 -0800
# Node ID 0611c6c740ab74c0d939634765a52ebc2b5a8497
# Parent 4569107adfccc72db9d12d8ecfcb7b97cfe06c65
Avoid confusing BTECH UV-5X3 users with UV-5X driver
Reportedly people that are buying the (new) BTECH UV-5X3 radio
are confused and choosing the Baofeng UV-5X model from the menus,
which won't work. Many are just outright returning the radio as
a result, assuming it's broken.
Since there are a million UV-5R variants and this is likely to
get worse, this patch adds a blacklist of similar magic strings
from radios that may be confused easily. If we fail to probe the
radio that was selected, we can probe for the blacklist magics,
and if any reply, raise a specific error to the user indicating
that they chose the wrong model.
#4539
diff -r 4569107adfcc -r 0611c6c740ab chirp/drivers/uv5r.py
--- a/chirp/drivers/uv5r.py Sat Feb 11 17:25:25 2017 -0500
+++ b/chirp/drivers/uv5r.py Thu Feb 16 18:28:49 2017 -0800
@@ -395,7 +395,7 @@
return version
-def _do_ident(radio, magic):
+def _do_ident(radio, magic, secondack=True):
serial = radio.pipe
serial.timeout = 1
@@ -448,10 +448,11 @@
LOG.debug(msg)
raise errors.RadioError("Unexpected response from radio.")
- serial.write("\x06")
- ack = serial.read(1)
- if ack != "\x06":
- raise errors.RadioError("Radio refused clone")
+ if secondack:
+ serial.write("\x06")
+ ack = serial.read(1)
+ if ack != "\x06":
+ raise errors.RadioError("Radio refused clone")
return ident
@@ -501,6 +502,11 @@
return version
+IDENT_BLACKLIST = {
+ "\x50\x0D\x0C\x20\x16\x03\x28": "Radio identifies as BTECH UV-5X3",
+}
+
+
def _ident_radio(radio):
for magic in radio._idents:
error = None
@@ -511,6 +517,22 @@
LOG.error(e)
error = e
time.sleep(2)
+
+ for magic, reason in IDENT_BLACKLIST.items():
+ try:
+ _do_ident(radio, magic, secondack=False)
+ except errors.RadioError as e:
+ # No match, try the next one
+ continue
+
+ # If we got here, it means we identified the radio as
+ # something other than one of our valid idents. Warn
+ # the user so they can do the right thing.
+ LOG.warning(('Identified radio as a blacklisted model '
+ '(details: %s)') % reason)
+ raise errors.RadioError(('%s. Please choose the proper vendor/'
+ 'model and try again.') % reason)
+
if error:
raise error
raise errors.RadioError("Radio did not respond")
2
2
Tested changes:
[Jim Unroe <rock.unroe(a)gmail.com>] [UV-B5] Address "Radio NAK'd block at address 0x0f10" Error
This patch works around the no ACK issue caused by the Baofeng UV-B5 and
UV-B6 radios with 27 menus that do not support the Service Menu settings.
related to #2109 and others.
[Tom Hayward <tom(a)tomh.us>] [id880] Fix typo in charset definition. #281
[Tom Hayward <tom(a)tomh.us>] [thf6a] Support full charset (ASCII). Fixes #141
[Tom Hayward <tom(a)tomh.us>] [id880] Support full charset. Fixes #281
[Tom Hayward <tom(a)tomh.us>] [vx5] Support full charset (ASCII). Fixes #292
[Tom Hayward <tom(a)tomh.us>] [id31a] set used bit when creating new memory, clear when deleting. Fixes #269
[Tom Hayward <tom(a)tomh.us>] Support PyGTK < 2.22 in bank edit. Fixes #231
[Tom Hayward <tom(a)tomh.us>] [d710] [v71] [d72] Fix tone list (not all tones are supported). Fixes #212
[Dan Smith <dsmith(a)danplanet.com>] [vx7] Fix setting memory power levels on 220MHz band
Fixes #214
[Dan Smith <dsmith(a)danplanet.com>] fips: Pennsylvania FIPS code was wrong. #117
[Marco Filippi <iz3gme.marco(a)gmail.com>] Consider lower bound frequency of each valid_band as valid
Fix bug #181
[Tom Hayward <tom(a)tomh.us>] tmd700: allow 8-char names. Fixes #176
[Dan Smith <dsmith(a)danplanet.com>] Fix the "blind deletion" problem, as well as properly direct copy/paste
Fixes #172
[David Griffith <dave(a)661.org>] Bug #155 fix: VX-7 1.25m power levels
[David Griffith <dave(a)661.org>] New INSTALL and README files
Fixes #122
[Tom Hayward <tom(a)tomh.us>] thd72: only use hardware flow on OS X. Fixes #166
[Marco Filippi <iz3gme.marco(a)gmail.com>] [FT817] Tone freq not set correctly
Same as #88 for FT857, to avoid code duplication fix code have been moved from
ft857 to its ancestor class
Fix bug #163
[Tom Hayward <tom(a)tomh.us>] Fix Mac .app so paths with spaces work. Fixes Bug #145
Full log:
Started by an SCM change
Building in workspace /var/lib/jenkins/jobs/chirp-test/workspace
[workspace] $ hg showconfig paths.default
[workspace] $ hg pull --rev default
[workspace] $ hg update --clean --rev default
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
[workspace] $ hg log --rev . --template {node}
[workspace] $ hg log --rev . --template {rev}
[workspace] $ hg log --rev 4c1697b626b287b087787645aaa894d81800ed46
[workspace] $ hg log --template "<changeset node='{node}' author='{author|xmlescape}' rev='{rev}' date='{date}'><msg>{desc|xmlescape}</msg><added>{file_adds|stringify|xmlescape}</added><deleted>{file_dels|stringify|xmlescape}</deleted><files>{files|stringify|xmlescape}</files><parents>{parents}</parents></changeset>\n" --rev default:0 --follow --prune 4c1697b626b287b087787645aaa894d81800ed46
No emails were triggered.
[workspace] $ /bin/sh -xe /tmp/hudson8970246190480063301.sh
[workspace] $ /bin/sh -xe /tmp/hudson902052329046171526.sh
+ PATH=/usr/bin:/bin:/usr/local/bin ./run_all_tests.sh
test_bit_array (tests.unit.test_bitwise.TestBitType) ... ok
test_bit_array_fail (tests.unit.test_bitwise.TestBitType) ... ok
test_bitfield_u16 (tests.unit.test_bitwise.TestBitfieldTypes) ... ok
test_bitfield_u24 (tests.unit.test_bitwise.TestBitfieldTypes) ... ok
test_bitfield_u8 (tests.unit.test_bitwise.TestBitfieldTypes) ... ok
test_bitfield_ul16 (tests.unit.test_bitwise.TestBitfieldTypes) ... ok
test_bitfield_ul24 (tests.unit.test_bitwise.TestBitfieldTypes) ... ok
test_bbcd (tests.unit.test_bitwise.TestBitwiseBCDTypes) ... ok
test_bbcd_array (tests.unit.test_bitwise.TestBitwiseBCDTypes) ... ok
test_lbcd (tests.unit.test_bitwise.TestBitwiseBCDTypes) ... ok
test_lbcd_array (tests.unit.test_bitwise.TestBitwiseBCDTypes) ... ok
test_int_array (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_u16 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_u24 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_u32 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_u8 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_ul16 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_ul24 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_ul32 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_char (tests.unit.test_bitwise.TestBitwiseCharTypes) ... ok
test_string (tests.unit.test_bitwise.TestBitwiseCharTypes) ... ok
test_string_invalid_chars (tests.unit.test_bitwise.TestBitwiseCharTypes) ... ok
test_string_wrong_length (tests.unit.test_bitwise.TestBitwiseCharTypes) ... ok
test_comment_cppstyle (tests.unit.test_bitwise.TestBitwiseComments) ... ok
test_comment_inline_cppstyle (tests.unit.test_bitwise.TestBitwiseComments) ... ok
test_missing_semicolon (tests.unit.test_bitwise.TestBitwiseErrors) ... ok
test_seek (tests.unit.test_bitwise.TestBitwiseSeek) ... ok
test_seekto (tests.unit.test_bitwise.TestBitwiseSeek) ... ok
test_struct_one_element (tests.unit.test_bitwise.TestBitwiseStructTypes) ... ok
test_struct_two_elements (tests.unit.test_bitwise.TestBitwiseStructTypes) ... ok
test_struct_writes (tests.unit.test_bitwise.TestBitwiseStructTypes) ... ok
split_tone_encode_test_cross_dtcs_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_cross_none_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_cross_none_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_cross_tone_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_cross_tone_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_none (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_tsql (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_dtcs_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_dtcs_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_none_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_none_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_tone_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_tone_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_none (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_tsql (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_fix_rounded_step_250 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_fix_rounded_step_500 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_fix_rounded_step_750 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_is_12_5 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_is_2_5 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_is_5_0 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_is_6_25 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_is_fractional_step (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_required_step (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_required_step_fail (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_format_freq (tests.unit.test_chirp_common.TestUtilityFunctions) ... ok
test_parse_freq_bad (tests.unit.test_chirp_common.TestUtilityFunctions) ... ok
test_parse_freq_decimal (tests.unit.test_chirp_common.TestUtilityFunctions) ... ok
test_parse_freq_whitespace (tests.unit.test_chirp_common.TestUtilityFunctions) ... ok
test_parse_freq_whole (tests.unit.test_chirp_common.TestUtilityFunctions) ... ok
test_ensure_has_calls_almost_full (tests.unit.test_import_logic.DstarTests) ... ok
test_ensure_has_calls_empty (tests.unit.test_import_logic.DstarTests) ... ok
test_ensure_has_calls_partial (tests.unit.test_import_logic.DstarTests) ... ok
test_ensure_has_calls_rptcall_full1 (tests.unit.test_import_logic.DstarTests) ... ok
test_ensure_has_calls_rptcall_full2 (tests.unit.test_import_logic.DstarTests) ... ok
test_ensure_has_calls_urcall_full (tests.unit.test_import_logic.DstarTests) ... ok
test_import_bank (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_dtcs_diffA_dtcs (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_dtcs_diffB_dtcs (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_duplex_negative (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_duplex_too_big_vhf (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_duplex_uhf (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_duplex_vhf (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mem (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mem_with_errors (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mem_with_warnings (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mode_invalid (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mode_valid_am (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mode_valid_fm (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_name (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_power_closest (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_power_no_dst (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_power_no_src (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_power_same (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_tone_diffA_tsql (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_tone_diffB_tsql (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_mapping (tests.unit.test_mappingmodel.TestBaseBank) ... ok
test_mapping_eq (tests.unit.test_mappingmodel.TestBaseBank) ... ok
test_base_class (tests.unit.test_mappingmodel.TestBaseBankModel) ... ok
test_get_name (tests.unit.test_mappingmodel.TestBaseBankModel) ... ok
test_mapping (tests.unit.test_mappingmodel.TestBaseMapping) ... ok
test_mapping_eq (tests.unit.test_mappingmodel.TestBaseMapping) ... ok
test_base_class (tests.unit.test_mappingmodel.TestBaseMappingModel) ... ok
test_get_name (tests.unit.test_mappingmodel.TestBaseMappingModel) ... ok
test_base_class (tests.unit.test_mappingmodel.TestBaseMappingModelIndexInterface) ... ok
test_add_memory_to_mapping (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_get_mapping_memories (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_get_mappings (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_get_memory_mappings (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_get_num_mappings (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_remove_memory_from_mapping (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_remove_memory_from_mapping_no_bank (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_remove_memory_from_mapping_wrong_bank (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_icom_bank (tests.unit.test_mappingmodel.TestIcomBanks) ... ok
test_mapping (tests.unit.test_mappingmodel.TestIcomBanks) ... ok
test_mapping_eq (tests.unit.test_mappingmodel.TestIcomBanks) ... ok
test_add_memory_to_mapping (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_index_bounds (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_mapping_memories (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_mappings (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_memory_index (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_memory_mappings (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_next_mapping_index (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_num_mappings (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_remove_memory_from_mapping (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_remove_memory_from_mapping_no_bank (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_remove_memory_from_mapping_wrong_bank (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_set_memory_index (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_set_memory_index_bad_bank (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_set_memory_index_bad_index (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_auto_tone_mode_cross (tests.unit.test_memedit_edits.TestEdits) ... ok
test_auto_tone_mode_dtcs (tests.unit.test_memedit_edits.TestEdits) ... ok
test_auto_tone_mode_dtcs_pol (tests.unit.test_memedit_edits.TestEdits) ... ok
test_auto_tone_mode_dtcs_rx (tests.unit.test_memedit_edits.TestEdits) ... ok
test_auto_tone_mode_tone (tests.unit.test_memedit_edits.TestEdits) ... ok
test_auto_tone_mode_tsql (tests.unit.test_memedit_edits.TestEdits) ... ok
test_init (tests.unit.test_platform.Win32PlatformTest) ... ok
test_serial_ports_bad_portnames (tests.unit.test_platform.Win32PlatformTest) ... ok
test_serial_ports_sorted (tests.unit.test_platform.Win32PlatformTest) ... ok
test_apply_callback (tests.unit.test_settings.TestSettingContainers) ... ok
test_radio_setting (tests.unit.test_settings.TestSettingContainers) ... ok
test_radio_setting_group (tests.unit.test_settings.TestSettingContainers) ... ok
test_radio_setting_multi (tests.unit.test_settings.TestSettingContainers) ... ok
test_changed (tests.unit.test_settings.TestSettingValues) ... ok
test_radio_setting_value_boolean (tests.unit.test_settings.TestSettingValues) ... ok
test_radio_setting_value_float (tests.unit.test_settings.TestSettingValues) ... ok
test_radio_setting_value_integer (tests.unit.test_settings.TestSettingValues) ... ok
test_radio_setting_value_list (tests.unit.test_settings.TestSettingValues) ... ok
test_radio_setting_value_string (tests.unit.test_settings.TestSettingValues) ... ok
test_validate_callback (tests.unit.test_settings.TestSettingValues) ... ok
test_delete_hole_with_all (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
test_delete_hole_with_all_full (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
test_delete_hole_with_hole (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
test_delete_hole_without_hole (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
test_insert_hole_with_space (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
test_insert_hole_without_space (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
----------------------------------------------------------------------
Ran 151 tests in 0.052s
OK
Patch 'tip' is OK
Checking for PEP8 regressions...
./chirp/platform.py:255:80: E501 line too long (82 > 79 characters)
./chirp/ui/mainapp.py:1909:80: E501 line too long (82 > 79 characters)
./chirp/ui/mainapp.py:1965:80: E501 line too long (82 > 79 characters)
real 0m7.620s
user 0m7.528s
sys 0m0.028s
================================================
Tests OK
+ cat /var/lib/jenkins/.chirp/debug.log
[2017-02-11 15:59:10,790] chirp.logger - DEBUG: CHIRP 0.3.0dev on Linux - Ubuntu 16.04.1 LTS (Python 2.7.12)
[2017-02-11 15:59:10,827] chirp.directory - INFO: Registered Kenwood_TH-D7 = THD7Radio
[2017-02-11 15:59:10,827] chirp.directory - INFO: Registered Kenwood_TH-D7G = THD7GRadio
[2017-02-11 15:59:10,827] chirp.directory - INFO: Registered Kenwood_TM-D700 = TMD700Radio
[2017-02-11 15:59:10,828] chirp.directory - INFO: Registered Kenwood_TM-V7 = TMV7Radio
[2017-02-11 15:59:10,828] chirp.directory - INFO: Registered Kenwood_TM-G707 = TMG707Radio
[2017-02-11 15:59:10,828] chirp.directory - INFO: Registered Kenwood_TH-G71 = THG71Radio
[2017-02-11 15:59:10,828] chirp.directory - INFO: Registered Kenwood_TH-F6 = THF6ARadio
[2017-02-11 15:59:10,828] chirp.directory - INFO: Registered Kenwood_TH-F7 = THF7ERadio
[2017-02-11 15:59:10,828] chirp.directory - INFO: Registered Kenwood_TM-D710 = TMD710Radio
[2017-02-11 15:59:10,828] chirp.directory - INFO: Registered Kenwood_TH-D72_live_mode = THD72Radio
[2017-02-11 15:59:10,828] chirp.directory - INFO: Registered Kenwood_TM-V71 = TMV71Radio
[2017-02-11 15:59:10,828] chirp.directory - INFO: Registered Kenwood_TM-D710G = TMD710GRadio
[2017-02-11 15:59:10,828] chirp.directory - INFO: Registered Kenwood_TH-K2 = THK2Radio
[2017-02-11 15:59:10,828] chirp.directory - INFO: Registered Kenwood_TM-271 = TM271Radio
[2017-02-11 15:59:10,829] chirp.directory - INFO: Registered Kenwood_TM-281 = TM281Radio
[2017-02-11 15:59:10,829] chirp.directory - INFO: Registered Kenwood_TM-471 = TM471Radio
[2017-02-11 15:59:10,829] chirp.directory - INFO: Registered Icom_7200 = Icom7200Radio
[2017-02-11 15:59:10,829] chirp.directory - INFO: Registered Icom_IC-7000 = Icom7000Radio
[2017-02-11 15:59:10,829] chirp.directory - INFO: Registered Icom_IC-7100 = Icom7100Radio
[2017-02-11 15:59:10,829] chirp.directory - INFO: Registered Icom_746 = Icom746Radio
[2017-02-11 15:59:10,832] chirp.directory - INFO: Registered Alinco_DR03T = DR03Radio
[2017-02-11 15:59:10,832] chirp.directory - INFO: Registered Alinco_DR06T = DR06Radio
[2017-02-11 15:59:10,832] chirp.directory - INFO: Registered Alinco_DR135T = DR135Radio
[2017-02-11 15:59:10,832] chirp.directory - INFO: Registered Alinco_DR235T = DR235Radio
[2017-02-11 15:59:10,832] chirp.directory - INFO: Registered Alinco_DR435T = DR435Radio
[2017-02-11 15:59:10,832] chirp.directory - INFO: Registered Alinco_DJ596 = DJ596Radio
[2017-02-11 15:59:10,832] chirp.directory - INFO: Registered Jetstream_JT220M = JT220MRadio
[2017-02-11 15:59:10,832] chirp.directory - INFO: Registered Alinco_DJ175 = DJ175Radio
[2017-02-11 15:59:10,832] chirp.directory - INFO: Registered Alinco_DJ-G7EG = AlincoDJG7EG
[2017-02-11 15:59:10,833] chirp.directory - INFO: Registered AnyTone_5888UV = AnyTone5888UVRadio
[2017-02-11 15:59:10,833] chirp.directory - INFO: Registered Intek_HR-2040 = IntekHR2040Radio
[2017-02-11 15:59:10,833] chirp.directory - INFO: Registered Polmar_DB-50M = PolmarDB50MRadio
[2017-02-11 15:59:10,833] chirp.directory - INFO: Registered Powerwerx_DB-750X = PowerwerxDB750XRadio
[2017-02-11 15:59:10,833] chirp.directory - INFO: Registered AnyTone_TERMN-8R = AnyToneTERMN8RRadio
[2017-02-11 15:59:10,833] chirp.directory - INFO: Registered AnyTone_OBLTR-8R = AnyToneOBLTR8RRadio
[2017-02-11 15:59:10,834] chirp.directory - INFO: Registered Baofeng_UV-3R = UV3RRadio
[2017-02-11 15:59:10,835] chirp.directory - INFO: Registered Baofeng_BF-A58 = BFA58
[2017-02-11 15:59:10,835] chirp.directory - INFO: Registered Baofeng_UV-82WP = UV82WP
[2017-02-11 15:59:10,835] chirp.directory - INFO: Registered Baofeng_GT-3WP = GT3WP
[2017-02-11 15:59:10,835] chirp.directory - INFO: Registered Retevis_RT6 = RT6
[2017-02-11 15:59:10,835] chirp.directory - INFO: Registered Baojie_BJ-9900 = BJ9900Radio
[2017-02-11 15:59:10,836] chirp.directory - INFO: Registered Baofeng_UV-5R = BaofengUV5RGeneric
[2017-02-11 15:59:10,836] chirp.directory - INFO: Registered Baofeng_F-11 = BaofengF11Radio
[2017-02-11 15:59:10,836] chirp.directory - INFO: Registered Baofeng_UV-82 = BaofengUV82Radio
[2017-02-11 15:59:10,836] chirp.directory - INFO: Registered Baofeng_UV-6 = BaofengUV6Radio
[2017-02-11 15:59:10,836] chirp.directory - INFO: Registered Intek_KT-980HP = IntekKT980Radio
[2017-02-11 15:59:10,836] chirp.directory - INFO: Registered Baofeng_BF-F8HP = BaofengBFF8HPRadio
[2017-02-11 15:59:10,836] chirp.directory - INFO: Registered Baofeng_UV-82HP = BaofengUV82HPRadio
[2017-02-11 15:59:10,836] chirp.directory - INFO: Registered Baojie_BJ-UV55 = BaojieBJUV55Radio
[2017-02-11 15:59:10,837] chirp.directory - INFO: Registered BTECH_UV-2501 = UV2501
[2017-02-11 15:59:10,837] chirp.directory - INFO: Registered BTECH_UV-2501+220 = UV2501_220
[2017-02-11 15:59:10,837] chirp.directory - INFO: Registered BTECH_UV-5001 = UV5001
[2017-02-11 15:59:10,837] chirp.directory - INFO: Registered WACCOM_MINI-8900 = MINI8900
[2017-02-11 15:59:10,837] chirp.directory - INFO: Registered QYT_KT-UV980 = KTUV980
[2017-02-11 15:59:10,837] chirp.directory - INFO: Registered QYT_KT8900 = KT9800
[2017-02-11 15:59:10,838] chirp.directory - INFO: Registered QYT_KT8900R = KT9800R
[2017-02-11 15:59:10,838] chirp.directory - INFO: Registered LUITON_LT-588UV = LT588UV
[2017-02-11 15:59:10,838] chirp.directory - INFO: Registered Feidaxin_FD-268A = FD268ARadio
[2017-02-11 15:59:10,838] chirp.directory - INFO: Registered Feidaxin_FD-268B = FD268BRadio
[2017-02-11 15:59:10,838] chirp.directory - INFO: Registered Feidaxin_FD-288A = FD288ARadio
[2017-02-11 15:59:10,838] chirp.directory - INFO: Registered Feidaxin_FD-288B = FD288BRadio
[2017-02-11 15:59:10,838] chirp.directory - INFO: Registered Feidaxin_FD-150A = FD150ARadio
[2017-02-11 15:59:10,838] chirp.directory - INFO: Registered Feidaxin_FD-160A = FD160ARadio
[2017-02-11 15:59:10,838] chirp.directory - INFO: Registered Feidaxin_FD-450A = FD450ARadio
[2017-02-11 15:59:10,839] chirp.directory - INFO: Registered Feidaxin_FD-460A = FD460ARadio
[2017-02-11 15:59:10,839] chirp.directory - INFO: Registered Feidaxin_FD-460UH = FD460UHRadio
[2017-02-11 15:59:10,839] chirp.directory - INFO: Registered Yaesu_FT-1802M = FT1802Radio
[2017-02-11 15:59:10,840] chirp.directory - INFO: Registered Yaesu_FT-1D_R = FT1Radio
[2017-02-11 15:59:10,840] chirp.directory - INFO: Registered Yaesu_FT-2800M = FT2800Radio
[2017-02-11 15:59:10,840] chirp.directory - INFO: Registered Yaesu_FT-2900R_1900R = FT2900Radio
[2017-02-11 15:59:10,841] chirp.directory - INFO: Registered Yaesu_FT-50 = FT50Radio
[2017-02-11 15:59:10,841] chirp.directory - INFO: Registered Yaesu_FT-60 = FT60Radio
[2017-02-11 15:59:10,842] chirp.directory - INFO: Registered Yaesu_FT-7800_7900 = FT7800Radio
[2017-02-11 15:59:10,842] chirp.directory - INFO: Registered Yaesu_FT-8800 = FT8800Radio
[2017-02-11 15:59:10,842] chirp.directory - INFO: Registered Yaesu_FT-8900 = FT8900Radio
[2017-02-11 15:59:10,842] chirp.directory - INFO: Registered Yaesu_FT-8100 = FT8100Radio
[2017-02-11 15:59:10,842] chirp.directory - INFO: Registered Yaesu_FT-817 = FT817Radio
[2017-02-11 15:59:10,842] chirp.directory - INFO: Registered Yaesu_FT-817ND = FT817NDRadio
[2017-02-11 15:59:10,843] chirp.directory - INFO: Registered Yaesu_FT-817ND_US = FT817NDUSRadio
[2017-02-11 15:59:10,843] chirp.directory - INFO: Registered Yaesu_FT-857_897 = FT857Radio
[2017-02-11 15:59:10,843] chirp.directory - INFO: Registered Yaesu_FT-857_897_US = FT857USRadio
[2017-02-11 15:59:10,843] chirp.directory - INFO: Registered Yaesu_FT-90 = FT90Radio
[2017-02-11 15:59:10,844] chirp.directory - INFO: Registered Yaesu_FTM-350 = FTM350Radio
[2017-02-11 15:59:10,844] chirp.directory - INFO: Registered Generic_CSV = CSVRadio
[2017-02-11 15:59:10,844] chirp.directory - INFO: Registered Commander_KG-UV = CommanderCSVRadio
[2017-02-11 15:59:10,844] chirp.directory - INFO: Registered RT_Systems_CSV = RTCSVRadio
[2017-02-11 15:59:10,845] chirp.directory - INFO: Registered ARRL_Travel_Plus = TpeRadio
[2017-02-11 15:59:10,852] chirp.directory - INFO: Registered Generic_XML = XMLRadio
[2017-02-11 15:59:10,852] chirp.directory - INFO: Registered BTECH_GMRS-V1 = GMRSV1
[2017-02-11 15:59:10,856] chirp.directory - INFO: Registered Baofeng_BF-888 = H777Radio
[2017-02-11 15:59:10,856] chirp.directory - INFO: Registered HobbyPCB_RS-UV3 = HobbyPCBRSUV3Radio
[2017-02-11 15:59:10,856] chirp.directory - INFO: Registered Icom_IC-208H = IC208Radio
[2017-02-11 15:59:10,856] chirp.directory - INFO: Registered Icom_IC-2100H = IC2100Radio
[2017-02-11 15:59:10,856] chirp.directory - INFO: Registered Icom_IC-2200H = IC2200Radio
[2017-02-11 15:59:10,857] chirp.directory - INFO: Registered Icom_IC-2720H = IC2720Radio
[2017-02-11 15:59:10,857] chirp.directory - INFO: Registered Icom_IC-2820H = IC2820Radio
[2017-02-11 15:59:10,857] chirp.directory - INFO: Registered Icom_IC-91_92AD = IC9xRadio
[2017-02-11 15:59:10,858] chirp.directory - INFO: Registered Icom_IC-Q7A = ICQ7Radio
[2017-02-11 15:59:10,858] chirp.directory - INFO: Registered Icom_IC-T70 = ICT70Radio
[2017-02-11 15:59:10,858] chirp.directory - INFO: Registered Icom_IC-T7H = ICT7HRadio
[2017-02-11 15:59:10,858] chirp.directory - INFO: Registered Icom_IC-T8A = ICT8ARadio
[2017-02-11 15:59:10,858] chirp.directory - INFO: Registered Icom_IC-W32A = ICW32ARadio
[2017-02-11 15:59:10,858] chirp.directory - INFO: Registered Icom_IC-W32E = ICW32ERadio
[2017-02-11 15:59:10,859] chirp.directory - INFO: Registered Icom_IC-V82_U82 = ICx8xRadio
[2017-02-11 15:59:10,859] chirp.directory - INFO: Registered Icom_ID-31A = ID31Radio
[2017-02-11 15:59:10,859] chirp.directory - INFO: Registered Icom_ID-51 = ID51Radio
[2017-02-11 15:59:10,859] chirp.directory - INFO: Registered Icom_ID-51_Plus = ID51PLUSRadio
[2017-02-11 15:59:10,860] chirp.directory - INFO: Registered Icom_ID-800H_v2 = ID800v2Radio
[2017-02-11 15:59:10,860] chirp.directory - INFO: Registered Icom_ID-880H = ID880Radio
[2017-02-11 15:59:10,860] chirp.directory - INFO: Registered Icom_ID-80H = ID80Radio
[2017-02-11 15:59:10,860] chirp.directory - INFO: Registered Kenwood_HMK = HMKRadio
[2017-02-11 15:59:10,860] chirp.directory - INFO: Registered Kenwood_ITM = ITMRadio
[2017-02-11 15:59:10,861] chirp.directory - INFO: Registered Wouxun_KG-UV8D = KGUV8DRadio
[2017-02-11 15:59:10,861] chirp.directory - INFO: Registered KYD_NC-630A = NC630aRadio
[2017-02-11 15:59:10,861] chirp.directory - INFO: Registered KYD_IP-620 = IP620Radio
[2017-02-11 15:59:10,862] chirp.directory - INFO: Registered Leixen_VV-898 = LeixenVV898Radio
[2017-02-11 15:59:10,862] chirp.directory - INFO: Registered Jetstream_JT270M = JetstreamJT270MRadio
[2017-02-11 15:59:10,862] chirp.directory - INFO: Registered Jetstream_JT270MH = JetstreamJT270MHRadio
[2017-02-11 15:59:10,862] chirp.directory - INFO: Registered Leixen_VV-898S = LeixenVV898SRadio
[2017-02-11 15:59:10,862] chirp.directory - INFO: Registered LUITON_LT-725UV = LT725UV
[2017-02-11 15:59:10,863] chirp.directory - INFO: Registered Wouxun_KG-UVD1P = KGUVD1PRadio
[2017-02-11 15:59:10,864] chirp.directory - INFO: Registered Wouxun_KG-UV6 = KGUV6DRadio
[2017-02-11 15:59:10,864] chirp.directory - INFO: Registered Wouxun_KG-816 = KG816Radio
[2017-02-11 15:59:10,864] chirp.directory - INFO: Registered Wouxun_KG-818 = KG818Radio
[2017-02-11 15:59:10,864] chirp.directory - INFO: Registered Puxing_PX-777 = Puxing777Radio
[2017-02-11 15:59:10,864] chirp.directory - INFO: Registered Puxing_PX-2R = Puxing2RRadio
[2017-02-11 15:59:10,865] chirp.directory - INFO: Registered Puxing_PX-888K = Puxing_PX888K_Radio
[2017-02-11 15:59:10,865] chirp.directory - INFO: Registered Retevis_RT1 = RT1Radio
[2017-02-11 15:59:10,865] chirp.directory - INFO: Registered Retevis_RT21 = RT21Radio
[2017-02-11 15:59:10,866] chirp.directory - INFO: Registered Retevis_RT22 = RT22Radio
[2017-02-11 15:59:10,866] chirp.directory - INFO: Registered WLN_KD-C1 = KDC1
[2017-02-11 15:59:10,866] chirp.directory - INFO: Registered Zastone_ZT-X6 = ZTX6
[2017-02-11 15:59:10,866] chirp.directory - INFO: Registered LUITON_LT-316 = LT316
[2017-02-11 15:59:10,866] chirp.directory - INFO: Registered TYT_TH-7800_File = TYTTH7800File
[2017-02-11 15:59:10,866] chirp.directory - INFO: Registered TYT_TH-7800 = TYTTH7800Radio
[2017-02-11 15:59:10,867] chirp.directory - INFO: Registered TYT_TH9000_220 = Th9000220Radio
[2017-02-11 15:59:10,867] chirp.directory - INFO: Registered TYT_TH9000_144 = Th9000144Radio
[2017-02-11 15:59:10,867] chirp.directory - INFO: Registered TYT_TH9000_440 = Th9000440Radio
[2017-02-11 15:59:10,867] chirp.directory - INFO: Registered TYT_TH-9800_File = TYTTH9800File
[2017-02-11 15:59:10,867] chirp.directory - INFO: Registered TYT_TH-9800 = TYTTH9800Radio
[2017-02-11 15:59:10,868] chirp.directory - INFO: Registered TYT_TH-UV3R = TYTUV3RRadio
[2017-02-11 15:59:10,868] chirp.directory - INFO: Registered TYT_TH-UV3R-25 = TYTUV3R25Radio
[2017-02-11 15:59:10,868] chirp.directory - INFO: Registered TYT_TH-UVF8D = TYTUVF8DRadio
[2017-02-11 15:59:10,868] chirp.directory - INFO: Registered Kenwood_TH-D72_clone_mode = THD72Radio
[2017-02-11 15:59:10,869] chirp.directory - INFO: Registered TYT_TH-UVF1 = TYTTHUVF1Radio
[2017-02-11 15:59:10,869] chirp.directory - INFO: Registered Kenwood_TK-260 = TK260_Radio
[2017-02-11 15:59:10,869] chirp.directory - INFO: Registered Kenwood_TK-270 = TK270_Radio
[2017-02-11 15:59:10,869] chirp.directory - INFO: Registered Kenwood_TK-272 = TK272_Radio
[2017-02-11 15:59:10,869] chirp.directory - INFO: Registered Kenwood_TK-278 = TK278_Radio
[2017-02-11 15:59:10,869] chirp.directory - INFO: Registered Kenwood_TK-360 = TK360_Radio
[2017-02-11 15:59:10,869] chirp.directory - INFO: Registered Kenwood_TK-370 = TK370_Radio
[2017-02-11 15:59:10,869] chirp.directory - INFO: Registered Kenwood_TK-372 = TK372_Radio
[2017-02-11 15:59:10,870] chirp.directory - INFO: Registered Kenwood_TK-378 = TK378_Radio
[2017-02-11 15:59:10,870] chirp.directory - INFO: Registered Kenwood_TK-760 = TK760_Radio
[2017-02-11 15:59:10,870] chirp.directory - INFO: Registered Kenwood_TK-762 = TK762_Radio
[2017-02-11 15:59:10,870] chirp.directory - INFO: Registered Kenwood_TK-768 = TK768_Radio
[2017-02-11 15:59:10,870] chirp.directory - INFO: Registered Kenwood_TK-860 = TK860_Radio
[2017-02-11 15:59:10,870] chirp.directory - INFO: Registered Kenwood_TK-862 = TK862_Radio
[2017-02-11 15:59:10,870] chirp.directory - INFO: Registered Kenwood_TK-868 = TK868_Radio
[2017-02-11 15:59:10,871] chirp.directory - INFO: Registered Kenwood_TK-868G = TK868G_Radios
[2017-02-11 15:59:10,871] chirp.directory - INFO: Registered Kenwood_TK-862G = TK862G_Radios
[2017-02-11 15:59:10,871] chirp.directory - INFO: Registered Kenwood_TK-860G = TK860G_Radios
[2017-02-11 15:59:10,871] chirp.directory - INFO: Registered Kenwood_TK-768G = TK768G_Radios
[2017-02-11 15:59:10,871] chirp.directory - INFO: Registered Kenwood_TK-762G = TK762G_Radios
[2017-02-11 15:59:10,871] chirp.directory - INFO: Registered Kenwood_TK-760G = TK760G_Radios
[2017-02-11 15:59:10,871] chirp.directory - INFO: Registered Kenwood_TK-388G = TK388G_Radios
[2017-02-11 15:59:10,871] chirp.directory - INFO: Registered Kenwood_TK-378G = TK378G_Radios
[2017-02-11 15:59:10,872] chirp.directory - INFO: Registered Kenwood_TK-372G = TK372G_Radios
[2017-02-11 15:59:10,872] chirp.directory - INFO: Registered Kenwood_TK-370G = TK370G_Radios
[2017-02-11 15:59:10,872] chirp.directory - INFO: Registered Kenwood_TK-360G = TK360G_Radios
[2017-02-11 15:59:10,872] chirp.directory - INFO: Registered Kenwood_TK-278G = TK278G_Radios
[2017-02-11 15:59:10,872] chirp.directory - INFO: Registered Kenwood_TK-272G = TK272G_Radios
[2017-02-11 15:59:10,872] chirp.directory - INFO: Registered Kenwood_TK-270G = TK270G_Radios
[2017-02-11 15:59:10,872] chirp.directory - INFO: Registered Kenwood_TK-260G = TK260G_Radios
[2017-02-11 15:59:10,872] chirp.directory - INFO: Registered Kenwood_TK-7102 = KenwoodTK7102Radio
[2017-02-11 15:59:10,872] chirp.directory - INFO: Registered Kenwood_TK-8102 = KenwoodTK8102Radio
[2017-02-11 15:59:10,872] chirp.directory - INFO: Registered Kenwood_TK-7108 = KenwoodTK7108Radio
[2017-02-11 15:59:10,873] chirp.directory - INFO: Registered Kenwood_TK-8108 = KenwoodTK8108Radio
[2017-02-11 15:59:10,873] chirp.directory - INFO: Registered Kenwood_TS-2000 = TS2000Radio
[2017-02-11 15:59:10,873] chirp.directory - INFO: Registered BTECH_UV-5X3 = UV5X3
[2017-02-11 15:59:10,874] chirp.directory - INFO: Registered Baofeng_UV-6R = UV6R
[2017-02-11 15:59:10,874] chirp.directory - INFO: Registered Baofeng_UV-B5 = BaofengUVB5
[2017-02-11 15:59:10,874] chirp.directory - INFO: Registered BTECH_UV-50X3 = UV50X3
[2017-02-11 15:59:10,875] chirp.directory - INFO: Registered Yaesu_VX-170 = VX170Radio
[2017-02-11 15:59:10,875] chirp.directory - INFO: Registered Yaesu_VX-2 = VX2Radio
[2017-02-11 15:59:10,875] chirp.directory - INFO: Registered Yaesu_VX-3 = VX3Radio
[2017-02-11 15:59:10,876] chirp.directory - INFO: Registered Yaesu_VX-5 = VX5Radio
[2017-02-11 15:59:10,876] chirp.directory - INFO: Registered Yaesu_VX-6 = VX6Radio
[2017-02-11 15:59:10,876] chirp.directory - INFO: Registered Yaesu_VX-7 = VX7Radio
[2017-02-11 15:59:10,877] chirp.directory - INFO: Registered Yaesu_VX-8_R = VX8Radio
[2017-02-11 15:59:10,877] chirp.directory - INFO: Registered Yaesu_VX-8_DR = VX8DRadio
[2017-02-11 15:59:10,877] chirp.directory - INFO: Registered Yaesu_VX-8_GE = VX8GERadio
[2017-02-11 15:59:10,877] chirp.directory - INFO: Registered Vertex_Standard_VXA-700 = VXA700Radio
Email was triggered for: Success
Sending email for trigger: Success
1
0
[chirp_devel] [PATCH] [UV-B5] Address "Radio NAK'd block at address 0x0f10" Error
by Jim Unroe 11 Feb '17
by Jim Unroe 11 Feb '17
11 Feb '17
# HG changeset patch
# User Jim Unroe <rock.unroe(a)gmail.com>
# Date 1486851925 18000
# Node ID 4569107adfccc72db9d12d8ecfcb7b97cfe06c65
# Parent 4c1697b626b287b087787645aaa894d81800ed46
[UV-B5] Address "Radio NAK'd block at address 0x0f10" Error
This patch works around the no ACK issue caused by the Baofeng UV-B5 and
UV-B6 radios with 27 menus that do not support the Service Menu settings.
related to #2109 and others.
diff -r 4c1697b626b2 -r 4569107adfcc chirp/drivers/uvb5.py
--- a/chirp/drivers/uvb5.py Wed Feb 08 23:13:46 2017 -0800
+++ b/chirp/drivers/uvb5.py Sat Feb 11 17:25:25 2017 -0500
@@ -238,7 +238,16 @@
radio.pipe.write(frame)
ack = radio.pipe.read(1)
if ack != "\x06":
- raise errors.RadioError("Radio NAK'd block at address 0x%04x" % i)
+ # UV-B5/UV-B6 radios with 27 menus do not support service settings
+ # and will stop ACKing when the upload reaches 0x0F10
+ if i == 0x0F10:
+ # must be a radio with 27 menus detected - stop upload
+ break
+ else:
+ LOG.debug("Radio NAK'd block at address 0x%04x" % i)
+ raise errors.RadioError(
+ "Radio NAK'd block at address 0x%04x" % i)
+ LOG.debug("Radio ACK'd block at address 0x%04x" % i)
do_status(radio, "to", i)
DUPLEX = ["", "-", "+", 'off', "split"]
1
0
# HG changeset patch
# User Tim Smith <hg(a)tds.xyz>
# Date 1486624426 28800
# Wed Feb 08 23:13:46 2017 -0800
# Node ID 8493808da8a1ea40baa5bbf79ea1c33e5646c935
# Parent 0b276128fdd8d7b02aee5d41216d37f11632af0b
Fix app launching on OS X #4479
Running chirp .app bundles from ~/Downloads was observed to fail on recent versions of OS X. This is because a OS X security feature called App Translocation is actually executing the .app bundle from a temporary read-only disk image, and the chirp launch script attempts to modify the contents of the app bundle.
This patch avoids modifying the .app bundle when App Translocation is active.
diff -r 0b276128fdd8 -r 8493808da8a1 build/chirp.app/Contents/MacOS/chirp
--- a/build/chirp.app/Contents/MacOS/chirp Mon Feb 06 12:09:45 2017 -0800
+++ b/build/chirp.app/Contents/MacOS/chirp Wed Feb 08 23:13:46 2017 -0800
@@ -2,14 +2,18 @@
LOCATION=$(dirname "${BASH_SOURCE}")
-PYTHON=/opt/kk7ds//Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python
+PYTHON=/opt/kk7ds/Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python
-if [ -x $PYTHON ]; then
+not_translocated () {
+ security translocate-status-check "${LOCATION}" 2>&1 | grep -q -e NOT -e unknown -e "not found"
+}
+
+if [ ! -x $PYTHON ]; then
+ PYTHON=/opt/kk7ds/bin/python2.7
+elif not_translocated; then
ln -s $PYTHON "${LOCATION}/../CHIRP"
PYTHON=${LOCATION}/../CHIRP
- export PYTHONPATH="/opt/kk7ds//Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/"
-else
- PYTHON=/opt/kk7ds/bin/python2.7
+ export PYTHONPATH=/opt/kk7ds/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages
fi
exec "$PYTHON" "${LOCATION}/../Resources/chirp/chirpw"
2
7
Tested changes:
[Tim Smith <hg(a)tds.xyz>] Fix app launching on OS X #4479
Running chirp .app bundles from ~/Downloads was observed to fail on recent versions of OS X. This is because a OS X security feature called App Translocation is actually executing the .app bundle from a temporary read-only disk image, and the chirp launch script attempts to modify the contents of the app bundle.
This patch avoids modifying the .app bundle when App Translocation is active.
[Tom Hayward <tom(a)tomh.us>] [id880] Fix typo in charset definition. #281
[Tom Hayward <tom(a)tomh.us>] [thf6a] Support full charset (ASCII). Fixes #141
[Tom Hayward <tom(a)tomh.us>] [id880] Support full charset. Fixes #281
[Tom Hayward <tom(a)tomh.us>] [vx5] Support full charset (ASCII). Fixes #292
[Tom Hayward <tom(a)tomh.us>] [id31a] set used bit when creating new memory, clear when deleting. Fixes #269
[Tom Hayward <tom(a)tomh.us>] Support PyGTK < 2.22 in bank edit. Fixes #231
[Tom Hayward <tom(a)tomh.us>] [d710] [v71] [d72] Fix tone list (not all tones are supported). Fixes #212
[Dan Smith <dsmith(a)danplanet.com>] [vx7] Fix setting memory power levels on 220MHz band
Fixes #214
[Dan Smith <dsmith(a)danplanet.com>] fips: Pennsylvania FIPS code was wrong. #117
[Marco Filippi <iz3gme.marco(a)gmail.com>] Consider lower bound frequency of each valid_band as valid
Fix bug #181
[Tom Hayward <tom(a)tomh.us>] tmd700: allow 8-char names. Fixes #176
[Dan Smith <dsmith(a)danplanet.com>] Fix the "blind deletion" problem, as well as properly direct copy/paste
Fixes #172
[David Griffith <dave(a)661.org>] Bug #155 fix: VX-7 1.25m power levels
[David Griffith <dave(a)661.org>] New INSTALL and README files
Fixes #122
[Tom Hayward <tom(a)tomh.us>] thd72: only use hardware flow on OS X. Fixes #166
[Marco Filippi <iz3gme.marco(a)gmail.com>] [FT817] Tone freq not set correctly
Same as #88 for FT857, to avoid code duplication fix code have been moved from
ft857 to its ancestor class
Fix bug #163
[Tom Hayward <tom(a)tomh.us>] Fix Mac .app so paths with spaces work. Fixes Bug #145
Full log:
Started by an SCM change
Building in workspace /var/lib/jenkins/jobs/chirp-test/workspace
[workspace] $ hg showconfig paths.default
[workspace] $ hg pull --rev default
[workspace] $ hg update --clean --rev default
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
[workspace] $ hg log --rev . --template {node}
[workspace] $ hg log --rev . --template {rev}
[workspace] $ hg log --rev 0b276128fdd8d7b02aee5d41216d37f11632af0b
[workspace] $ hg log --template "<changeset node='{node}' author='{author|xmlescape}' rev='{rev}' date='{date}'><msg>{desc|xmlescape}</msg><added>{file_adds|stringify|xmlescape}</added><deleted>{file_dels|stringify|xmlescape}</deleted><files>{files|stringify|xmlescape}</files><parents>{parents}</parents></changeset>\n" --rev default:0 --follow --prune 0b276128fdd8d7b02aee5d41216d37f11632af0b
No emails were triggered.
[workspace] $ /bin/sh -xe /tmp/hudson7532925309143247219.sh
[workspace] $ /bin/sh -xe /tmp/hudson2639413947814089205.sh
+ PATH=/usr/bin:/bin:/usr/local/bin ./run_all_tests.sh
test_bit_array (tests.unit.test_bitwise.TestBitType) ... ok
test_bit_array_fail (tests.unit.test_bitwise.TestBitType) ... ok
test_bitfield_u16 (tests.unit.test_bitwise.TestBitfieldTypes) ... ok
test_bitfield_u24 (tests.unit.test_bitwise.TestBitfieldTypes) ... ok
test_bitfield_u8 (tests.unit.test_bitwise.TestBitfieldTypes) ... ok
test_bitfield_ul16 (tests.unit.test_bitwise.TestBitfieldTypes) ... ok
test_bitfield_ul24 (tests.unit.test_bitwise.TestBitfieldTypes) ... ok
test_bbcd (tests.unit.test_bitwise.TestBitwiseBCDTypes) ... ok
test_bbcd_array (tests.unit.test_bitwise.TestBitwiseBCDTypes) ... ok
test_lbcd (tests.unit.test_bitwise.TestBitwiseBCDTypes) ... ok
test_lbcd_array (tests.unit.test_bitwise.TestBitwiseBCDTypes) ... ok
test_int_array (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_u16 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_u24 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_u32 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_u8 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_ul16 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_ul24 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_type_ul32 (tests.unit.test_bitwise.TestBitwiseBaseIntTypes) ... ok
test_char (tests.unit.test_bitwise.TestBitwiseCharTypes) ... ok
test_string (tests.unit.test_bitwise.TestBitwiseCharTypes) ... ok
test_string_invalid_chars (tests.unit.test_bitwise.TestBitwiseCharTypes) ... ok
test_string_wrong_length (tests.unit.test_bitwise.TestBitwiseCharTypes) ... ok
test_comment_cppstyle (tests.unit.test_bitwise.TestBitwiseComments) ... ok
test_comment_inline_cppstyle (tests.unit.test_bitwise.TestBitwiseComments) ... ok
test_missing_semicolon (tests.unit.test_bitwise.TestBitwiseErrors) ... ok
test_seek (tests.unit.test_bitwise.TestBitwiseSeek) ... ok
test_seekto (tests.unit.test_bitwise.TestBitwiseSeek) ... ok
test_struct_one_element (tests.unit.test_bitwise.TestBitwiseStructTypes) ... ok
test_struct_two_elements (tests.unit.test_bitwise.TestBitwiseStructTypes) ... ok
test_struct_writes (tests.unit.test_bitwise.TestBitwiseStructTypes) ... ok
split_tone_encode_test_cross_dtcs_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_cross_none_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_cross_none_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_cross_tone_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_cross_tone_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_none (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
split_tone_encode_test_tsql (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_dtcs_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_dtcs_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_none_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_none_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_tone_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_cross_tone_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_dtcs (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_none (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_tone (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_split_tone_decode_tsql (tests.unit.test_chirp_common.TestSplitTone) ... ok
test_fix_rounded_step_250 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_fix_rounded_step_500 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_fix_rounded_step_750 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_is_12_5 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_is_2_5 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_is_5_0 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_is_6_25 (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_is_fractional_step (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_required_step (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_required_step_fail (tests.unit.test_chirp_common.TestStepFunctions) ... ok
test_format_freq (tests.unit.test_chirp_common.TestUtilityFunctions) ... ok
test_parse_freq_bad (tests.unit.test_chirp_common.TestUtilityFunctions) ... ok
test_parse_freq_decimal (tests.unit.test_chirp_common.TestUtilityFunctions) ... ok
test_parse_freq_whitespace (tests.unit.test_chirp_common.TestUtilityFunctions) ... ok
test_parse_freq_whole (tests.unit.test_chirp_common.TestUtilityFunctions) ... ok
test_ensure_has_calls_almost_full (tests.unit.test_import_logic.DstarTests) ... ok
test_ensure_has_calls_empty (tests.unit.test_import_logic.DstarTests) ... ok
test_ensure_has_calls_partial (tests.unit.test_import_logic.DstarTests) ... ok
test_ensure_has_calls_rptcall_full1 (tests.unit.test_import_logic.DstarTests) ... ok
test_ensure_has_calls_rptcall_full2 (tests.unit.test_import_logic.DstarTests) ... ok
test_ensure_has_calls_urcall_full (tests.unit.test_import_logic.DstarTests) ... ok
test_import_bank (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_dtcs_diffA_dtcs (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_dtcs_diffB_dtcs (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_duplex_negative (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_duplex_too_big_vhf (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_duplex_uhf (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_duplex_vhf (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mem (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mem_with_errors (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mem_with_warnings (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mode_invalid (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mode_valid_am (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_mode_valid_fm (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_name (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_power_closest (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_power_no_dst (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_power_no_src (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_power_same (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_tone_diffA_tsql (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_import_tone_diffB_tsql (tests.unit.test_import_logic.ImportFieldTests) ... ok
test_mapping (tests.unit.test_mappingmodel.TestBaseBank) ... ok
test_mapping_eq (tests.unit.test_mappingmodel.TestBaseBank) ... ok
test_base_class (tests.unit.test_mappingmodel.TestBaseBankModel) ... ok
test_get_name (tests.unit.test_mappingmodel.TestBaseBankModel) ... ok
test_mapping (tests.unit.test_mappingmodel.TestBaseMapping) ... ok
test_mapping_eq (tests.unit.test_mappingmodel.TestBaseMapping) ... ok
test_base_class (tests.unit.test_mappingmodel.TestBaseMappingModel) ... ok
test_get_name (tests.unit.test_mappingmodel.TestBaseMappingModel) ... ok
test_base_class (tests.unit.test_mappingmodel.TestBaseMappingModelIndexInterface) ... ok
test_add_memory_to_mapping (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_get_mapping_memories (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_get_mappings (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_get_memory_mappings (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_get_num_mappings (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_remove_memory_from_mapping (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_remove_memory_from_mapping_no_bank (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_remove_memory_from_mapping_wrong_bank (tests.unit.test_mappingmodel.TestIcomBankModel) ... ok
test_icom_bank (tests.unit.test_mappingmodel.TestIcomBanks) ... ok
test_mapping (tests.unit.test_mappingmodel.TestIcomBanks) ... ok
test_mapping_eq (tests.unit.test_mappingmodel.TestIcomBanks) ... ok
test_add_memory_to_mapping (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_index_bounds (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_mapping_memories (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_mappings (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_memory_index (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_memory_mappings (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_next_mapping_index (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_get_num_mappings (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_remove_memory_from_mapping (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_remove_memory_from_mapping_no_bank (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_remove_memory_from_mapping_wrong_bank (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_set_memory_index (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_set_memory_index_bad_bank (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_set_memory_index_bad_index (tests.unit.test_mappingmodel.TestIcomIndexedBankModel) ... ok
test_auto_tone_mode_cross (tests.unit.test_memedit_edits.TestEdits) ... ok
test_auto_tone_mode_dtcs (tests.unit.test_memedit_edits.TestEdits) ... ok
test_auto_tone_mode_dtcs_pol (tests.unit.test_memedit_edits.TestEdits) ... ok
test_auto_tone_mode_dtcs_rx (tests.unit.test_memedit_edits.TestEdits) ... ok
test_auto_tone_mode_tone (tests.unit.test_memedit_edits.TestEdits) ... ok
test_auto_tone_mode_tsql (tests.unit.test_memedit_edits.TestEdits) ... ok
test_init (tests.unit.test_platform.Win32PlatformTest) ... ok
test_serial_ports_bad_portnames (tests.unit.test_platform.Win32PlatformTest) ... ok
test_serial_ports_sorted (tests.unit.test_platform.Win32PlatformTest) ... ok
test_apply_callback (tests.unit.test_settings.TestSettingContainers) ... ok
test_radio_setting (tests.unit.test_settings.TestSettingContainers) ... ok
test_radio_setting_group (tests.unit.test_settings.TestSettingContainers) ... ok
test_radio_setting_multi (tests.unit.test_settings.TestSettingContainers) ... ok
test_changed (tests.unit.test_settings.TestSettingValues) ... ok
test_radio_setting_value_boolean (tests.unit.test_settings.TestSettingValues) ... ok
test_radio_setting_value_float (tests.unit.test_settings.TestSettingValues) ... ok
test_radio_setting_value_integer (tests.unit.test_settings.TestSettingValues) ... ok
test_radio_setting_value_list (tests.unit.test_settings.TestSettingValues) ... ok
test_radio_setting_value_string (tests.unit.test_settings.TestSettingValues) ... ok
test_validate_callback (tests.unit.test_settings.TestSettingValues) ... ok
test_delete_hole_with_all (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
test_delete_hole_with_all_full (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
test_delete_hole_with_hole (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
test_delete_hole_without_hole (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
test_insert_hole_with_space (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
test_insert_hole_without_space (tests.unit.test_shiftdialog.ShiftDialogTest) ... ok
----------------------------------------------------------------------
Ran 151 tests in 0.057s
OK
Patch 'tip' is OK
Checking for PEP8 regressions...
./chirp/platform.py:255:80: E501 line too long (82 > 79 characters)
./chirp/ui/mainapp.py:1909:80: E501 line too long (82 > 79 characters)
./chirp/ui/mainapp.py:1965:80: E501 line too long (82 > 79 characters)
real 0m7.927s
user 0m7.796s
sys 0m0.056s
================================================
Tests OK
+ cat /var/lib/jenkins/.chirp/debug.log
[2017-02-09 07:09:09,757] chirp.logger - DEBUG: CHIRP 0.3.0dev on Linux - Ubuntu 16.04.1 LTS (Python 2.7.12)
[2017-02-09 07:09:09,793] chirp.directory - INFO: Registered Kenwood_TH-D7 = THD7Radio
[2017-02-09 07:09:09,794] chirp.directory - INFO: Registered Kenwood_TH-D7G = THD7GRadio
[2017-02-09 07:09:09,794] chirp.directory - INFO: Registered Kenwood_TM-D700 = TMD700Radio
[2017-02-09 07:09:09,794] chirp.directory - INFO: Registered Kenwood_TM-V7 = TMV7Radio
[2017-02-09 07:09:09,794] chirp.directory - INFO: Registered Kenwood_TM-G707 = TMG707Radio
[2017-02-09 07:09:09,794] chirp.directory - INFO: Registered Kenwood_TH-G71 = THG71Radio
[2017-02-09 07:09:09,794] chirp.directory - INFO: Registered Kenwood_TH-F6 = THF6ARadio
[2017-02-09 07:09:09,794] chirp.directory - INFO: Registered Kenwood_TH-F7 = THF7ERadio
[2017-02-09 07:09:09,794] chirp.directory - INFO: Registered Kenwood_TM-D710 = TMD710Radio
[2017-02-09 07:09:09,794] chirp.directory - INFO: Registered Kenwood_TH-D72_live_mode = THD72Radio
[2017-02-09 07:09:09,794] chirp.directory - INFO: Registered Kenwood_TM-V71 = TMV71Radio
[2017-02-09 07:09:09,794] chirp.directory - INFO: Registered Kenwood_TM-D710G = TMD710GRadio
[2017-02-09 07:09:09,795] chirp.directory - INFO: Registered Kenwood_TH-K2 = THK2Radio
[2017-02-09 07:09:09,795] chirp.directory - INFO: Registered Kenwood_TM-271 = TM271Radio
[2017-02-09 07:09:09,795] chirp.directory - INFO: Registered Kenwood_TM-281 = TM281Radio
[2017-02-09 07:09:09,795] chirp.directory - INFO: Registered Kenwood_TM-471 = TM471Radio
[2017-02-09 07:09:09,795] chirp.directory - INFO: Registered Icom_7200 = Icom7200Radio
[2017-02-09 07:09:09,795] chirp.directory - INFO: Registered Icom_IC-7000 = Icom7000Radio
[2017-02-09 07:09:09,795] chirp.directory - INFO: Registered Icom_IC-7100 = Icom7100Radio
[2017-02-09 07:09:09,795] chirp.directory - INFO: Registered Icom_746 = Icom746Radio
[2017-02-09 07:09:09,798] chirp.directory - INFO: Registered Alinco_DR03T = DR03Radio
[2017-02-09 07:09:09,798] chirp.directory - INFO: Registered Alinco_DR06T = DR06Radio
[2017-02-09 07:09:09,798] chirp.directory - INFO: Registered Alinco_DR135T = DR135Radio
[2017-02-09 07:09:09,798] chirp.directory - INFO: Registered Alinco_DR235T = DR235Radio
[2017-02-09 07:09:09,798] chirp.directory - INFO: Registered Alinco_DR435T = DR435Radio
[2017-02-09 07:09:09,798] chirp.directory - INFO: Registered Alinco_DJ596 = DJ596Radio
[2017-02-09 07:09:09,798] chirp.directory - INFO: Registered Jetstream_JT220M = JT220MRadio
[2017-02-09 07:09:09,799] chirp.directory - INFO: Registered Alinco_DJ175 = DJ175Radio
[2017-02-09 07:09:09,799] chirp.directory - INFO: Registered Alinco_DJ-G7EG = AlincoDJG7EG
[2017-02-09 07:09:09,799] chirp.directory - INFO: Registered AnyTone_5888UV = AnyTone5888UVRadio
[2017-02-09 07:09:09,799] chirp.directory - INFO: Registered Intek_HR-2040 = IntekHR2040Radio
[2017-02-09 07:09:09,799] chirp.directory - INFO: Registered Polmar_DB-50M = PolmarDB50MRadio
[2017-02-09 07:09:09,799] chirp.directory - INFO: Registered Powerwerx_DB-750X = PowerwerxDB750XRadio
[2017-02-09 07:09:09,800] chirp.directory - INFO: Registered AnyTone_TERMN-8R = AnyToneTERMN8RRadio
[2017-02-09 07:09:09,800] chirp.directory - INFO: Registered AnyTone_OBLTR-8R = AnyToneOBLTR8RRadio
[2017-02-09 07:09:09,800] chirp.directory - INFO: Registered Baofeng_UV-3R = UV3RRadio
[2017-02-09 07:09:09,801] chirp.directory - INFO: Registered Baofeng_BF-A58 = BFA58
[2017-02-09 07:09:09,801] chirp.directory - INFO: Registered Baofeng_UV-82WP = UV82WP
[2017-02-09 07:09:09,801] chirp.directory - INFO: Registered Baofeng_GT-3WP = GT3WP
[2017-02-09 07:09:09,801] chirp.directory - INFO: Registered Retevis_RT6 = RT6
[2017-02-09 07:09:09,801] chirp.directory - INFO: Registered Baojie_BJ-9900 = BJ9900Radio
[2017-02-09 07:09:09,802] chirp.directory - INFO: Registered Baofeng_UV-5R = BaofengUV5RGeneric
[2017-02-09 07:09:09,802] chirp.directory - INFO: Registered Baofeng_F-11 = BaofengF11Radio
[2017-02-09 07:09:09,802] chirp.directory - INFO: Registered Baofeng_UV-82 = BaofengUV82Radio
[2017-02-09 07:09:09,802] chirp.directory - INFO: Registered Baofeng_UV-6 = BaofengUV6Radio
[2017-02-09 07:09:09,803] chirp.directory - INFO: Registered Intek_KT-980HP = IntekKT980Radio
[2017-02-09 07:09:09,803] chirp.directory - INFO: Registered Baofeng_BF-F8HP = BaofengBFF8HPRadio
[2017-02-09 07:09:09,803] chirp.directory - INFO: Registered Baofeng_UV-82HP = BaofengUV82HPRadio
[2017-02-09 07:09:09,803] chirp.directory - INFO: Registered Baojie_BJ-UV55 = BaojieBJUV55Radio
[2017-02-09 07:09:09,804] chirp.directory - INFO: Registered BTECH_UV-2501 = UV2501
[2017-02-09 07:09:09,804] chirp.directory - INFO: Registered BTECH_UV-2501+220 = UV2501_220
[2017-02-09 07:09:09,804] chirp.directory - INFO: Registered BTECH_UV-5001 = UV5001
[2017-02-09 07:09:09,804] chirp.directory - INFO: Registered WACCOM_MINI-8900 = MINI8900
[2017-02-09 07:09:09,804] chirp.directory - INFO: Registered QYT_KT-UV980 = KTUV980
[2017-02-09 07:09:09,804] chirp.directory - INFO: Registered QYT_KT8900 = KT9800
[2017-02-09 07:09:09,804] chirp.directory - INFO: Registered QYT_KT8900R = KT9800R
[2017-02-09 07:09:09,804] chirp.directory - INFO: Registered LUITON_LT-588UV = LT588UV
[2017-02-09 07:09:09,804] chirp.directory - INFO: Registered Feidaxin_FD-268A = FD268ARadio
[2017-02-09 07:09:09,805] chirp.directory - INFO: Registered Feidaxin_FD-268B = FD268BRadio
[2017-02-09 07:09:09,805] chirp.directory - INFO: Registered Feidaxin_FD-288A = FD288ARadio
[2017-02-09 07:09:09,805] chirp.directory - INFO: Registered Feidaxin_FD-288B = FD288BRadio
[2017-02-09 07:09:09,805] chirp.directory - INFO: Registered Feidaxin_FD-150A = FD150ARadio
[2017-02-09 07:09:09,805] chirp.directory - INFO: Registered Feidaxin_FD-160A = FD160ARadio
[2017-02-09 07:09:09,805] chirp.directory - INFO: Registered Feidaxin_FD-450A = FD450ARadio
[2017-02-09 07:09:09,805] chirp.directory - INFO: Registered Feidaxin_FD-460A = FD460ARadio
[2017-02-09 07:09:09,805] chirp.directory - INFO: Registered Feidaxin_FD-460UH = FD460UHRadio
[2017-02-09 07:09:09,805] chirp.directory - INFO: Registered Yaesu_FT-1802M = FT1802Radio
[2017-02-09 07:09:09,806] chirp.directory - INFO: Registered Yaesu_FT-1D_R = FT1Radio
[2017-02-09 07:09:09,807] chirp.directory - INFO: Registered Yaesu_FT-2800M = FT2800Radio
[2017-02-09 07:09:09,807] chirp.directory - INFO: Registered Yaesu_FT-2900R_1900R = FT2900Radio
[2017-02-09 07:09:09,807] chirp.directory - INFO: Registered Yaesu_FT-50 = FT50Radio
[2017-02-09 07:09:09,808] chirp.directory - INFO: Registered Yaesu_FT-60 = FT60Radio
[2017-02-09 07:09:09,808] chirp.directory - INFO: Registered Yaesu_FT-7800_7900 = FT7800Radio
[2017-02-09 07:09:09,808] chirp.directory - INFO: Registered Yaesu_FT-8800 = FT8800Radio
[2017-02-09 07:09:09,808] chirp.directory - INFO: Registered Yaesu_FT-8900 = FT8900Radio
[2017-02-09 07:09:09,808] chirp.directory - INFO: Registered Yaesu_FT-8100 = FT8100Radio
[2017-02-09 07:09:09,809] chirp.directory - INFO: Registered Yaesu_FT-817 = FT817Radio
[2017-02-09 07:09:09,809] chirp.directory - INFO: Registered Yaesu_FT-817ND = FT817NDRadio
[2017-02-09 07:09:09,809] chirp.directory - INFO: Registered Yaesu_FT-817ND_US = FT817NDUSRadio
[2017-02-09 07:09:09,809] chirp.directory - INFO: Registered Yaesu_FT-857_897 = FT857Radio
[2017-02-09 07:09:09,810] chirp.directory - INFO: Registered Yaesu_FT-857_897_US = FT857USRadio
[2017-02-09 07:09:09,810] chirp.directory - INFO: Registered Yaesu_FT-90 = FT90Radio
[2017-02-09 07:09:09,810] chirp.directory - INFO: Registered Yaesu_FTM-350 = FTM350Radio
[2017-02-09 07:09:09,811] chirp.directory - INFO: Registered Generic_CSV = CSVRadio
[2017-02-09 07:09:09,811] chirp.directory - INFO: Registered Commander_KG-UV = CommanderCSVRadio
[2017-02-09 07:09:09,811] chirp.directory - INFO: Registered RT_Systems_CSV = RTCSVRadio
[2017-02-09 07:09:09,811] chirp.directory - INFO: Registered ARRL_Travel_Plus = TpeRadio
[2017-02-09 07:09:09,824] chirp.directory - INFO: Registered Generic_XML = XMLRadio
[2017-02-09 07:09:09,825] chirp.directory - INFO: Registered BTECH_GMRS-V1 = GMRSV1
[2017-02-09 07:09:09,828] chirp.directory - INFO: Registered Baofeng_BF-888 = H777Radio
[2017-02-09 07:09:09,828] chirp.directory - INFO: Registered HobbyPCB_RS-UV3 = HobbyPCBRSUV3Radio
[2017-02-09 07:09:09,828] chirp.directory - INFO: Registered Icom_IC-208H = IC208Radio
[2017-02-09 07:09:09,828] chirp.directory - INFO: Registered Icom_IC-2100H = IC2100Radio
[2017-02-09 07:09:09,829] chirp.directory - INFO: Registered Icom_IC-2200H = IC2200Radio
[2017-02-09 07:09:09,829] chirp.directory - INFO: Registered Icom_IC-2720H = IC2720Radio
[2017-02-09 07:09:09,829] chirp.directory - INFO: Registered Icom_IC-2820H = IC2820Radio
[2017-02-09 07:09:09,829] chirp.directory - INFO: Registered Icom_IC-91_92AD = IC9xRadio
[2017-02-09 07:09:09,830] chirp.directory - INFO: Registered Icom_IC-Q7A = ICQ7Radio
[2017-02-09 07:09:09,830] chirp.directory - INFO: Registered Icom_IC-T70 = ICT70Radio
[2017-02-09 07:09:09,830] chirp.directory - INFO: Registered Icom_IC-T7H = ICT7HRadio
[2017-02-09 07:09:09,830] chirp.directory - INFO: Registered Icom_IC-T8A = ICT8ARadio
[2017-02-09 07:09:09,831] chirp.directory - INFO: Registered Icom_IC-W32A = ICW32ARadio
[2017-02-09 07:09:09,831] chirp.directory - INFO: Registered Icom_IC-W32E = ICW32ERadio
[2017-02-09 07:09:09,831] chirp.directory - INFO: Registered Icom_IC-V82_U82 = ICx8xRadio
[2017-02-09 07:09:09,831] chirp.directory - INFO: Registered Icom_ID-31A = ID31Radio
[2017-02-09 07:09:09,832] chirp.directory - INFO: Registered Icom_ID-51 = ID51Radio
[2017-02-09 07:09:09,832] chirp.directory - INFO: Registered Icom_ID-51_Plus = ID51PLUSRadio
[2017-02-09 07:09:09,832] chirp.directory - INFO: Registered Icom_ID-800H_v2 = ID800v2Radio
[2017-02-09 07:09:09,832] chirp.directory - INFO: Registered Icom_ID-880H = ID880Radio
[2017-02-09 07:09:09,832] chirp.directory - INFO: Registered Icom_ID-80H = ID80Radio
[2017-02-09 07:09:09,832] chirp.directory - INFO: Registered Kenwood_HMK = HMKRadio
[2017-02-09 07:09:09,833] chirp.directory - INFO: Registered Kenwood_ITM = ITMRadio
[2017-02-09 07:09:09,833] chirp.directory - INFO: Registered Wouxun_KG-UV8D = KGUV8DRadio
[2017-02-09 07:09:09,833] chirp.directory - INFO: Registered KYD_NC-630A = NC630aRadio
[2017-02-09 07:09:09,834] chirp.directory - INFO: Registered KYD_IP-620 = IP620Radio
[2017-02-09 07:09:09,834] chirp.directory - INFO: Registered Leixen_VV-898 = LeixenVV898Radio
[2017-02-09 07:09:09,834] chirp.directory - INFO: Registered Jetstream_JT270M = JetstreamJT270MRadio
[2017-02-09 07:09:09,834] chirp.directory - INFO: Registered Jetstream_JT270MH = JetstreamJT270MHRadio
[2017-02-09 07:09:09,834] chirp.directory - INFO: Registered Leixen_VV-898S = LeixenVV898SRadio
[2017-02-09 07:09:09,835] chirp.directory - INFO: Registered LUITON_LT-725UV = LT725UV
[2017-02-09 07:09:09,836] chirp.directory - INFO: Registered Wouxun_KG-UVD1P = KGUVD1PRadio
[2017-02-09 07:09:09,836] chirp.directory - INFO: Registered Wouxun_KG-UV6 = KGUV6DRadio
[2017-02-09 07:09:09,836] chirp.directory - INFO: Registered Wouxun_KG-816 = KG816Radio
[2017-02-09 07:09:09,836] chirp.directory - INFO: Registered Wouxun_KG-818 = KG818Radio
[2017-02-09 07:09:09,836] chirp.directory - INFO: Registered Puxing_PX-777 = Puxing777Radio
[2017-02-09 07:09:09,836] chirp.directory - INFO: Registered Puxing_PX-2R = Puxing2RRadio
[2017-02-09 07:09:09,837] chirp.directory - INFO: Registered Puxing_PX-888K = Puxing_PX888K_Radio
[2017-02-09 07:09:09,838] chirp.directory - INFO: Registered Retevis_RT1 = RT1Radio
[2017-02-09 07:09:09,838] chirp.directory - INFO: Registered Retevis_RT21 = RT21Radio
[2017-02-09 07:09:09,838] chirp.directory - INFO: Registered Retevis_RT22 = RT22Radio
[2017-02-09 07:09:09,838] chirp.directory - INFO: Registered WLN_KD-C1 = KDC1
[2017-02-09 07:09:09,838] chirp.directory - INFO: Registered Zastone_ZT-X6 = ZTX6
[2017-02-09 07:09:09,838] chirp.directory - INFO: Registered LUITON_LT-316 = LT316
[2017-02-09 07:09:09,839] chirp.directory - INFO: Registered TYT_TH-7800_File = TYTTH7800File
[2017-02-09 07:09:09,839] chirp.directory - INFO: Registered TYT_TH-7800 = TYTTH7800Radio
[2017-02-09 07:09:09,839] chirp.directory - INFO: Registered TYT_TH9000_220 = Th9000220Radio
[2017-02-09 07:09:09,839] chirp.directory - INFO: Registered TYT_TH9000_144 = Th9000144Radio
[2017-02-09 07:09:09,840] chirp.directory - INFO: Registered TYT_TH9000_440 = Th9000440Radio
[2017-02-09 07:09:09,840] chirp.directory - INFO: Registered TYT_TH-9800_File = TYTTH9800File
[2017-02-09 07:09:09,840] chirp.directory - INFO: Registered TYT_TH-9800 = TYTTH9800Radio
[2017-02-09 07:09:09,840] chirp.directory - INFO: Registered TYT_TH-UV3R = TYTUV3RRadio
[2017-02-09 07:09:09,840] chirp.directory - INFO: Registered TYT_TH-UV3R-25 = TYTUV3R25Radio
[2017-02-09 07:09:09,841] chirp.directory - INFO: Registered TYT_TH-UVF8D = TYTUVF8DRadio
[2017-02-09 07:09:09,841] chirp.directory - INFO: Registered Kenwood_TH-D72_clone_mode = THD72Radio
[2017-02-09 07:09:09,841] chirp.directory - INFO: Registered TYT_TH-UVF1 = TYTTHUVF1Radio
[2017-02-09 07:09:09,842] chirp.directory - INFO: Registered Kenwood_TK-260 = TK260_Radio
[2017-02-09 07:09:09,842] chirp.directory - INFO: Registered Kenwood_TK-270 = TK270_Radio
[2017-02-09 07:09:09,842] chirp.directory - INFO: Registered Kenwood_TK-272 = TK272_Radio
[2017-02-09 07:09:09,842] chirp.directory - INFO: Registered Kenwood_TK-278 = TK278_Radio
[2017-02-09 07:09:09,842] chirp.directory - INFO: Registered Kenwood_TK-360 = TK360_Radio
[2017-02-09 07:09:09,842] chirp.directory - INFO: Registered Kenwood_TK-370 = TK370_Radio
[2017-02-09 07:09:09,842] chirp.directory - INFO: Registered Kenwood_TK-372 = TK372_Radio
[2017-02-09 07:09:09,842] chirp.directory - INFO: Registered Kenwood_TK-378 = TK378_Radio
[2017-02-09 07:09:09,843] chirp.directory - INFO: Registered Kenwood_TK-760 = TK760_Radio
[2017-02-09 07:09:09,843] chirp.directory - INFO: Registered Kenwood_TK-762 = TK762_Radio
[2017-02-09 07:09:09,843] chirp.directory - INFO: Registered Kenwood_TK-768 = TK768_Radio
[2017-02-09 07:09:09,843] chirp.directory - INFO: Registered Kenwood_TK-860 = TK860_Radio
[2017-02-09 07:09:09,843] chirp.directory - INFO: Registered Kenwood_TK-862 = TK862_Radio
[2017-02-09 07:09:09,843] chirp.directory - INFO: Registered Kenwood_TK-868 = TK868_Radio
[2017-02-09 07:09:09,844] chirp.directory - INFO: Registered Kenwood_TK-868G = TK868G_Radios
[2017-02-09 07:09:09,844] chirp.directory - INFO: Registered Kenwood_TK-862G = TK862G_Radios
[2017-02-09 07:09:09,844] chirp.directory - INFO: Registered Kenwood_TK-860G = TK860G_Radios
[2017-02-09 07:09:09,844] chirp.directory - INFO: Registered Kenwood_TK-768G = TK768G_Radios
[2017-02-09 07:09:09,844] chirp.directory - INFO: Registered Kenwood_TK-762G = TK762G_Radios
[2017-02-09 07:09:09,844] chirp.directory - INFO: Registered Kenwood_TK-760G = TK760G_Radios
[2017-02-09 07:09:09,844] chirp.directory - INFO: Registered Kenwood_TK-388G = TK388G_Radios
[2017-02-09 07:09:09,844] chirp.directory - INFO: Registered Kenwood_TK-378G = TK378G_Radios
[2017-02-09 07:09:09,844] chirp.directory - INFO: Registered Kenwood_TK-372G = TK372G_Radios
[2017-02-09 07:09:09,844] chirp.directory - INFO: Registered Kenwood_TK-370G = TK370G_Radios
[2017-02-09 07:09:09,844] chirp.directory - INFO: Registered Kenwood_TK-360G = TK360G_Radios
[2017-02-09 07:09:09,845] chirp.directory - INFO: Registered Kenwood_TK-278G = TK278G_Radios
[2017-02-09 07:09:09,845] chirp.directory - INFO: Registered Kenwood_TK-272G = TK272G_Radios
[2017-02-09 07:09:09,845] chirp.directory - INFO: Registered Kenwood_TK-270G = TK270G_Radios
[2017-02-09 07:09:09,845] chirp.directory - INFO: Registered Kenwood_TK-260G = TK260G_Radios
[2017-02-09 07:09:09,845] chirp.directory - INFO: Registered Kenwood_TK-7102 = KenwoodTK7102Radio
[2017-02-09 07:09:09,845] chirp.directory - INFO: Registered Kenwood_TK-8102 = KenwoodTK8102Radio
[2017-02-09 07:09:09,845] chirp.directory - INFO: Registered Kenwood_TK-7108 = KenwoodTK7108Radio
[2017-02-09 07:09:09,845] chirp.directory - INFO: Registered Kenwood_TK-8108 = KenwoodTK8108Radio
[2017-02-09 07:09:09,846] chirp.directory - INFO: Registered Kenwood_TS-2000 = TS2000Radio
[2017-02-09 07:09:09,846] chirp.directory - INFO: Registered BTECH_UV-5X3 = UV5X3
[2017-02-09 07:09:09,847] chirp.directory - INFO: Registered Baofeng_UV-6R = UV6R
[2017-02-09 07:09:09,847] chirp.directory - INFO: Registered Baofeng_UV-B5 = BaofengUVB5
[2017-02-09 07:09:09,847] chirp.directory - INFO: Registered BTECH_UV-50X3 = UV50X3
[2017-02-09 07:09:09,848] chirp.directory - INFO: Registered Yaesu_VX-170 = VX170Radio
[2017-02-09 07:09:09,848] chirp.directory - INFO: Registered Yaesu_VX-2 = VX2Radio
[2017-02-09 07:09:09,848] chirp.directory - INFO: Registered Yaesu_VX-3 = VX3Radio
[2017-02-09 07:09:09,849] chirp.directory - INFO: Registered Yaesu_VX-5 = VX5Radio
[2017-02-09 07:09:09,849] chirp.directory - INFO: Registered Yaesu_VX-6 = VX6Radio
[2017-02-09 07:09:09,849] chirp.directory - INFO: Registered Yaesu_VX-7 = VX7Radio
[2017-02-09 07:09:09,850] chirp.directory - INFO: Registered Yaesu_VX-8_R = VX8Radio
[2017-02-09 07:09:09,850] chirp.directory - INFO: Registered Yaesu_VX-8_DR = VX8DRadio
[2017-02-09 07:09:09,850] chirp.directory - INFO: Registered Yaesu_VX-8_GE = VX8GERadio
[2017-02-09 07:09:09,850] chirp.directory - INFO: Registered Vertex_Standard_VXA-700 = VXA700Radio
Email was triggered for: Success
Sending email for trigger: Success
1
0