Project

General

Profile

New Model #6525 » FTM7250D.patch

Mercurial patch file - Iain White, 06/29/2020 12:38 PM

View differences:

chirp/drivers/ftm7250d.py
1
# Copyright 2010 Dan Smith <dsmith@danplanet.com>
2
# Copyright 2017 Wade Simmons <wade@wades.im>
3
# FTM-7250D driver cloned from the FTM-3200 and modified by Iain White
4
#
5
# This program is free software: you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation, either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17

  
18
import logging
19
from textwrap import dedent
20

  
21
from chirp.drivers import yaesu_clone, ft1d
22
from chirp import chirp_common, directory, bitwise
23
from chirp.settings import RadioSettings
24

  
25
LOG = logging.getLogger(__name__)
26

  
27
POWER_LEVELS = [chirp_common.PowerLevel("Low", watts=5),
28
                chirp_common.PowerLevel("Mid", watts=25),
29
                chirp_common.PowerLevel("Hi", watts=50)]
30

  
31
TMODES = ["", "Tone", "TSQL", "DTCS", "TSQL-R", None, None, "Pager", "Cross"]
32
CROSS_MODES = [None, "DTCS->", "Tone->DTCS", "DTCS->Tone"]
33

  
34
MODES = ["FM", "NFM"]
35
STEPS = [0, 5, 6.25, 10, 12.5, 15, 20, 25, 50, 100]  # 0 = auto
36
RFSQUELCH = ["OFF", "S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8"]
37

  
38
# Charset is subset of ASCII + some unknown chars \x80-\x86
39
VALID_CHARS = ["%i" % int(x) for x in range(0, 10)] + \
40
    list(":>=<?@") + \
41
    [chr(x) for x in range(ord("A"), ord("Z") + 1)] + \
42
    list("[\\]_") + \
43
    [chr(x) for x in range(ord("a"), ord("z") + 1)] + \
44
    list("%*+,-/=$ ")
45

  
46
MEM_FORMAT = """
47
#seekto 0xceca;
48
struct {
49
  u8 unknown5;
50
  u8 unknown3;
51
  u8 unknown4:6,
52
     dsqtype:2;
53
  u8 dsqcode;
54
  u8 unknown1[2];
55
  char mycall[10];
56
  u8 unknown2[368];
57
} settings;
58

  
59
#seekto 0xfec9;
60
u8 checksum;
61
"""
62

  
63

  
64
@directory.register
65
class FTM7250Radio(ft1d.FT1Radio):
66
    """Yaesu FTM-7250D"""
67
    BAUD_RATE = 38400
68
    VENDOR = "Yaesu"
69
    MODEL = "FTM-7250D"
70
    VARIANT = "R"
71

  
72
    _model = "AH52N"
73
    _memsize = 65227
74
    _block_lengths = [10, 65217]
75
    _has_vibrate = False
76
    _has_af_dual = False
77

  
78
    _mem_params = (199,            # size of memories array
79
                   199)            # size of flags array
80

  
81
    @classmethod
82
    def get_prompts(cls):
83
        rp = chirp_common.RadioPrompts()
84
        rp.pre_download = _(dedent("""\
85
            1. Turn radio off.
86
            2. Connect cable to MIC Jack.
87
            3. Press and hold in the [MHz(SETUP)] key while turning the radio
88
                 on ("CLONE" will appear on the display).
89
            4. <b>After clicking OK</b>, press the [GM(AMS)] key
90
                 to send image."""))
91
        rp.pre_upload = _(dedent("""\
92
            1. Turn radio off.
93
            2. Connect cable to MIC Jack.
94
            3. Press and hold in the [MHz(SETUP)] key while turning the radio
95
                 on ("CLONE" will appear on the display).
96
            4. Press the [MHz(SETUP)] key
97
                 ("-WAIT-" will appear on the LCD)."""))
98
        return rp
99

  
100
    def process_mmap(self):
101
        mem_format = ft1d.MEM_FORMAT + MEM_FORMAT
102
        self._memobj = bitwise.parse(mem_format % self._mem_params, self._mmap)
103

  
104
    def get_features(self):
105
        rf = chirp_common.RadioFeatures()
