Project

General

Profile

Bug #10495 » id51plus.py

Dan Smith, 04/01/2023 07:45 AM

 
1
# Copyright 2015 Eric Dropps <kc1ckh@kc1ckh.com>
2
#
3
# This program is free software: you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation, either version 3 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
from builtins import bytes
16

    
17
import logging
18

    
19
from chirp.drivers import id31
20
from chirp import directory, bitwise
21

    
22
LOG = logging.getLogger(__name__)
23

    
24
MEM_FORMAT = """
25
struct {
26
  u24 freq;
27
  u16 offset;
28
  u16 rtone:6,
29
      ctone:6,
30
      unknown2:1,
31
      mode:3;
32
  u8 dtcs;
33
  u8 tune_step:4,
34
     dsql_mode:2,
35
     unknown5:2;
36
  u8 unknown4;
37
  u8 tmode:4,
38
     duplex:2,
39
     dtcs_polarity:2;
40
  char name[16];
41
  u8 digcode;
42
  u8 urcall[7];
43
  u8 rpt1call[7];
44
  u8 rpt2call[7];
45
} memory[500];
46

    
47
#seekto 0x6A40;
48
u8 used_flags[70];
49

    
50
#seekto 0x6A86;
51
u8 skip_flags[69];
52

    
53
#seekto 0x6ACB;
54
u8 pskp_flags[69];
55

    
56
#seekto 0x6B40;
57
struct {
58
  u8 unknown:3,
59
     bank:5;
60
  u8 index;
61
} banks[500];
62

    
63
#seekto 0x6FD0;
64
struct {
65
  char name[16];
66
} bank_names[26];
67

    
68

    
69
#seekto 0xA8C0;
70
struct {
71
  u24 freq;
72
  u16 offset;
73
  u8 unknown1[4];
74
  u8 call[7];
75
  char name[16];
76
  char subname[8];
77
  u8 unknown3[10];
78
} repeaters[750];
79

    
80
#seekto 0x1384E;
81
struct {
82
  u8 call[7];
83
} rptcall[750];
84

    
85
#seekto 0x14FBE;
86
struct {
87
 char name[16];
88
} rptgroup_names[30];
89

    
90
#seekto 0x1519E;
91
struct {
92
  char call[8];
93
  char tag[4];
94
} mycall[6];
95

    
96
#seekto 0x151E6;
97
struct {
98
  char call[8];
99
} urcall[200];
100

    
101
#seekto 0x15826;
102
struct {
103
  char name[16];
104
} urcallname[200];
105
"""
106

    
107

    
108
@directory.register
109
class ID51PLUSRadio(id31.ID31Radio):
110
    """Icom ID-51 Plus/50th Anniversary"""
111
    MODEL = "ID-51 Plus"
112

    
113
    _memsize = 0x1FB40
114
    _model = "\x33\x90\x00\x02"
115
    _endframe = "Icom Inc\x2E\x44\x41"
116
    _bank_class = id31.ID31Bank
117
    _ranges = [(0x00000, 0x1FB40, 32)]
118

    
119
    MODES = {0: "FM", 1: "NFM", 3: "AM", 5: "DV"}
120

    
121
    @classmethod
122
    def match_model(cls, filedata, filename):
123
        """Given contents of a stored file (@filedata), return True if
124
        this radio driver handles the represented model"""
125

    
126
        # The default check for ICOM is just to check memory size
127
        # Since the ID-51 and ID-51 Plus/Anniversary have exactly
128
        # the same memory size, we need to do a more detailed check.
129
        if len(filedata) == cls._memsize:
130
            snip = bytes(filedata[0x1AF40:0x1AF60])
131
            if snip != bytes(b'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF'
132
                             b'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF'
133
                             b'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF'
134
                             b'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF'):
135
                return True
136
        return False
137

    
138
    def _get_bank(self, loc):
139
        _bank = self._memobj.banks[loc]
140
        LOG.debug("Bank Value for location %s is %s" % (loc, _bank.bank))
141
        if _bank.bank == 0x1F:
142
            return None
143
        else:
144
            return _bank.bank
145

    
146
    def _set_bank(self, loc, bank):
147
        _bank = self._memobj.banks[loc]
148
        if bank is None:
149
            _bank.bank = 0x1F
150
        else:
151
            _bank.bank = bank
152

    
153
    def get_features(self):
154
        rf = super(ID51PLUSRadio, self).get_features()
155
        rf.valid_bands = [(108000000, 174000000), (380000000, 479000000)]
156
        return rf
157

    
158
    def get_repeater_call_list(self):
159
        calls = []
160
        # Unlike previous DStar radios, there is not a separate repeater
161
        # callsign list. It's only the DV Memory banks.
162
        for repeater in self._memobj.repeaters:
163
            call = id31._decode_call(repeater.call)
164
            if call == "CALLSIGN":
165
                call = ""
166
            calls.append(call.rstrip())
167
        return calls
168

    
169
    def process_mmap(self):
170
        self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
171

    
172

    
173
@directory.register
174
class ID51PLUS2Radio(ID51PLUSRadio):
175
    MODEL = 'ID-51 Plus2'
176
    _model = b'\x33\x90\x00\x03'
177
    _endframe = 'Icom Inc.DA'
178

    
179
    _raw_frames = True
180
    _highbit_flip = True
181

    
182
    _icf_data = {
183
        'MapRev': 1,
184
        'EtcData': 0x400001,
185
    }
186

    
187
    @classmethod
188
    def match_model(cls, filedata, filename):
189
        # This model is always matched with metadata
190
        return False
(2-2/3)