# HG changeset patch
# Date 1422595106 28800
# Thu Jan 29 21:18:26 2015 -0800
# Node ID fd4bb2f6fd60680f6f811b7573f6fef1132fa9d3
# Parent bd1d2bac911911051c0a7b7f345cb6a0eba58ea7
Add support for new firmware in TYT TH-UV3R that supports 2.5kHz steps.
This hopefully fixes #1227
diff -r bd1d2bac9119 -r fd4bb2f6fd60 chirp/th_uv3r25.py
--- /dev/nullThu Jan 01 00:00:00 1970 +0000
+++ b/chirp/th_uv3r25.pyThu Jan 29 21:18:26 2015 -0800
@@ -0,0 +1,175 @@
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+
+"""TYT uv3r (2.5kHz) radio management module"""
+
+from chirp import chirp_common, bitwise, directory
+from chirp.wouxun_common import do_download, do_upload
+
+from th_uv3r import TYTUV3RRadio, tyt_uv3r_prep, THUV3R_CHARSET
+
+
+def tyt_uv3r_download(radio):
+ tyt_uv3r_prep(radio)
+ return do_download(radio, 0x0000, 0x0B30, 0x0010)
+
+
+def tyt_uv3r_upload(radio):
+ tyt_uv3r_prep(radio)
+ return do_upload(radio, 0x0000, 0x0B30, 0x0010)
+
+mem_format = """
+// 20 bytes per memory
+struct memory {
+ ul32 rx_freq; // 4 bytes
+ ul32 tx_freq; // 8 bytes
+
+ ul16 rx_tone; // 10 bytes
+ ul16 tx_tone; // 12 bytes
+
+ u8 unknown1a:1,
+ iswide:1,
+ bclo_n:1, // TODO: expose in UI
+ vox_n:1, // TODO: expose in UI
+ epilogue:1, // TODO: figure out what this even is
+ power_high:1,
+ voice_mode:2; // TODO: expose in UI
+ u8 name[6]; // 19 bytes
+ u8 unknown2; // 20 bytes
+};
+
+#seekto 0x0010;
+struct memory memory[128];
+
+#seekto 0x0A80;
+u8 emptyflags[16];
+u8 skipflags[16];
+"""
+
+
+class TYTUV3R25Radio(TYTUV3RRadio):
+ MODEL = "TH-UV3R (2.5kHz)"
+ _memsize = 2864
+
+ POWER_LEVELS = [chirp_common.PowerLevel("High", watts=2.00),
+ chirp_common.PowerLevel("Low", watts=0.80)]
+
+ def get_features(self):
+ rf = super(TYTUV3R25Radio, self).get_features()
+
+ rf.valid_tuning_steps = [2.5, 5.0, 6.25, 10.0, 12.5, 25.0, 37.50,
+ 50.0, 100.0]
+ rf.valid_power_levels = self.POWER_LEVELS
+ return rf
+
+ def sync_in(self):
+ self.pipe.setTimeout(2)
+ self._mmap = tyt_uv3r_download(self)
+ self.process_mmap()
+
+ def sync_out(self):
+ tyt_uv3r_upload(self)
+
+ def process_mmap(self):
+ self._memobj = bitwise.parse(mem_format, self._mmap)
+
+ def get_raw_memory(self, number):
+ return repr(self._memobj.memory[number - 1])
+
+ def get_memory(self, number):
+ _mem = self._memobj.memory[number - 1]
+ mem = chirp_common.Memory()
+ mem.number = number
+
+ bit = 1 << ((number - 1) % 8)
+ byte = (number - 1) / 8
+
+ if self._memobj.emptyflags[byte] & bit:
+ mem.empty = True
+ return mem
+
+ mem.freq = _mem.rx_freq * 10
+ mem.offset = abs(_mem.rx_freq - _mem.tx_freq)
+ if _mem.tx_freq == _mem.rx_freq:
+ mem.duplex = ""
+ elif _mem.tx_freq < _mem.rx_freq:
+ mem.duplex = "-"
+ elif _mem.tx_freq > _mem.rx_freq:
+ mem.duplex = "+"
+
+ mem.mode = _mem.iswide and "FM" or "NFM"
+ self._decode_tone(mem, _mem)
+ mem.skip = (self._memobj.skipflags[byte] & bit) and "S" or ""
+
+ for char in _mem.name:
+ try:
+ c = THUV3R_CHARSET[char]
+ except:
+ c = ""
+ mem.name += c
+ mem.name = mem.name.rstrip()
+
+ mem.power = self.POWER_LEVELS[not _mem.power_high]
+
+ return mem
+
+ def set_memory(self, mem):
+ _mem = self._memobj.memory[mem.number - 1]
+ bit = 1 << ((mem.number - 1) % 8)
+ byte = (mem.number - 1) / 8
+
+ if mem.empty:
+ self._memobj.emptyflags[byte] |= bit
+ _mem.set_raw("\xFF" * 16)
+ return
+
+ self._memobj.emptyflags[byte] &= ~bit
+
+ _mem.rx_freq = mem.freq / 10
+
+ if mem.duplex == "":
+ _mem.tx_freq = _mem.rx_freq
+ elif mem.duplex == "-":
+ _mem.tx_freq = _mem.rx_freq - mem.offset
+ elif mem.duplex == "+":
+ _mem.tx_freq = _mem.rx_freq + mem.offset
+
+ _mem.iswide = mem.mode == "FM"
+
+ self._encode_tone(mem, _mem)
+
+ if mem.skip:
+ self._memobj.skipflags[byte] |= bit
+ else:
+ self._memobj.skipflags[byte] &= ~bit
+
+ name = []
+ for char in mem.name.ljust(6):
+ try:
+ c = THUV3R_CHARSET.index(char)
+ except:
+ c = THUV3R_CHARSET.index(" ")
+ name.append(c)
+ _mem.name = name
+
+ if mem.power == self.POWER_LEVELS[0]:
+ _mem.power_high = 1
+ else:
+ _mem.power_high = 0
+
+ @classmethod
+ def match_model(cls, filedata, filename):
+ return len(filedata) == cls._memsize