[chirp_devel] [PATCH] [id51] Add support for Icom ID-51A #553

Dean Gibson
Wed Feb 20 18:55:29 PST 2013


# HG changeset patch
# User Dean Gibson <data at ae7q.net>
# Date 1361414752 28800
# Node ID a509b80675f08afb453b33b20187848b0ce4d14c
# Parent  3aa15df765586388d0b71671d079f27524a884cc
[id51] Add support for Icom ID-51A #553

diff -r 3aa15df76558 -r a509b80675f0 chirp/id51.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chirp/id51.py	Wed Feb 20 18:45:52 2013 -0800
@@ -0,0 +1,323 @@
+# Copyright 2012 Dan Smith <dsmith at danplanet.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 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
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from chirp import directory, icf, bitwise, chirp_common
+
+MEM_FORMAT = """
+struct {
+  u24 freq;
+  u16 offset;
+  u16 rtone:6,
+      ctone:6,
+      unknown2:1,
+      mode:3;
+  u8 dtcs;
+  u8 tune_step:4,
+     unknown5:4;
+  u8 unknown4;
+  u8 tmode:4,
+     duplex:2,
+     dtcs_polarity:2;
+  char name[16];
+  u8 unknown13;
+  u8 urcall[7];
+  u8 rpt1call[7];
+  u8 rpt2call[7];
+} memory[500];
+
+#seekto 0x6A40;
+u8 used_flags[70];
+
+#seekto 0x6A86;
+u8 skip_flags[69];
+
+#seekto 0x6ACB;
+u8 pskp_flags[69];
+
+#seekto 0x6B40;
+struct {
+  u8 bank;
+  u8 index;
+} banks[500];
+
+#seekto 0x6FD0;
+struct {
+  char name[16];
+} bank_names[26];
+
+#seekto 0xA8C0;
+struct {
+  u24 freq;
+  u16 offset;
+  u8 unknown1[3];
+  u8 call[7];
+  char name[16];
+  char subname[8];
+  u8 unknown3[10];
+} repeaters[750];
+
+#seekto 0x1384E;
+struct {
+  u8 call[7];
+} rptcall[750];
+
+#seekto 0x14E60;
+struct {
+  char call[8];
+  char tag[4];
+} mycall[6];
+
+#seekto 0x14EA8;
+struct {
+  char call[8];
+} urcall[200];
+
+"""
+
+MODES = [ "FM", "NFM", "AM", "DV" ]  
+MODE_INDEX = [ 0, 1, 3, 5 ]  
+TMODES = ["", "Tone", "TSQL", "TSQL", "DTCS", "DTCS", "TSQL-R", "DTCS-R"]
+DUPLEX = ["", "-", "+"]
+DTCS_POLARITY = ["NN", "NR", "RN", "RR"]
+TUNING_STEPS = [5.0, 6.25, 0, 0, 10.0, 12.5, 15.0, 20.0, 25.0, 30.0, 50.0,
+                100.0, 125.0, 200.0]
+
+def _decode_call(_call):
+    # Why Icom, why?
+    call = ""
+    shift = 1
+    acc = 0
+    for val in _call:
+        mask = (1 << (shift)) - 1
+        call += chr((val >> shift) | acc)
+        acc = (val & mask) << (7 - shift)
+        shift += 1
+    call += chr(acc)
+    return call
+
+def _encode_call(call):
+    _call = [0x00] * 7
+    for i in range(0, 7):
+        val = ord(call[i]) << (i + 1)
+        if i > 0:
+            _call[i-1] |= (val & 0xFF00) >> 8
+        _call[i] = val
+    _call[6] |= (ord(call[7]) & 0x7F)
+        
+    return _call
+
+def _get_freq(_mem):
+    freq = int(_mem.freq)
+    offs = int(_mem.offset)
+
+    if freq & 0x00200000:
+        mult = 6250
+    else:
+        mult = 5000
+
+    freq &= 0x0003FFFF
+
+    return (freq * mult), (offs * mult)
+
+def _set_freq(_mem, freq, offset):
+    if chirp_common.is_fractional_step(freq):
+        mult = 6250
+        flag = 0x00200000
+    else:
+        mult = 5000
+        flag = 0x00000000
+
+    _mem.freq = (freq / mult) | flag
+    _mem.offset = (offset / mult)
+
+class ID51Bank(icf.IcomBank):
+    """A ID-51 Bank"""
+    def get_name(self):
+        _banks = self._model._radio._memobj.bank_names
+        return str(_banks[self.index].name).rstrip()
+
+    def set_name(self, name):
+        _banks = self._model._radio._memobj.bank_names
+        _banks[self.index].name = str(name).ljust(16)[:16]
+
+ at directory.register
+class ID51Radio(icf.IcomCloneModeRadio, chirp_common.IcomDstarSupport):
+    """Icom ID-51"""
+    MODEL = "ID-51A"
+
+    _memsize = 0x1FB40
+    _model = "\x33\x90\x00\x01"
+    _endframe = "Icom Inc\x2E\x44\x41"
+    _num_banks = 26
+    _bank_class = ID51Bank
+    _can_hispeed = True
+
+    _ranges = [(0x00000, 0x1FB40, 32)]
+
+    def _get_bank(self, loc):
+        _bank = self._memobj.banks[loc]
+        if _bank.bank == 0xFF:
+            return None
+        else:
+            return _bank.bank
+
+    def _set_bank(self, loc, bank):
+        _bank = self._memobj.banks[loc]
+        if bank is None:
+            _bank.bank = 0xFF
+        else:
+            _bank.bank = bank
+
+    def _get_bank_index(self, loc):
+        _bank = self._memobj.banks[loc]
+        return _bank.index
+
+    def _set_bank_index(self, loc, index):
+        _bank = self._memobj.banks[loc]
+        _bank.index = index
+
+    def get_features(self):
+        rf = chirp_common.RadioFeatures()
+        rf.memory_bounds = (0, 499)
+        rf.valid_bands = [(108000000, 174000000), (400000000, 479000000)]
+        rf.has_settings = True
+        rf.has_ctone = True
+        rf.has_bank_index = True
+        rf.has_bank_names = True
+        rf.valid_tmodes = list(TMODES)
+        rf.valid_tuning_steps = sorted(list(TUNING_STEPS))
+        rf.valid_modes = list(MODES)
+        rf.valid_skips = ["", "S", "P"]
+        rf.valid_characters = chirp_common.CHARSET_ASCII
+        rf.valid_name_length = 16
+        return rf
+
+    def process_mmap(self):
+        self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
+
+    def get_raw_memory(self, number):
+        return repr(self._memobj.memory[number])
+
+    def get_memory(self, number):
+        _mem = self._memobj.memory[number]
+        _usd = self._memobj.used_flags[number / 8]
+        _skp = self._memobj.skip_flags[number / 8]
+        _psk = self._memobj.pskp_flags[number / 8]
+
+        bit = (1 << (number % 8))
+
+        if MODES[MODE_INDEX.index(_mem.mode)] == "DV":
+            mem = chirp_common.DVMemory()
+        else:
+            mem = chirp_common.Memory()
+        mem.number = number
+
+        if _usd & bit:
+            mem.empty = True
+            return mem
+
+        mem.freq, mem.offset = _get_freq(_mem)
+        mem.name = str(_mem.name).rstrip()
+        mem.rtone = chirp_common.TONES[_mem.rtone]
+        mem.ctone = chirp_common.TONES[_mem.ctone]
+        mem.tmode = TMODES[_mem.tmode]
+        mem.duplex = DUPLEX[_mem.duplex]
+        mem.dtcs = chirp_common.DTCS_CODES[_mem.dtcs]
+        mem.dtcs_polarity = DTCS_POLARITY[_mem.dtcs_polarity]
+        mem.tuning_step = TUNING_STEPS[_mem.tune_step]
+        mem.mode = MODES[MODE_INDEX.index(_mem.mode)]
+        
+        if mem.mode == "DV":
+            mem.dv_urcall = _decode_call(_mem.urcall).rstrip()
+            mem.dv_rpt1call = _decode_call(_mem.rpt1call).rstrip()
+            mem.dv_rpt2call = _decode_call(_mem.rpt2call).rstrip()
+
+        if _psk & bit:
+            mem.skip = "P"
+        if _skp & bit:
+            mem.skip = "S"
+            
+        return mem
+
+    def set_memory(self, memory):
+        _mem = self._memobj.memory[memory.number]
+        _usd = self._memobj.used_flags[memory.number / 8]
+        _skp = self._memobj.skip_flags[memory.number / 8]
+        _psk = self._memobj.pskp_flags[memory.number / 8]
+
+        bit = (1 << (memory.number % 8))
+
+        if memory.empty:
+            _usd |= bit
+            self._set_bank(memory.number, None)
+            return
+
+        _usd &= ~bit
+
+        _set_freq(_mem, memory.freq, memory.offset)
+        _mem.name = memory.name.ljust(16)[:16]
+        _mem.rtone = chirp_common.TONES.index(memory.rtone)
+        _mem.ctone = chirp_common.TONES.index(memory.ctone)
+        _mem.tmode = TMODES.index(memory.tmode)
+        _mem.duplex = DUPLEX.index(memory.duplex)
+        _mem.dtcs = chirp_common.DTCS_CODES.index(memory.dtcs)
+        _mem.dtcs_polarity = DTCS_POLARITY.index(memory.dtcs_polarity)
+        _mem.tune_step = TUNING_STEPS.index(memory.tuning_step)
+        _mem.mode = MODE_INDEX[MODES.index(memory.mode)]
+
+        if isinstance(memory, chirp_common.DVMemory):
+            _mem.urcall = _encode_call(memory.dv_urcall.ljust(8))
+            _mem.rpt1call = _encode_call(memory.dv_rpt1call.ljust(8))
+            _mem.rpt2call = _encode_call(memory.dv_rpt2call.ljust(8))
+        elif memory.mode == "DV":
+            raise Exception("BUG")
+
+        if memory.skip == "S":
+            _skp |=  bit
+            _psk &= ~bit
+        elif memory.skip == "P":
+            _skp &= ~bit
+            _psk |=  bit
+        else:
+            _skp &= ~bit
+            _psk &= ~bit
+            
+    def get_urcall_list(self):
+        calls = []
+        for i in range(0, 200):
+            call = str(self._memobj.urcall[i].call)
+            if call == "CALLSIGN":
+                call = ""
+            calls.append(call)
+        return calls
+
+    def get_mycall_list(self):
+        calls = []
+        for i in range(0, 6):
+            calls.append(str(self._memobj.mycall[i].call))
+        return calls
+
+    def get_repeater_call_list(self):
+        calls = []
+        for rptcall in self._memobj.rptcall:
+            call = _decode_call(rptcall.call)
+            if call.rstrip() and not call == "CALLSIGN":
+                calls.append(call)
+        for repeater in self._memobj.repeaters:
+            call = _decode_call(repeater.call)
+            if call == "CALLSIGN":
+                call = ""
+            calls.append(call.rstrip())
+        return calls



More information about the chirp_devel mailing list