Project

General

Profile

New Model #280 ยป icw32.py

IC-W32 driver with E version support - Filippi Marco, 10/16/2015 10:15 AM

 
1
# Copyright 2011 Dan Smith <dsmith@danplanet.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

    
16
import logging
17

    
18
from chirp.drivers import icf
19
from chirp import chirp_common, util, directory, bitwise
20

    
21
LOG = logging.getLogger(__name__)
22

    
23
MEM_FORMAT = """
24
#seekto 0x%x;
25
struct {
26
  bbcd freq[3];
27
  bbcd offset[3];
28
  u8 ctone;
29
  u8 rtone;
30
  char name[8];
31
} memory[111];
32

    
33
#seekto 0x%x;
34
struct {
35
  u8 empty:1,
36
     skip:1,
37
     tmode:2,
38
     duplex:2,
39
     unk3:1,
40
     am:1;
41
} flag[111];
42

    
43
#seekto 0x0E9C;
44
struct {
45
  u8 unknown1:7,
46
     right_scan_direction:1;
47
  u8 right_scanning:1,
48
     unknown2:7;
49
  u8 unknown3:7,
50
     left_scan_direction:1;
51
  u8 left_scanning:1,
52
     unknown4:7;
53
} state[1];
54

    
55
#seekto 0x0F20;
56
struct {
57
  bbcd freq[3];
58
  bbcd offset[3];
59
  u8 ctone;
60
  u8 rtone;
61
} callchans[2];
62

    
63
"""
64

    
65
DUPLEX = ["", "", "-", "+"]
66
TONE = ["", "", "Tone", "TSQL"]
67

    
68

    
69
def _get_special():
70
    special = {}
71
    for i in range(0, 5):
72
        special["M%iA" % (i+1)] = 100 + i*2
73
        special["M%iB" % (i+1)] = 100 + i*2 + 1
74
    return special
75

    
76

    
77
@directory.register
78
class ICW32ARadio(icf.IcomCloneModeRadio):
79
    """Icom IC-W32A"""
80
    VENDOR = "Icom"
81
    MODEL = "IC-W32A"
82

    
83
    _model = "\x18\x82\x00\x01"
84
    _memsize = 4064
85
    _endframe = "Icom Inc\x2e"
86

    
87
    _ranges = [(0x0000, 0x0FE0, 16)]
88

    
89
    _limits = (0, 0)
90
    _mem_positions = (0, 1)
91

    
92
    def get_features(self):
93
        rf = chirp_common.RadioFeatures()
94
        rf.memory_bounds = (0, 99)
95
        rf.valid_bands = [self._limits]
96
        if int(self._limits[0] / 100) == 1:
97
            rf.valid_modes = ["FM", "AM"]
98
        else:
99
            rf.valid_modes = ["FM"]
100
        rf.valid_tmodes = ["", "Tone", "TSQL"]
101
        rf.valid_name_length = 8
102
        rf.valid_special_chans = sorted(_get_special().keys())
103

    
104
        rf.has_sub_devices = self.VARIANT == ""
105
        rf.has_ctone = True
106
        rf.has_dtcs = False
107
        rf.has_dtcs_polarity = False
108
        rf.has_mode = "AM" in rf.valid_modes
109
        rf.has_tuning_step = False
110
        rf.has_bank = False
111

    
112
        return rf
113

    
114
    def process_mmap(self):
115
        fmt = MEM_FORMAT % self._mem_positions
116
        self._memobj = bitwise.parse(fmt, self._mmap)
117

    
118
    def get_raw_memory(self, number):
119
        return repr(self._memobj.memory[number])
120

    
121
    def get_memory(self, number):
122
        if isinstance(number, str):
123
            number = _get_special()[number]
124

    
125
        _mem = self._memobj.memory[number]
126
        _flg = self._memobj.flag[number]
127

    
128
        mem = chirp_common.Memory()
129
        mem.number = number
130

    
131
        if number < 100:
132
            # Normal memories
133
            mem.skip = _flg.skip and "S" or ""
134
        else:
135
            # Special memories
136
            mem.extd_number = util.get_dict_rev(_get_special(), number)
137

    
138
        if _flg.empty:
139
            mem.empty = True
140
            return mem
141

    
142
        mem.freq = chirp_common.fix_rounded_step(int(_mem.freq) * 1000)
143
        mem.offset = int(_mem.offset) * 100
144
        if str(_mem.name)[0] != chr(0xFF):
145
            mem.name = str(_mem.name).rstrip()
