<div dir="ltr"><div class="gmail_signature"><div dir="ltr"><div dir="ltr"># HG changeset patch</div><div dir="ltr"># User Alexey K &lt;<a href="mailto:lepik.stv@gmail.com">lepik.stv@gmail.com</a>&gt;</div><div dir="ltr"># Date 1444251379 -10800</div><div dir="ltr">#      Wed Oct 07 23:56:19 2015 +0300</div><div dir="ltr"># Node ID 6213e68e50e323221bf1939101bfc4169621a8cd</div><div dir="ltr"># Parent  39ec1a8bc0b04f90f47e8e76795a7abbe5b1af40</div><div dir="ltr">[KYD IP-620] Add support for KYD IP-620 radio - issue #2033</div><div dir="ltr"><br></div><div dir="ltr">diff -r 39ec1a8bc0b0 -r 6213e68e50e3 chirp/drivers/kyd_IP620.py</div><div dir="ltr">--- /dev/null<span class="" style="white-space:pre">        </span>Thu Jan 01 00:00:00 1970 +0000</div><div dir="ltr">+++ b/chirp/drivers/kyd_IP620.py<span class="" style="white-space:pre">        </span>Wed Oct 07 23:56:19 2015 +0300</div><div dir="ltr">@@ -0,0 +1,619 @@</div><div dir="ltr">+# Copyright 2015 Lepik.stv &lt;<a href="mailto:lepik.stv@gmail.com">lepik.stv@gmail.com</a>&gt;</div><div dir="ltr">+# based on modification of Dan Smith&#39;s and Jim Unroe original work</div><div dir="ltr">+#</div><div dir="ltr">+# This program is free software: you can redistribute it and/or modify</div><div dir="ltr">+# it under the terms of the GNU General Public License as published by</div><div dir="ltr">+# the Free Software Foundation, either version 2 of the License, or</div><div dir="ltr">+# (at your option) any later version.</div><div dir="ltr">+#</div><div dir="ltr">+# This program is distributed in the hope that it will be useful,</div><div dir="ltr">+# but WITHOUT ANY WARRANTY; without even the implied warranty of</div><div dir="ltr">+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</div><div dir="ltr">+# GNU General Public License for more details.</div><div dir="ltr">+#</div><div dir="ltr">+# You should have received a copy of the GNU General Public License</div><div dir="ltr">+# along with this program.  If not, see &lt;<a href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>&gt;.</div><div dir="ltr">+</div><div dir="ltr">+&quot;&quot;&quot;KYD IP-620 radios management module&quot;&quot;&quot;</div><div dir="ltr">+</div><div dir="ltr">+# TODO: Power on message</div><div dir="ltr">+# TODO: Channel name</div><div dir="ltr">+# TODO: Tuning step</div><div dir="ltr">+</div><div dir="ltr">+import struct</div><div dir="ltr">+import time</div><div dir="ltr">+import os</div><div dir="ltr">+import logging</div><div dir="ltr">+from chirp import util, chirp_common, bitwise, memmap, errors, directory</div><div dir="ltr">+from chirp.settings import RadioSetting, RadioSettingGroup, \</div><div dir="ltr">+                RadioSettingValueBoolean, RadioSettingValueList, \</div><div dir="ltr">+                RadioSettingValueInteger, RadioSettingValueString, \</div><div dir="ltr">+                RadioSettings</div><div dir="ltr">+</div><div dir="ltr">+LOG = logging.getLogger(__name__)</div><div dir="ltr">+</div><div dir="ltr">+IP620_MEM_FORMAT = &quot;&quot;&quot;</div><div dir="ltr">+#seekto 0x0000;</div><div dir="ltr">+struct {           // Channel memory structure</div><div dir="ltr">+  lbcd rx_freq[4]; // RX frequency</div><div dir="ltr">+  lbcd tx_freq[4]; // TX frequency</div><div dir="ltr">+  ul16 rx_tone;    // RX tone</div><div dir="ltr">+  ul16 tx_tone;    // TX tone</div><div dir="ltr">+  u8 unknown_1:4   // n-a</div><div dir="ltr">+     busy_loc:2,   // NO-00, Crrier wave-01, SM-10</div><div dir="ltr">+     n_a:2;        // n-a</div><div dir="ltr">+  u8 unknown_2:1   // n-a</div><div dir="ltr">+     scan_add:1,   // Scan add</div><div dir="ltr">+     n_a:1,        // n-a</div><div dir="ltr">+     w_n:1,        // Narrow-0 Wide-1</div><div dir="ltr">+     lout:1,       // LOCKOUT OFF-0 ON-1</div><div dir="ltr">+     n_a_:1,       // n-a</div><div dir="ltr">+     power:2;      // Power  low-00 middle-01 high-10</div><div dir="ltr">+  u8 unknown_3;    // n-a</div><div dir="ltr">+  u8 unknown_4;    // n-a</div><div dir="ltr">+} memory[200];</div><div dir="ltr">+</div><div dir="ltr">+#seekto 0x1000;</div><div dir="ltr">+struct {</div><div dir="ltr">+  u8 chan_name[6];  //Channel name</div><div dir="ltr">+  u8 unknown_1[10];</div><div dir="ltr">+} chan_names[200];</div><div dir="ltr">+</div><div dir="ltr">+#seekto 0x0C80;</div><div dir="ltr">+struct {           // Settings memory structure ( A-Frequency mode )</div><div dir="ltr">+  lbcd freq_a_rx[4];</div><div dir="ltr">+  lbcd freq_a_tx[4];</div><div dir="ltr">+  ul16 freq_a_rx_tone;    // RX tone</div><div dir="ltr">+  ul16 freq_a_tx_tone;    // TX tone</div><div dir="ltr">+  u8 unknown_1_5:4</div><div dir="ltr">+  freq_a_busy_loc:2,</div><div dir="ltr">+  n_a:2;</div><div dir="ltr">+  u8 unknown_1_6:3</div><div dir="ltr">+  freq_a_w_n:1,</div><div dir="ltr">+  n_a:1,</div><div dir="ltr">+  na:1,</div><div dir="ltr">+  freq_a_power:2;</div><div dir="ltr">+  u8 unknown_1_7;</div><div dir="ltr">+  u8 unknown_1_8;</div><div dir="ltr">+} settings_freq_a;</div><div dir="ltr">+</div><div dir="ltr">+#seekto 0x0E20;</div><div dir="ltr">+struct {</div><div dir="ltr">+  u8 chan_disp_way;  // Channel display way</div><div dir="ltr">+  u8 step_freq;      // Step frequency KHz</div><div dir="ltr">+  u8 rf_sql;         // Squelch level</div><div dir="ltr">+  u8 bat_save;       // Battery Saver</div><div dir="ltr">+  u8 chan_pri;       // Channel PRI</div><div dir="ltr">+  u8 end_beep;       // End beep</div><div dir="ltr">+  u8 tot;            // Time-out timer</div><div dir="ltr">+  u8 vox;            // VOX Gain</div><div dir="ltr">+  u8 chan_pri_num;   // Channel PRI time Sec</div><div dir="ltr">+  u8 n_a_2;</div><div dir="ltr">+  u8 ch_mode;        // CH mode</div><div dir="ltr">+  u8 n_a_3;</div><div dir="ltr">+  u8 call_tone;      // Call tone</div><div dir="ltr">+  u8 beep;           // Beep</div><div dir="ltr">+  u8 unknown_1_1[2];</div><div dir="ltr">+  u8 unknown_1_2[8];</div><div dir="ltr">+  u8 scan_rev;       // Scan rev</div><div dir="ltr">+  u8 unknown_1_3[2];</div><div dir="ltr">+  u8 enc;            // Frequency lock</div><div dir="ltr">+  u8 vox_dly;        // VOX Delay</div><div dir="ltr">+  u8 wait_back_light;// Wait back light</div><div dir="ltr">+  u8 unknown_1_4[2];</div><div dir="ltr">+} settings;</div><div dir="ltr">+</div><div dir="ltr">+#seekto 0x0E40;</div><div dir="ltr">+struct {</div><div dir="ltr">+  u8 fm_radio;        // FM radio</div><div dir="ltr">+  u8 auto_lock;       // Auto lock</div><div dir="ltr">+  u8 unknown_1[8];</div><div dir="ltr">+  u8 pon_msg[6];      //Power on msg</div><div dir="ltr">+} settings_misc;</div><div dir="ltr">+</div><div dir="ltr">+#seekto 0x1C80;</div><div dir="ltr">+struct {</div><div dir="ltr">+  u8 unknown_1[16];</div><div dir="ltr">+  u8 unknown_2[16];</div><div dir="ltr">+} settings_radio_3;</div><div dir="ltr">+&quot;&quot;&quot;</div><div dir="ltr">+</div><div dir="ltr">+CMD_ACK = &quot;\x06&quot;</div><div dir="ltr">+WRITE_BLOCK_SIZE = 0x10</div><div dir="ltr">+READ_BLOCK_SIZE = 0x40</div><div dir="ltr">+</div><div dir="ltr">+CHAR_LENGTH_MAX = 6</div><div dir="ltr">+</div><div dir="ltr">+OFF_ON_LIST = [&quot;OFF&quot;, &quot;ON&quot;]</div><div dir="ltr">+ON_OFF_LIST = [&quot;ON&quot;, &quot;OFF&quot;]</div><div dir="ltr">+NO_YES_LIST = [&quot;NO&quot;, &quot;YES&quot;]</div><div dir="ltr">+STEP_LIST = [&quot;5.0&quot;, &quot;6.25&quot;, &quot;10.0&quot;, &quot;12.5&quot;, &quot;25.0&quot;]</div><div dir="ltr">+BAT_SAVE_LIST = [&quot;OFF&quot;, &quot;0.2 Sec&quot;, &quot;0.4 Sec&quot;, &quot;0.6 Sec&quot;, &quot;0.8 Sec&quot;,&quot;1.0 Sec&quot;]</div><div dir="ltr">+SHIFT_LIST = [&quot;&quot;, &quot;-&quot;, &quot;+&quot;]</div><div dir="ltr">+SCANM_LIST = [&quot;Time&quot;, &quot;Carrier wave&quot;, &quot;Search&quot;]</div><div dir="ltr">+ENDBEEP_LIST = [&quot;OFF&quot;, &quot;Begin&quot;, &quot;End&quot;, &quot;Begin/End&quot;]</div><div dir="ltr">+POWER_LEVELS = [chirp_common.PowerLevel(&quot;Low&quot;,  watts=1.00), chirp_common.PowerLevel(&quot;Medium&quot;, watts=2.50), chirp_common.PowerLevel(&quot;High&quot;, watts=5.00)]</div><div dir="ltr">+TIMEOUT_LIST = [&quot;OFF&quot;, &quot;1 Min&quot;, &quot;3 Min&quot;, &quot;10 Min&quot;]</div><div dir="ltr">+TOTALERT_LIST = [&quot;&quot;, &quot;OFF&quot;] + [&quot;%s seconds&quot; % x for x in range(1, 11)]</div><div dir="ltr">+VOX_LIST = [&quot;OFF&quot;] + [&quot;%s&quot; % x for x in range(1, 17)]</div><div dir="ltr">+VOXDELAY_LIST = [&quot;0.3 Sec&quot;, &quot;0.5 Sec&quot;, &quot;1.0 Sec&quot;, &quot;1.5 Sec&quot;, &quot;2.0 Sec&quot;, &quot;3.0 Sec&quot;, &quot;4.0 Sec&quot;, &quot;5.0 Sec&quot;]</div><div dir="ltr">+PRI_NUM = [3, 5, 8, 10]</div><div dir="ltr">+PRI_NUM_LIST = [str(x) for x in PRI_NUM]</div><div dir="ltr">+CH_FLAG_LIST = [&quot;Channel+Freq&quot;, &quot;Channel+Name&quot;]</div><div dir="ltr">+BACKLIGHT_LIST = [&quot;Always Off&quot;, &quot;Auto&quot;, &quot;Always On&quot;]</div><div dir="ltr">+BUSYLOCK_LIST = [&quot;NO&quot;, &quot;Carrier&quot;, &quot;SM&quot;]</div><div dir="ltr">+KEYBLOCK_LIST = [&quot;Manual&quot;, &quot;Auto&quot;]</div><div dir="ltr">+CALLTONE_LIST = [&quot;OFF&quot;, &quot;1&quot;, &quot;2&quot;, &quot;3&quot;, &quot;4&quot;, &quot;5&quot;, &quot;6&quot;, &quot;7&quot;, &quot;8&quot;, &quot;1750&quot;]</div><div dir="ltr">+RFSQL_LIST = [&quot;OFF&quot;, &quot;S-1&quot;, &quot;S-2&quot;, &quot;S-3&quot;, &quot;S-4&quot;, &quot;S-5&quot;, &quot;S-6&quot;,&quot;S-7&quot;, &quot;S-8&quot;, &quot;S-FULL&quot;]</div><div dir="ltr">+</div><div dir="ltr">+IP620_CHARSET = &quot;0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ?+-* &quot;</div><div dir="ltr">+</div><div dir="ltr">+IP620_BANDS = [</div><div dir="ltr">+    (136000000, 174000000),</div><div dir="ltr">+    (200000000, 260000000),</div><div dir="ltr">+    (300000000, 340000000),  # &lt;--- this band supports only Russian model (ARGUT A-36)</div><div dir="ltr">+    (350000000, 390000000),</div><div dir="ltr">+    (400000000, 480000000),</div><div dir="ltr">+    (420000000, 510000000),</div><div dir="ltr">+    (450000000, 520000000),</div><div dir="ltr">+]</div><div dir="ltr">+</div><div dir="ltr">+@directory.register</div><div dir="ltr">+class IP620Radio(chirp_common.CloneModeRadio,</div><div dir="ltr">+                chirp_common.ExperimentalRadio):</div><div dir="ltr">+    &quot;&quot;&quot;KYD IP-620&quot;&quot;&quot;</div><div dir="ltr">+    VENDOR = &quot;KYD&quot;</div><div dir="ltr">+    MODEL = &quot;IP-620&quot;</div><div dir="ltr">+    BAUD_RATE = 9600</div><div dir="ltr">+</div><div dir="ltr">+    _ranges = [</div><div dir="ltr">+               (0x0000, 0x2000),</div><div dir="ltr">+              ]</div><div dir="ltr">+    _memsize = 0x2000</div><div dir="ltr">+</div><div dir="ltr">+    def _ip620_exit_programming_mode(self):</div><div dir="ltr">+        try:</div><div dir="ltr">+            self.pipe.write(&quot;\x06&quot;)</div><div dir="ltr">+        except errors.RadioError:</div><div dir="ltr">+            raise</div><div dir="ltr">+        except Exception, e:</div><div dir="ltr">+            raise errors.RadioError(&quot;Radio refused to exit programming mode: %s&quot; % e)</div><div dir="ltr">+</div><div dir="ltr">+    def _ip620_enter_programming_mode(self):</div><div dir="ltr">+        try:</div><div dir="ltr">+            self.pipe.write(&quot;iUHOUXUN&quot;)</div><div dir="ltr">+            self.pipe.write(&quot;\x02&quot;)</div><div dir="ltr">+            time.sleep(0.2)</div><div dir="ltr">+            _ack = self.pipe.read(1)</div><div dir="ltr">+        except errors.RadioError:</div><div dir="ltr">+            raise</div><div dir="ltr">+        except Exception, e:</div><div dir="ltr">+            raise errors.RadioError(&quot;Error communicating with radio: %s&quot; % e)</div><div dir="ltr">+        if not _ack:</div><div dir="ltr">+            raise errors.RadioError(&quot;No response from radio&quot;)</div><div dir="ltr">+        elif _ack != CMD_ACK:</div><div dir="ltr">+            raise errors.RadioError(&quot;Radio refused to enter programming mode&quot;)</div><div dir="ltr">+        try:</div><div dir="ltr">+            self.pipe.write(&quot;\x02&quot;)</div><div dir="ltr">+            _ident = self.pipe.read(8)</div><div dir="ltr">+        except errors.RadioError:</div><div dir="ltr">+            raise</div><div dir="ltr">+        except Exception, e:</div><div dir="ltr">+            raise errors.RadioError(&quot;Error communicating with radio: %s&quot; % e)</div><div dir="ltr">+        if not _ident.startswith(&quot;\x06\x4B\x47\x36\x37\x01\x56\xF8&quot;):</div><div dir="ltr">+            print util.hexprint(_ident)</div><div dir="ltr">+            raise errors.RadioError(&quot;Radio returned unknown identification string&quot;)</div><div dir="ltr">+        try:</div><div dir="ltr">+            self.pipe.write(CMD_ACK)</div><div dir="ltr">+            _ack = self.pipe.read(1)</div><div dir="ltr">+        except errors.RadioError:</div><div dir="ltr">+            raise</div><div dir="ltr">+        except Exception, e:</div><div dir="ltr">+            raise errors.RadioError(&quot;Error communicating with radio: %s&quot; % e)</div><div dir="ltr">+        if _ack != CMD_ACK:</div><div dir="ltr">+            raise errors.RadioError(&quot;Radio refused to enter programming mode&quot;)</div><div dir="ltr">+</div><div dir="ltr">+    def _ip620_write_block(self, block_addr):</div><div dir="ltr">+        _cmd = struct.pack(&quot;&gt;cHb&quot;, &#39;W&#39;, block_addr, WRITE_BLOCK_SIZE)</div><div dir="ltr">+        _data = self.get_mmap()[block_addr:block_addr + WRITE_BLOCK_SIZE]</div><div dir="ltr">+        LOG.debug(&quot;Writing Data:&quot;)</div><div dir="ltr">+        LOG.debug(util.hexprint(_cmd + _data))</div><div dir="ltr">+        try:</div><div dir="ltr">+            self.pipe.write(_cmd + _data)</div><div dir="ltr">+            if self.pipe.read(1) != CMD_ACK:</div><div dir="ltr">+                raise Exception(&quot;No ACK&quot;)</div><div dir="ltr">+        except:</div><div dir="ltr">+            raise errors.RadioError(&quot;Failed to send block &quot;</div><div dir="ltr">+                                    &quot;to radio at %04x&quot; % block_addr)</div><div dir="ltr">+</div><div dir="ltr">+    def _ip620_read_block(self, block_addr):</div><div dir="ltr">+        _cmd = struct.pack(&quot;&gt;cHb&quot;, &#39;R&#39;, block_addr, READ_BLOCK_SIZE)</div><div dir="ltr">+        _expectedresponse = &quot;W&quot; + _cmd[1:]</div><div dir="ltr">+        LOG.debug(&quot;Reading block %04x...&quot; % (block_addr))</div><div dir="ltr">+        try:</div><div dir="ltr">+            self.pipe.write(_cmd)</div><div dir="ltr">+            _response = self.pipe.read(4 + READ_BLOCK_SIZE)</div><div dir="ltr">+            if _response[:4] != _expectedresponse:</div><div dir="ltr">+                raise Exception(&quot;Error reading block %04x.&quot; % (block_addr))</div><div dir="ltr">+            _block_data = _response[4:]</div><div dir="ltr">+            self.pipe.write(CMD_ACK)</div><div dir="ltr">+            _ack = self.pipe.read(1)</div><div dir="ltr">+        except:</div><div dir="ltr">+            raise errors.RadioError(&quot;Failed to read block at %04x&quot; % block_addr)</div><div dir="ltr">+        if _ack != CMD_ACK:</div><div dir="ltr">+            raise Exception(&quot;No ACK reading block %04x.&quot; % (block_addr))</div><div dir="ltr">+        return _block_data</div><div dir="ltr">+</div><div dir="ltr">+    def _do_download(self):</div><div dir="ltr">+        self._ip620_enter_programming_mode()</div><div dir="ltr">+        _data = &quot;&quot;</div><div dir="ltr">+        _status = chirp_common.Status()</div><div dir="ltr">+        _status.msg = &quot;Cloning from radio&quot;</div><div dir="ltr">+        _status.cur = 0</div><div dir="ltr">+        _status.max = self._memsize</div><div dir="ltr">+        for _addr in range(0, self._memsize, READ_BLOCK_SIZE):</div><div dir="ltr">+            _status.cur = _addr + READ_BLOCK_SIZE</div><div dir="ltr">+            self.status_fn(_status)</div><div dir="ltr">+            _block = self._ip620_read_block(_addr)</div><div dir="ltr">+            _data += _block</div><div dir="ltr">+            LOG.debug(&quot;Address: %04x&quot; % _addr)</div><div dir="ltr">+            LOG.debug(util.hexprint(_block))</div><div dir="ltr">+        self._ip620_exit_programming_mode()</div><div dir="ltr">+        return memmap.MemoryMap(_data)</div><div dir="ltr">+</div><div dir="ltr">+    def _do_upload(self):</div><div dir="ltr">+        _status = chirp_common.Status()</div><div dir="ltr">+        _status.msg = &quot;Uploading to radio&quot;</div><div dir="ltr">+        self._ip620_enter_programming_mode()</div><div dir="ltr">+        _status.cur = 0</div><div dir="ltr">+        _status.max = self._memsize</div><div dir="ltr">+        for _start_addr, _end_addr in self._ranges:</div><div dir="ltr">+            for _addr in range(_start_addr, _end_addr, WRITE_BLOCK_SIZE):</div><div dir="ltr">+                _status.cur = _addr + WRITE_BLOCK_SIZE</div><div dir="ltr">+                self.status_fn(_status)</div><div dir="ltr">+                self._ip620_write_block(_addr)</div><div dir="ltr">+        self._ip620_exit_programming_mode()</div><div dir="ltr">+</div><div dir="ltr">+    @classmethod</div><div dir="ltr">+    def get_prompts(cls):</div><div dir="ltr">+        rp = chirp_common.RadioPrompts()</div><div dir="ltr">+        rp.experimental = (&quot;This radio driver is currently under development. &quot;</div><div dir="ltr">+                           &quot;There are no known issues with it, but you should &quot;</div><div dir="ltr">+                           &quot;proceed with caution. However, proceed at your own risk!&quot;)</div><div dir="ltr">+        return rp</div><div dir="ltr">+</div><div dir="ltr">+    def get_features(self):</div><div dir="ltr">+        rf = chirp_common.RadioFeatures()</div><div dir="ltr">+        rf.has_settings = True</div><div dir="ltr">+        rf.has_bank = False</div><div dir="ltr">+        rf.has_ctone = True</div><div dir="ltr">+        rf.has_cross = False</div><div dir="ltr">+        rf.has_rx_dtcs = True</div><div dir="ltr">+        rf.has_tuning_step = False</div><div dir="ltr">+        rf.can_odd_split = False</div><div dir="ltr">+        rf.has_name = False</div><div dir="ltr">+        rf.valid_skips = []</div><div dir="ltr">+        rf.valid_tmodes = [&quot;&quot;, &quot;Tone&quot;, &quot;TSQL&quot;, &quot;DTCS&quot;]</div><div dir="ltr">+        rf.valid_power_levels = POWER_LEVELS</div><div dir="ltr">+        rf.valid_duplexes = SHIFT_LIST</div><div dir="ltr">+        rf.valid_modes = [&quot;FM&quot;, &quot;NFM&quot;]</div><div dir="ltr">+        rf.memory_bounds = (1, 200)</div><div dir="ltr">+        rf.valid_bands = IP620_BANDS</div><div dir="ltr">+        rf.valid_characters = &#39;&#39;.join(set(IP620_CHARSET))</div><div dir="ltr">+        rf.valid_name_length = CHAR_LENGTH_MAX</div><div dir="ltr">+        return rf</div><div dir="ltr">+</div><div dir="ltr">+    def process_mmap(self):</div><div dir="ltr">+        self._memobj = bitwise.parse(IP620_MEM_FORMAT, self._mmap)</div><div dir="ltr">+</div><div dir="ltr">+    def sync_in(self):</div><div dir="ltr">+        try:</div><div dir="ltr">+            self._mmap = self._do_download()</div><div dir="ltr">+        except errors.RadioError:</div><div dir="ltr">+            raise</div><div dir="ltr">+        except Exception, e:</div><div dir="ltr">+            raise errors.RadioError(&quot;Failed to communicate with radio: %s&quot; % e)</div><div dir="ltr">+        self.process_mmap()</div><div dir="ltr">+</div><div dir="ltr">+    def sync_out(self):</div><div dir="ltr">+        self._do_upload()</div><div dir="ltr">+</div><div dir="ltr">+    def get_raw_memory(self, number):</div><div dir="ltr">+        return repr(self._memobj.memory[number - 1])</div><div dir="ltr">+</div><div dir="ltr">+    def _get_tone(self, _mem, mem):</div><div dir="ltr">+        def _get_dcs(val):</div><div dir="ltr">+            code = int(&quot;%03o&quot; % (val &amp; 0x07FF))</div><div dir="ltr">+            pol = (val &amp; 0x8000) and &quot;R&quot; or &quot;N&quot;</div><div dir="ltr">+            return code, pol</div><div dir="ltr">+</div><div dir="ltr">+        if _mem.tx_tone != 0xFFFF and _mem.tx_tone &gt; 0x2800:</div><div dir="ltr">+            tcode, tpol = _get_dcs(_mem.tx_tone)</div><div dir="ltr">+            mem.dtcs = tcode</div><div dir="ltr">+            txmode = &quot;DTCS&quot;</div><div dir="ltr">+        elif _mem.tx_tone != 0xFFFF:</div><div dir="ltr">+            mem.rtone = _mem.tx_tone / 10.0</div><div dir="ltr">+            txmode = &quot;Tone&quot;</div><div dir="ltr">+        else:</div><div dir="ltr">+            txmode = &quot;&quot;</div><div dir="ltr">+</div><div dir="ltr">+        if _mem.rx_tone != 0xFFFF and _mem.rx_tone &gt; 0x2800:</div><div dir="ltr">+            rcode, rpol = _get_dcs(_mem.rx_tone)</div><div dir="ltr">+            mem.rx_dtcs = rcode</div><div dir="ltr">+            rxmode = &quot;DTCS&quot;</div><div dir="ltr">+        elif _mem.rx_tone != 0xFFFF:</div><div dir="ltr">+            mem.ctone = _mem.rx_tone / 10.0</div><div dir="ltr">+            rxmode = &quot;Tone&quot;</div><div dir="ltr">+        else:</div><div dir="ltr">+            rxmode = &quot;&quot;</div><div dir="ltr">+</div><div dir="ltr">+        if txmode == &quot;Tone&quot; and not rxmode:</div><div dir="ltr">+            mem.tmode = &quot;Tone&quot;</div><div dir="ltr">+        elif txmode == rxmode and txmode == &quot;Tone&quot; and mem.rtone == mem.ctone:</div><div dir="ltr">+            mem.tmode = &quot;TSQL&quot;</div><div dir="ltr">+        elif txmode == rxmode and txmode == &quot;DTCS&quot; and mem.dtcs == mem.rx_dtcs:</div><div dir="ltr">+            mem.tmode = &quot;DTCS&quot;</div><div dir="ltr">+        elif rxmode or txmode:</div><div dir="ltr">+            mem.tmode = &quot;Cross&quot;</div><div dir="ltr">+            mem.cross_mode = &quot;%s-&gt;%s&quot; % (txmode, rxmode)</div><div dir="ltr">+</div><div dir="ltr">+        if mem.tmode == &quot;DTCS&quot;:</div><div dir="ltr">+            mem.dtcs_polarity = &quot;%s%s&quot; % (tpol, rpol)</div><div dir="ltr">+</div><div dir="ltr">+        LOG.debug(&quot;Got TX %s (%i) RX %s (%i)&quot; % (txmode, _mem.tx_tone,</div><div dir="ltr">+                                              rxmode, _mem.rx_tone))</div><div dir="ltr">+</div><div dir="ltr">+    def get_memory(self, number):</div><div dir="ltr">+        _mem = self._memobj.memory[number - 1]</div><div dir="ltr">+        _nam = self._memobj.chan_names[number - 1]</div><div dir="ltr">+</div><div dir="ltr">+        def _is_empty():</div><div dir="ltr">+            for i in range(0, 4):</div><div dir="ltr">+                if _mem.rx_freq[i].get_raw() != &quot;\xFF&quot;:</div><div dir="ltr">+                    return False</div><div dir="ltr">+            return True</div><div dir="ltr">+</div><div dir="ltr">+        mem = chirp_common.Memory()</div><div dir="ltr">+        mem.number = number</div><div dir="ltr">+</div><div dir="ltr">+        if _is_empty():</div><div dir="ltr">+            mem.empty = True</div><div dir="ltr">+            return mem</div><div dir="ltr">+</div><div dir="ltr">+        mem.freq = int(_mem.rx_freq) * 10</div><div dir="ltr">+</div><div dir="ltr">+        if int(_mem.rx_freq) == int(_mem.tx_freq):</div><div dir="ltr">+            mem.duplex = &quot;&quot;</div><div dir="ltr">+            mem.offset = 0</div><div dir="ltr">+        else:</div><div dir="ltr">+            mem.duplex = int(_mem.rx_freq) &gt; int(_mem.tx_freq) and &quot;-&quot; or &quot;+&quot;</div><div dir="ltr">+            mem.offset = abs(int(_mem.rx_freq) - int(_mem.tx_freq)) * 10</div><div dir="ltr">+</div><div dir="ltr">+        mem.mode = _mem.w_n and &quot;FM&quot; or &quot;NFM&quot;</div><div dir="ltr">+        self._get_tone(_mem, mem)</div><div dir="ltr">+        mem.power = POWER_LEVELS[_mem.power]</div><div dir="ltr">+</div><div dir="ltr">+        mem.extra = RadioSettingGroup(&quot;Extra&quot;, &quot;extra&quot;)</div><div dir="ltr">+        rs = RadioSetting(&quot;lout&quot;, &quot;Lock out&quot;,</div><div dir="ltr">+                          RadioSettingValueList(OFF_ON_LIST,</div><div dir="ltr">+                          OFF_ON_LIST[_mem.lout]))</div><div dir="ltr">+        mem.extra.append(rs)</div><div dir="ltr">+</div><div dir="ltr">+        rs = RadioSetting(&quot;busy_loc&quot;, &quot;Busy lock&quot;,</div><div dir="ltr">+                          RadioSettingValueList(BUSYLOCK_LIST,</div><div dir="ltr">+                          BUSYLOCK_LIST[_mem.busy_loc]))</div><div dir="ltr">+        mem.extra.append(rs)</div><div dir="ltr">+</div><div dir="ltr">+        rs = RadioSetting(&quot;scan_add&quot;, &quot;Scan add&quot;,</div><div dir="ltr">+                          RadioSettingValueList(NO_YES_LIST,</div><div dir="ltr">+                          NO_YES_LIST[_mem.scan_add]))</div><div dir="ltr">+        mem.extra.append(rs)</div><div dir="ltr">+        #TODO: Show name channel</div><div dir="ltr">+##        count = 0</div><div dir="ltr">+##        for i in _nam.chan_name:</div><div dir="ltr">+##            if i == 0xFF:</div><div dir="ltr">+##                break</div><div dir="ltr">+##            try:</div><div dir="ltr">+##                <a href="http://mem.name">mem.name</a> += IP620_CHARSET[i]</div><div dir="ltr">+##            except Exception:</div><div dir="ltr">+##                LOG.error(&quot;Unknown name char %i: 0x%02x (mem %i)&quot; %</div><div dir="ltr">+##                          (count, i, number - 1))</div><div dir="ltr">+##                <a href="http://mem.name">mem.name</a> += &quot; &quot;</div><div dir="ltr">+##            count += 1</div><div dir="ltr">+##        <a href="http://mem.name">mem.name</a> = mem.name.rstrip()</div><div dir="ltr">+</div><div dir="ltr">+        return mem</div><div dir="ltr">+</div><div dir="ltr">+    def _set_tone(self, mem, _mem):</div><div dir="ltr">+        def _set_dcs(code, pol):</div><div dir="ltr">+            val = int(&quot;%i&quot; % code, 8) + 0x2800</div><div dir="ltr">+            if pol == &quot;R&quot;:</div><div dir="ltr">+                val += 0x8000</div><div dir="ltr">+            return val</div><div dir="ltr">+</div><div dir="ltr">+        if mem.tmode == &quot;Cross&quot;:</div><div dir="ltr">+            tx_mode, rx_mode = mem.cross_mode.split(&quot;-&gt;&quot;)</div><div dir="ltr">+        elif mem.tmode == &quot;Tone&quot;:</div><div dir="ltr">+            tx_mode = mem.tmode</div><div dir="ltr">+            rx_mode = None</div><div dir="ltr">+        else:</div><div dir="ltr">+            tx_mode = rx_mode = mem.tmode</div><div dir="ltr">+</div><div dir="ltr">+        if tx_mode == &quot;DTCS&quot;:</div><div dir="ltr">+            _mem.tx_tone = mem.tmode != &quot;DTCS&quot; and \</div><div dir="ltr">+                _set_dcs(mem.dtcs, mem.dtcs_polarity[0]) or \</div><div dir="ltr">+                _set_dcs(mem.rx_dtcs, mem.dtcs_polarity[0])</div><div dir="ltr">+        elif tx_mode:</div><div dir="ltr">+            _mem.tx_tone = tx_mode == &quot;Tone&quot; and \</div><div dir="ltr">+                int(mem.rtone * 10) or int(mem.ctone * 10)</div><div dir="ltr">+        else:</div><div dir="ltr">+            _mem.tx_tone = 0xFFFF</div><div dir="ltr">+</div><div dir="ltr">+        if rx_mode == &quot;DTCS&quot;:</div><div dir="ltr">+            _mem.rx_tone = _set_dcs(mem.rx_dtcs, mem.dtcs_polarity[1])</div><div dir="ltr">+        elif rx_mode:</div><div dir="ltr">+            _mem.rx_tone = int(mem.ctone * 10)</div><div dir="ltr">+        else:</div><div dir="ltr">+            _mem.rx_tone = 0xFFFF</div><div dir="ltr">+</div><div dir="ltr">+        LOG.debug(&quot;Set TX %s (%i) RX %s (%i)&quot; % (tx_mode, _mem.tx_tone,</div><div dir="ltr">+                                              rx_mode, _mem.rx_tone))</div><div dir="ltr">+</div><div dir="ltr">+    def set_memory(self, mem):</div><div dir="ltr">+        _mem = self._memobj.memory[mem.number - 1]</div><div dir="ltr">+        if mem.empty:</div><div dir="ltr">+            _mem.set_raw(&quot;\xFF&quot; * (_mem.size() / 8))</div><div dir="ltr">+            return</div><div dir="ltr">+</div><div dir="ltr">+        _mem.rx_freq = mem.freq / 10</div><div dir="ltr">+        if mem.duplex == &quot;OFF&quot;:</div><div dir="ltr">+            for i in range(0, 4):</div><div dir="ltr">+                _mem.tx_freq[i].set_raw(&quot;\xFF&quot;)</div><div dir="ltr">+        elif mem.duplex == &quot;+&quot;:</div><div dir="ltr">+            _mem.tx_freq = (mem.freq + mem.offset) / 10</div><div dir="ltr">+        elif mem.duplex == &quot;-&quot;:</div><div dir="ltr">+            _mem.tx_freq = (mem.freq - mem.offset) / 10</div><div dir="ltr">+        else:</div><div dir="ltr">+            _mem.tx_freq = mem.freq / 10</div><div dir="ltr">+</div><div dir="ltr">+        _mem.w_n = mem.mode == &quot;FM&quot;</div><div dir="ltr">+        self._set_tone(mem, _mem)</div><div dir="ltr">+        _mem.power = mem.power == POWER_LEVELS[1]</div><div dir="ltr">+</div><div dir="ltr">+        for setting in mem.extra:</div><div dir="ltr">+            setattr(_mem, setting.get_name(), setting.value)</div><div dir="ltr">+</div><div dir="ltr">+    def get_settings(self):</div><div dir="ltr">+        _settings = self._memobj.settings</div><div dir="ltr">+        _settings_misc = self._memobj.settings_misc</div><div dir="ltr">+        basic = RadioSettingGroup(&quot;basic&quot;, &quot;Basic Settings&quot;)</div><div dir="ltr">+        top = RadioSettings(basic)</div><div dir="ltr">+</div><div dir="ltr">+        rs = RadioSetting(&quot;rf_sql&quot;, &quot;Squelch level (SQL)&quot;,</div><div dir="ltr">+                          RadioSettingValueList(RFSQL_LIST,</div><div dir="ltr">+                          RFSQL_LIST[_settings.rf_sql]))</div><div dir="ltr">+        basic.append(rs)</div><div dir="ltr">+</div><div dir="ltr">+        rs = RadioSetting(&quot;step_freq&quot;, &quot;Step frequency KHz (STP)&quot;,</div><div dir="ltr">+                          RadioSettingValueList(STEP_LIST,</div><div dir="ltr">+                          STEP_LIST[_settings.step_freq]))</div><div dir="ltr">+        basic.append(rs)</div><div dir="ltr">+</div><div dir="ltr">+        rs = RadioSetting(&quot;fm_radio&quot;, &quot;FM radio (DW)&quot;,</div><div dir="ltr">+                          RadioSettingValueList(OFF_ON_LIST,</div><div dir="ltr">+                          OFF_ON_LIST[_settings_misc.fm_radio]))</div><div dir="ltr">+        basic.append(rs)</div><div dir="ltr">+</div><div dir="ltr">+        rs = RadioSetting(&quot;call_tone&quot;, &quot;Call tone (CK)&quot;,</div><div dir="ltr">+                          RadioSettingValueList(CALLTONE_LIST,</div><div dir="ltr">+                          CALLTONE_LIST[_settings.call_tone]))</div><div dir="ltr">+        basic.append(rs)</div><div dir="ltr">+</div><div dir="ltr">+        rs = RadioSetting(&quot;tot&quot;, &quot;Time-out timer (TOT)&quot;,</div><div dir="ltr">+                          RadioSettingValueList(TIMEOUT_LIST,</div><div dir="ltr">+                          TIMEOUT_LIST[_settings.tot]))</div><div dir="ltr">+        basic.append(rs)</div><div dir="ltr">+</div><div dir="ltr">+        rs = RadioSetting(&quot;chan_disp_way&quot;, &quot;Channel display way&quot;,</div><div dir="ltr">+                          RadioSettingValueList(CH_FLAG_LIST,</div><div dir="ltr">+                          CH_FLAG_LIST[_settings.chan_disp_way]))</div><div dir="ltr">+        basic.append(rs)</div><div dir="ltr">+</div><div dir="ltr">+        rs = RadioSetting(&quot;vox&quot;, &quot;VOX Gain (VOX)&quot;,</div><div dir="ltr">+                          RadioSettingValueList(VOX_LIST,</div><div dir="ltr">+                          VOX_LIST[_settings.vox]))</div><div dir="ltr">+        basic.append(rs)</div><div dir="ltr">+</div><div dir="ltr">+        rs = RadioSetting(&quot;vox_dly&quot;, &quot;VOX Delay&quot;,</div><div dir="ltr">+                          RadioSettingValueList(VOXDELAY_LIST,</div><div dir="ltr">+                          VOXDELAY_LIST[_settings.vox_dly]))</div><div dir="ltr">+        basic.append(rs)</div><div dir="ltr">+</div><div dir="ltr">+        rs = RadioSetting(&quot;beep&quot;, &quot;Beep (BP)&quot;,</div><div dir="ltr">+                          RadioSettingValueList(OFF_ON_LIST,</div><div dir="ltr">+                          OFF_ON_LIST[_settings.beep]))</div><div dir="ltr">+        basic.append(rs)</div><div dir="ltr">+</div><div dir="ltr">+        rs = RadioSetting(&quot;auto_lock&quot;, &quot;Auto lock (KY)&quot;,</div><div dir="ltr">+                          RadioSettingValueList(NO_YES_LIST,</div><div dir="ltr">+                          NO_YES_LIST[_settings_misc.auto_lock]))</div><div dir="ltr">+        basic.append(rs)</div><div dir="ltr">+</div><div dir="ltr">+        rs = RadioSetting(&quot;bat_save&quot;, &quot;Battery Saver (SAV)&quot;,</div><div dir="ltr">+                          RadioSettingValueList(BAT_SAVE_LIST,</div><div dir="ltr">+                          BAT_SAVE_LIST[_settings.bat_save]))</div><div dir="ltr">+        basic.append(rs)</div><div dir="ltr">+</div><div dir="ltr">+        rs = RadioSetting(&quot;chan_pri&quot;, &quot;Channel PRI (PRI)&quot;,</div><div dir="ltr">+                          RadioSettingValueList(OFF_ON_LIST,</div><div dir="ltr">+                          OFF_ON_LIST[_settings.chan_pri]))</div><div dir="ltr">+        basic.append(rs)</div><div dir="ltr">+</div><div dir="ltr">+        rs = RadioSetting(&quot;chan_pri_num&quot;, &quot;Channel PRI time Sec (PRI)&quot;,</div><div dir="ltr">+                          RadioSettingValueList(PRI_NUM_LIST,</div><div dir="ltr">+                          PRI_NUM_LIST[_settings.chan_pri_num]))</div><div dir="ltr">+        basic.append(rs)</div><div dir="ltr">+</div><div dir="ltr">+        rs = RadioSetting(&quot;end_beep&quot;, &quot;End beep (ET)&quot;,</div><div dir="ltr">+                          RadioSettingValueList(ENDBEEP_LIST,</div><div dir="ltr">+                          ENDBEEP_LIST[_settings.end_beep]))</div><div dir="ltr">+        basic.append(rs)</div><div dir="ltr">+</div><div dir="ltr">+        rs = RadioSetting(&quot;ch_mode&quot;, &quot;CH mode&quot;,</div><div dir="ltr">+                          RadioSettingValueList(ON_OFF_LIST,</div><div dir="ltr">+                          ON_OFF_LIST[_settings.ch_mode]))</div><div dir="ltr">+        basic.append(rs)</div><div dir="ltr">+</div><div dir="ltr">+        rs = RadioSetting(&quot;scan_rev&quot;, &quot;Scan rev (SCAN)&quot;,</div><div dir="ltr">+                          RadioSettingValueList(SCANM_LIST,</div><div dir="ltr">+                          SCANM_LIST[_settings.scan_rev]))</div><div dir="ltr">+        basic.append(rs)</div><div dir="ltr">+</div><div dir="ltr">+        rs = RadioSetting(&quot;enc&quot;, &quot;Frequency lock (ENC)&quot;,</div><div dir="ltr">+                          RadioSettingValueList(OFF_ON_LIST,</div><div dir="ltr">+                          OFF_ON_LIST[_settings.enc]))</div><div dir="ltr">+        basic.append(rs)</div><div dir="ltr">+</div><div dir="ltr">+        rs = RadioSetting(&quot;wait_back_light&quot;, &quot;Wait back light (LED)&quot;,</div><div dir="ltr">+                          RadioSettingValueList(BACKLIGHT_LIST,</div><div dir="ltr">+                          BACKLIGHT_LIST[_settings.wait_back_light]))</div><div dir="ltr">+        basic.append(rs)</div><div dir="ltr">+</div><div dir="ltr">+        return top</div><div dir="ltr">+</div><div dir="ltr">+    def _set_misc_settings(self, settings):</div><div dir="ltr">+        for element in settings:</div><div dir="ltr">+            try:</div><div dir="ltr">+                setattr(self._memobj.settings_misc,</div><div dir="ltr">+                        element.get_name(),</div><div dir="ltr">+                        element.value)</div><div dir="ltr">+            except Exception, e:</div><div dir="ltr">+                LOG.debug(element.get_name())</div><div dir="ltr">+                raise</div><div dir="ltr">+</div><div dir="ltr">+    def set_settings(self, settings):</div><div dir="ltr">+        _settings = self._memobj.settings</div><div dir="ltr">+        _settings_misc = self._memobj.settings_misc</div><div dir="ltr">+        for element in settings:</div><div dir="ltr">+            if not isinstance(element, RadioSetting):</div><div dir="ltr">+                self.set_settings(element)</div><div dir="ltr">+                continue</div><div dir="ltr">+            if not element.changed():</div><div dir="ltr">+                continue</div><div dir="ltr">+            try:</div><div dir="ltr">+                setting = element.get_name()</div><div dir="ltr">+                if setting in [&quot;auto_lock&quot;,&quot;fm_radio&quot;]:</div><div dir="ltr">+                    oldval = getattr(_settings_misc, setting)</div><div dir="ltr">+                else:</div><div dir="ltr">+                    oldval = getattr(_settings, setting)</div><div dir="ltr">+</div><div dir="ltr">+                newval = element.value</div><div dir="ltr">+</div><div dir="ltr">+                LOG.debug(&quot;Setting %s(%s) &lt;= %s&quot; % (setting, oldval, newval))</div><div dir="ltr">+                if setting in [&quot;auto_lock&quot;,&quot;fm_radio&quot;]:</div><div dir="ltr">+                    setattr(_settings_misc, setting, newval)</div><div dir="ltr">+                else:</div><div dir="ltr">+                    setattr(_settings, setting, newval)</div><div dir="ltr">+            except Exception, e:</div><div dir="ltr">+                LOG.debug(element.get_name())</div><div dir="ltr">+                raise</div><div><br></div></div></div>
</div>