106
        rf.has_dtcs_polarity = False
107
        rf.valid_modes = list(MODES)
108
        rf.valid_tmodes = [x for x in TMODES if x is not None]
109
        rf.valid_cross_modes = [x for x in CROSS_MODES if x is not None]
110
        rf.valid_duplexes = list(ft1d.DUPLEX)
111
        rf.valid_tuning_steps = list(STEPS)
112
        rf.valid_bands = [(136000000, 174000000),(420000000, 450000000)]
113
        # rf.valid_skips = SKIPS
114
        rf.valid_power_levels = POWER_LEVELS
115
        rf.valid_characters = "".join(VALID_CHARS)
116
        rf.valid_name_length = 8
117
        rf.memory_bounds = (1, 199)
118
        rf.can_odd_split = True
119
        rf.has_ctone = False
120
        rf.has_bank = False
121
        rf.has_bank_names = False
122
        # disable until implemented
123
        rf.has_settings = False
124
        return rf
125

  
126
    def _decode_label(self, mem):
127
        # TODO preserve the unknown \x80-x86 chars?
128
        return str(mem.label).rstrip("\xFF").decode('ascii', 'replace')
129

  
130
    def _encode_label(self, mem):
131
        label = mem.name.rstrip().encode('ascii', 'ignore')
132
        return self._add_ff_pad(label, 16)
133

  
134
    def _encode_charsetbits(self, mem):
135
        # TODO this is a setting to decide if the memory should be displayed
136
        # as a name or frequency. Should we expose this setting to the user
137
        # instead of autoselecting it (and losing their preference)?
138
        if mem.name.rstrip() == '':
139
            return [0x00, 0x00]
140
        return [0x00, 0x80]
141

  
142
    def _decode_power_level(self, mem):
143
        return POWER_LEVELS[mem.power - 1]
144

  
145
    def _encode_power_level(self, mem):
146
        return POWER_LEVELS.index(mem.power) + 1
147

  
148
    def _decode_mode(self, mem):
149
        return MODES[mem.mode_alt]
150

  
151
    def _encode_mode(self, mem):
152
        return MODES.index(mem.mode)
153

  
154
    def _get_tmode(self, mem, _mem):
155
        if _mem.tone_mode > 8:
156
            tmode = "Cross"
157
            mem.cross_mode = CROSS_MODES[_mem.tone_mode - 8]
158
        else:
159
            tmode = TMODES[_mem.tone_mode]
160

  
161
        if tmode == "Pager":
162
            # TODO chirp_common does not allow 'Pager'
163
            #   Expose as a different setting?
164
            mem.tmode = ""
165
        else:
166
            mem.tmode = tmode
167

  
168
    def _set_tmode(self, _mem, mem):
169
        if mem.tmode == "Cross":
170
            _mem.tone_mode = 8 + CROSS_MODES.index(mem.cross_mode)
171
        else:
172
            _mem.tone_mode = TMODES.index(mem.tmode)
173

  
174
    def _set_mode(self, _mem, mem):
175
        _mem.mode_alt = self._encode_mode(mem)
176

  
177
    def get_bank_model(self):
178
        return None
179

  
180
    def _debank(self, mem):
181
        return
182

  
183
    def _checksums(self):
184
        return [yaesu_clone.YaesuChecksum(0x064A, 0x06C8),
185
                yaesu_clone.YaesuChecksum(0x06CA, 0x0748),
186
                yaesu_clone.YaesuChecksum(0x074A, 0x07C8),
187
                yaesu_clone.YaesuChecksum(0x07CA, 0x0848),
188
                yaesu_clone.YaesuChecksum(0x0000, 0xFEC9)]
189

  
190
    def _get_settings(self):
191
        # TODO
192
        top = RadioSettings()
193
        return top
194

  
195
    @classmethod
196
    def _wipe_memory(cls, mem):
197
        mem.set_raw("\x00" * (mem.size() / 8))
198

  
199
    def sync_out(self):
200
        # Need to give enough time for the radio to ACK after writes
201
        self.pipe.timeout = 1
202
        return super(FTM7250Radio, self).sync_out()
(2-2/3)