146
        mem.rtone = chirp_common.TONES[_mem.rtone]
147
        mem.ctone = chirp_common.TONES[_mem.ctone]
148

    
149
        mem.mode = _flg.am and "AM" or "FM"
150
        mem.duplex = DUPLEX[_flg.duplex]
151
        mem.tmode = TONE[_flg.tmode]
152

    
153
        if number > 100:
154
            mem.immutable = ["number", "skip", "extd_number", "name"]
155

    
156
        return mem
157

    
158
    def set_memory(self, mem):
159
        _mem = self._memobj.memory[mem.number]
160
        _flg = self._memobj.flag[mem.number]
161

    
162
        _flg.empty = mem.empty
163
        if mem.empty:
164
            return
165

    
166
        _mem.freq = mem.freq / 1000
167
        _mem.offset = mem.offset / 100
168
        if mem.name:
169
            _mem.name = mem.name.ljust(8)[:8]
170
        else:
171
            _mem.name = "".join(["\xFF" * 8])
172
        _mem.rtone = chirp_common.TONES.index(mem.rtone)
173
        _mem.ctone = chirp_common.TONES.index(mem.ctone)
174

    
175
        _flg.duplex = DUPLEX.index(mem.duplex)
176
        _flg.tmode = TONE.index(mem.tmode)
177
        _flg.skip = mem.skip == "S"
178
        _flg.am = mem.mode == "AM"
179

    
180
        if self._memobj.state.left_scanning:
181
            LOG.debug("Canceling scan on left VFO")
182
            self._memobj.state.left_scanning = 0
183
        if self._memobj.state.right_scanning:
184
            LOG.debug("Canceling scan on right VFO")
185
            self._memobj.state.right_scanning = 0
186

    
187
    def get_sub_devices(self):
188
        return [ICW32ARadioVHF(self._mmap), ICW32ARadioUHF(self._mmap)]
189

    
190
    @classmethod
191
    def match_model(cls, filedata, filename):
192
        if not len(filedata) == cls._memsize:
193
            return False
194
        return filedata[-16:] == "IcomCloneFormat3"
195

    
196

    
197
class ICW32ARadioVHF(ICW32ARadio):
198
    """ICW32 VHF subdevice"""
199
    VARIANT = "VHF"
200
    _limits = (118000000, 174000000)
201
    _mem_positions = (0x0000, 0x0DC0)
202

    
203

    
204
class ICW32ARadioUHF(ICW32ARadio):
205
    """ICW32 UHF subdevice"""
206
    VARIANT = "UHF"
207
    _limits = (400000000, 470000000)
208
    _mem_positions = (0x06E0, 0x0E2E)
209

    
210

    
211
# IC-W32E are the very same as IC-W32A but have a different _model
212
@directory.register
213
class ICW32ERadio(ICW32ARadio):
214
    """Icom IC-W32E"""
215
    MODEL = "IC-W32E"
216

    
217
    _model = "\x18\x82\x00\x02"
218

    
219
    # an extra byte is added to distinguish file images from IC-W32A
220
    # it will be allocated and initialized to 0x00 in _clone_from_radio
221
    # (icf.py) but radio will not send it
222
    # That byte is not sent to radio because the _clone_to_radio use _ranges
223
    # for the send cycle
224
    _memsize = ICW32ARadio._memsize + 1
225

    
226
    def get_sub_devices(self):
227
        # this is needed because sub devices must be of a child class
228
        return [ICW32ERadioVHF(self._mmap), ICW32ERadioUHF(self._mmap)]
229

    
230
    @classmethod
231
    def match_model(cls, filedata, filename):
232
        if not len(filedata) == cls._memsize:
233
            return False
234
        return filedata[-16 - 1: -1] == "IcomCloneFormat3" and \
235
            filedata[-1] == chr(0x00)
236

    
237

    
238
# this is the very same as ICW32ARadioVHF but have ICW32ERadio as parent class
239
class ICW32ERadioVHF(ICW32ERadio):
240
    """ICW32 VHF subdevice"""
241
    VARIANT = "VHF"
242
    _limits = (118000000, 174000000)
243
    _mem_positions = (0x0000, 0x0DC0)
244

    
245

    
246
# this is the very same as ICW32ARadioUHF but have ICW32ERadio as parent class
247
class ICW32ERadioUHF(ICW32ERadio):
248
    """ICW32 UHF subdevice"""
249
    VARIANT = "UHF"
250
    _limits = (400000000, 470000000)
251
    _mem_positions = (0x06E0, 0x0E2E)
    (1-1/1)