Project

General

Profile

Bug #9515 » uv5x3_6VFOs.py

Jim Unroe, 11/05/2021 08:13 PM

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

    
17
import time
18
import struct
19
import logging
20
import re
21

    
22
from chirp.drivers import baofeng_common
23
from chirp import chirp_common, directory, memmap
24
from chirp import bitwise, errors, util
25
from chirp.settings import RadioSettingGroup, RadioSetting, \
26
    RadioSettingValueBoolean, RadioSettingValueList, \
27
    RadioSettingValueString, RadioSettingValueInteger, \
28
    RadioSettingValueFloat, RadioSettings, \
29
    InvalidValueError
30
from textwrap import dedent
31

    
32
LOG = logging.getLogger(__name__)
33

    
34
# #### MAGICS #########################################################
35

    
36
# BTECH UV-5X3 magic string
37
MSTRING_UV5X3 = "\x50\x0D\x0C\x20\x16\x03\x28"
38

    
39
# MTC UV-5R-3 magic string
40
MSTRING_UV5R3 = "\x50\x0D\x0C\x20\x17\x09\x19"
41

    
42
# #### ID strings #####################################################
43

    
44
# BTECH UV-5X3
45
UV5X3_fp1 = "UVVG302"  # BFB300 original
46
UV5X3_fp2 = "UVVG301"  # UVV300 original
47
UV5X3_fp3 = "UVVG306"  # UVV306 original
48

    
49
# MTC UV-5R-3
50
UV5R3_fp1 = "5R31709"
51

    
52
DTMF_CHARS = " 1234567890*#ABCD"
53
STEPS = [2.5, 5.0, 6.25, 10.0, 12.5, 20.0, 25.0, 50.0]
54

    
55
LIST_AB = ["A", "B"]
56
LIST_ALMOD = ["Site", "Tone", "Code"]
57
LIST_BANDWIDTH = ["Wide", "Narrow"]
58
LIST_COLOR = ["Off", "Blue", "Orange", "Purple"]
59
LIST_DELAYPROCTIME = ["%s ms" % x for x in range(100, 4100, 100)]
60
LIST_DTMFSPEED = ["%s ms" % x for x in range(50, 2010, 10)]
61
LIST_DTMFST = ["Off", "DT-ST", "ANI-ST", "DT+ANI"]
62
LIST_MODE = ["Channel", "Name", "Frequency"]
63
LIST_OFF1TO9 = ["Off"] + list("123456789")
64
LIST_OFF1TO10 = LIST_OFF1TO9 + ["10"]
65
LIST_OFFAB = ["Off"] + LIST_AB
66
LIST_RESETTIME = ["%s ms" % x for x in range(100, 16100, 100)]
67
LIST_RESUME = ["TO", "CO", "SE"]
68
LIST_PONMSG = ["Full", "Message"]
69
LIST_PTTID = ["Off", "BOT", "EOT", "Both"]
70
LIST_SCODE = ["%s" % x for x in range(1, 16)]
71
LIST_RPSTE = ["Off"] + ["%s" % x for x in range(1, 11)]
72
LIST_SAVE = ["Off", "1:1", "1:2", "1:3", "1:4"]
73
LIST_SHIFTD = ["Off", "+", "-"]
74
LIST_STEDELAY = ["Off"] + ["%s ms" % x for x in range(100, 1100, 100)]
75
LIST_STEP = [str(x) for x in STEPS]
76
LIST_TIMEOUT = ["%s sec" % x for x in range(15, 615, 15)]
77
LIST_TXPOWER = ["High", "Low"]
78
LIST_VOICE = ["Off", "English", "Chinese"]
79
LIST_WORKMODE = ["Frequency", "Channel"]
80
LIST_DTMF_SPECIAL_DIGITS = ["*", "#", "A", "B", "C", "D"]
81
LIST_DTMF_SPECIAL_VALUES = [0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00]
82

    
83

    
84
def model_match(cls, data):
85
    """Match the opened/downloaded image to the correct version"""
86
    match_rid1 = False
87
    match_rid2 = False
88

    
89
    rid1 = data[0x1EF0:0x1EF7]
90

    
91
    if rid1 in cls._fileid:
92
        match_rid1 = True
93

    
94
    if match_rid1:
95
        return True
96
    else:
97
        return False
98

    
99

    
100
@directory.register
101
class UV5X3(baofeng_common.BaofengCommonHT):
102
    """BTech UV-5X3"""
103
    VENDOR = "BTECH"
104
    MODEL = "UV-5X3"
105

    
106
    _fileid = [UV5X3_fp3,
107
               UV5X3_fp2,
108
               UV5X3_fp1]
109

    
110
    _magic = [MSTRING_UV5X3, ]
111
    _magic_response_length = 14
112
    _fw_ver_start = 0x1EF0
113
    _recv_block_size = 0x40
114
    _mem_size = 0x2000
115
    _ack_block = True
116

    
117
    _ranges = [(0x0000, 0x0DF0),
118
               (0x0E00, 0x1800),
119
               (0x1E00, 0x1E70),
120
               (0x1EE0, 0x1EF0),
121
               (0x1F60, 0x1F70),
122
               (0x1F80, 0x1F90),
123
               (0x1FA0, 0x1FB0),
124
               (0x1FE0, 0x2000)]
125
    _send_block_size = 0x10
126

    
127
    MODES = ["FM", "NFM"]
128
    VALID_CHARS = chirp_common.CHARSET_ALPHANUMERIC + \
129
        "!@#$%^&*()+-=[]:\";'<>?,./"
130
    LENGTH_NAME = 7
131
    SKIP_VALUES = ["", "S"]
132
    DTCS_CODES = sorted(chirp_common.DTCS_CODES + [645])
133
    POWER_LEVELS = [chirp_common.PowerLevel("High", watts=5.00),
134
                    chirp_common.PowerLevel("Low", watts=1.00)]
135
    VALID_BANDS = [(130000000, 180000000),
136
                   (220000000, 226000000),
137
                   (400000000, 521000000)]
138
    PTTID_LIST = LIST_PTTID
139
    SCODE_LIST = LIST_SCODE
140

    
141
    MEM_FORMAT = """
142
    #seekto 0x0000;
143
    struct {
144
      lbcd rxfreq[4];
145
      lbcd txfreq[4];
146
      ul16 rxtone;
147
      ul16 txtone;
148
      u8 unknown0:4,
149
         scode:4;
150
      u8 unknown1;
151
      u8 unknown2:7,
152
         lowpower:1;
153
      u8 unknown3:1,
154
         wide:1,
155
         unknown4:2,
156
         bcl:1,
157
         scan:1,
158
         pttid:2;
159
    } memory[128];
160

    
161
    #seekto 0x0B00;
162
    struct {
163
      u8 code[16];
164
    } pttid[15];
165

    
166
    #seekto 0x0C80;
167
    struct {
168
      u8 inspection[8];
169
      u8 monitor[8];
170
      u8 alarmcode[8];
171
      u8 stun[8];
172
      u8 kill[8];
173
      u8 revive[8];
174
      u8 code[7];
175
      u8 unknown06;
176
      u8 dtmfon;
177
      u8 dtmfoff;
178
      u8 unused00:6,
179
         aniid:2;
180
      u8 unknown07[5];
181
      u8 masterid[5];
182
      u8 unknown08[3];
183
      u8 viceid[5];
184
      u8 unknown09[3];
185
      u8 unused01:7,
186
         mastervice:1;
187
      u8 unused02:3,
188
         mrevive:1,
189
         mkill:1,
190
         mstun:1,
191
         mmonitor:1,
192
         minspection:1;
193
      u8 unused03:3,
194
         vrevive:1,
195
         vkill:1,
196
         vstun:1,
197
         vmonitor:1,
198
         vinspection:1;
199
      u8 unused04:6,
200
         txdisable:1,
201
         rxdisable:1;
202
      u8 groupcode;
203
      u8 spacecode;
204
      u8 delayproctime;
205
      u8 resettime;
206
    } ani;
207

    
208
    #seekto 0x0E20;
209
    struct {
210
      u8 unused00:4,
211
         squelch:4;
212
      u8 unused01:5,
213
         step:3;
214
      u8 unknown00;
215
      u8 unused02:5,
216
         save:3;
217
      u8 unused03:4,
218
         vox:4;
219
      u8 unknown01;
220
      u8 unused04:4,
221
         abr:4;
222
      u8 unused05:7,
223
         tdr:1;
224
      u8 unused06:7,
225
         beep:1;
226
      u8 unused07:2,
227
         timeout:6;
228
      u8 unknown02[4];
229
      u8 unused09:6,
230
         voice:2;
231
      u8 unknown03;
232
      u8 unused10:6,
233
         dtmfst:2;
234
      u8 unknown04;
235
      u8 unused11:6,
236
         screv:2;
237
      u8 unused12:6,
238
         pttid:2;
239
      u8 unused13:2,
240
         pttlt:6;
241
      u8 unused14:6,
242
         mdfa:2;
243
      u8 unused15:6,
244
         mdfb:2;
245
      u8 unknown05;
246
      u8 unused16:7,
247
         sync:1;
248
      u8 unknown06[4];
249
      u8 unused17:6,
250
         wtled:2;
251
      u8 unused18:6,
252
         rxled:2;
253
      u8 unused19:6,
254
         txled:2;
255
      u8 unused20:6,
256
         almod:2;
257
      u8 unknown07;
258
      u8 unused21:6,
259
         tdrab:2;
260
      u8 unused22:7,
261
         ste:1;
262
      u8 unused23:4,
263
         rpste:4;
264
      u8 unused24:4,
265
         rptrl:4;
266
      u8 unused25:7,
267
         ponmsg:1;
268
      u8 unused26:7,
269
         roger:1;
270
      u8 unused27:7,
271
         dani:1;
272
      u8 unused28:2,
273
         dtmfg:6;
274
      u8 unknown08:7,
275
         unknown09:1;
276
      u8 unknown10[3];
277
      u8 cht;
278
      u8 unknown11[13];
279
      u8 displayab:1,
280
         unknown12:2,
281
         fmradio:1,
282
         alarm:1,
283
         unknown13:1,
284
         reset:1,
285
         menu:1;
286
      u8 unknown14;
287
      u8 unused29:7,
288
         workmode:1;
289
      u8 unused30:7,
290
         keylock:1;
291
    } settings;
292

    
293
    #seekto 0x0E76;
294
    struct {
295
      u8 unused0:1,
296
         mrcha:7;
297
      u8 unused1:1,
298
         mrchb:7;
299
    } wmchannel;
300

    
301
    struct vfo {
302
      u8 unknown0[8];
303
      u8 freq[8];
304
      u8 offset[6];
305
      ul16 rxtone;
306
      ul16 txtone;
307
      u8 unused0:7,
308
         band:1;
309
      u8 unknown3;
310
      u8 unknown4:2,
311
         sftd:2,
312
         scode:4;
313
      u8 unknown5;
314
      u8 unknown6:1,
315
         step:3,
316
         unknown7:4;
317
      u8 txpower:1,
318
         widenarr:1,
319
         unknown8:6;
320
    };
321

    
322
    #seekto 0x0F00;
323
    struct {
324
      struct vfo a;
325
      struct vfo b;
326
    } vfo;
327

    
328
    #seekto 0x0F4E;
329
    u16 fm_presets;
330

    
331
    #seekto 0x1000;
332
    struct {
333
      char name[7];
334
      u8 unknown[9];
335
    } names[128];
336

    
337
    #seekto 0x1ED0;
338
    struct {
339
      char line1[7];
340
      char line2[7];
341
    } sixpoweron_msg;
342

    
343
    #seekto 0x1EF0;
344
    struct {
345
      char line1[7];
346
      char line2[7];
347
    } firmware_msg;
348

    
349
    struct squelch {
350
      u8 sql0;
351
      u8 sql1;
352
      u8 sql2;
353
      u8 sql3;
354
      u8 sql4;
355
      u8 sql5;
356
      u8 sql6;
357
      u8 sql7;
358
      u8 sql8;
359
      u8 sql9;
360
    };
361

    
362
    #seekto 0x1F60;
363
    struct {
364
      struct squelch vhf;
365
      u8 unknown0[6];
366
      u8 unknown1[16];
367
      struct squelch vhf2;
368
      u8 unknown2[6];
369
      u8 unknown3[16];
370
      struct squelch uhf;
371
    } squelch;
372

    
373
    #seekto 0x1FE0;
374
    struct {
375
      char line1[7];
376
      char line2[7];
377
    } poweron_msg;
378

    
379
    struct limit {
380
      u8 enable;
381
      bbcd lower[2];
382
      bbcd upper[2];
383
    };
384

    
385
    #seekto 0x1FF0;
386
    struct {
387
      struct limit vhf;
388
      struct limit vhf2;
389
      struct limit uhf;
390
    } limits;
391

    
392
    """
393

    
394
    @classmethod
395
    def get_prompts(cls):
396
        rp = chirp_common.RadioPrompts()
397
        rp.experimental = \
398
            ('Please save an unedited copy of your first successful\n'
399
             'download to a CHIRP Radio Images(*.img) file.'
400
             )
401
        rp.pre_download = _(dedent("""\
402
            Follow these instructions to download your info:
403

    
404
            1 - Turn off your radio
405
            2 - Connect your interface cable
406
            3 - Turn on your radio
407
            4 - Do the download of your radio data
408
            """))
409
        rp.pre_upload = _(dedent("""\
410
            Follow this instructions to upload your info:
411

    
412
            1 - Turn off your radio
413
            2 - Connect your interface cable
414
            3 - Turn on your radio
415
            4 - Do the upload of your radio data
416
            """))
417
        return rp
418

    
419
    def process_mmap(self):
420
        """Process the mem map into the mem object"""
421
        self._memobj = bitwise.parse(self.MEM_FORMAT, self._mmap)
422

    
423
    def get_settings(self):
424
        """Translate the bit in the mem_struct into settings in the UI"""
425
        _mem = self._memobj
426
        basic = RadioSettingGroup("basic", "Basic Settings")
427
        advanced = RadioSettingGroup("advanced", "Advanced Settings")
428
        other = RadioSettingGroup("other", "Other Settings")
429
        work = RadioSettingGroup("work", "Work Mode Settings")
430
        fm_preset = RadioSettingGroup("fm_preset", "FM Preset")
431
        dtmfe = RadioSettingGroup("dtmfe", "DTMF Encode Settings")
432
        dtmfd = RadioSettingGroup("dtmfd", "DTMF Decode Settings")
433
        service = RadioSettingGroup("service", "Service Settings")
434
        top = RadioSettings(basic, advanced, other, work, fm_preset, dtmfe,
435
                            dtmfd, service)
436

    
437
        # Basic settings
438
        if _mem.settings.squelch > 0x09:
439
            val = 0x00
440
        else:
441
            val = _mem.settings.squelch
442
        rs = RadioSetting("settings.squelch", "Squelch",
443
                          RadioSettingValueList(
444
                              LIST_OFF1TO9, LIST_OFF1TO9[val]))
445
        basic.append(rs)
446

    
447
        if _mem.settings.save > 0x04:
448
            val = 0x00
449
        else:
450
            val = _mem.settings.save
451
        rs = RadioSetting("settings.save", "Battery Saver",
452
                          RadioSettingValueList(
453
                              LIST_SAVE, LIST_SAVE[val]))
454
        basic.append(rs)
455

    
456
        if _mem.settings.vox > 0x0A:
457
            val = 0x00
458
        else:
459
            val = _mem.settings.vox
460
        rs = RadioSetting("settings.vox", "Vox",
461
                          RadioSettingValueList(
462
                              LIST_OFF1TO10, LIST_OFF1TO10[val]))
463
        basic.append(rs)
464

    
465
        if _mem.settings.abr > 0x0A:
466
            val = 0x00
467
        else:
468
            val = _mem.settings.abr
469
        rs = RadioSetting("settings.abr", "Backlight Timeout",
470
                          RadioSettingValueList(
471
                              LIST_OFF1TO10, LIST_OFF1TO10[val]))
472
        basic.append(rs)
473

    
474
        rs = RadioSetting("settings.tdr", "Dual Watch",
475
                          RadioSettingValueBoolean(_mem.settings.tdr))
476
        basic.append(rs)
477

    
478
        rs = RadioSetting("settings.beep", "Beep",
479
                          RadioSettingValueBoolean(_mem.settings.beep))
480
        basic.append(rs)
481

    
482
        if _mem.settings.timeout > 0x27:
483
            val = 0x03
484
        else:
485
            val = _mem.settings.timeout
486
        rs = RadioSetting("settings.timeout", "Timeout Timer",
487
                          RadioSettingValueList(
488
                              LIST_TIMEOUT, LIST_TIMEOUT[val]))
489
        basic.append(rs)
490

    
491
        if _mem.settings.voice > 0x02:
492
            val = 0x01
493
        else:
494
            val = _mem.settings.voice
495
        rs = RadioSetting("settings.voice", "Voice Prompt",
496
                          RadioSettingValueList(
497
                              LIST_VOICE, LIST_VOICE[val]))
498
        basic.append(rs)
499

    
500
        rs = RadioSetting("settings.dtmfst", "DTMF Sidetone",
501
                          RadioSettingValueList(LIST_DTMFST, LIST_DTMFST[
502
                              _mem.settings.dtmfst]))
503
        basic.append(rs)
504

    
505
        if _mem.settings.screv > 0x02:
506
            val = 0x01
507
        else:
508
            val = _mem.settings.screv
509
        rs = RadioSetting("settings.screv", "Scan Resume",
510
                          RadioSettingValueList(
511
                              LIST_RESUME, LIST_RESUME[val]))
512
        basic.append(rs)
513

    
514
        rs = RadioSetting("settings.pttid", "When to send PTT ID",
515
                          RadioSettingValueList(LIST_PTTID, LIST_PTTID[
516
                              _mem.settings.pttid]))
517
        basic.append(rs)
518

    
519
        if _mem.settings.pttlt > 0x1E:
520
            val = 0x05
521
        else:
522
            val = _mem.settings.pttlt
523
        rs = RadioSetting("pttlt", "PTT ID Delay",
524
                          RadioSettingValueInteger(0, 50, val))
525
        basic.append(rs)
526

    
527
        rs = RadioSetting("settings.mdfa", "Display Mode (A)",
528
                          RadioSettingValueList(LIST_MODE, LIST_MODE[
529
                              _mem.settings.mdfa]))
530
        basic.append(rs)
531

    
532
        rs = RadioSetting("settings.mdfb", "Display Mode (B)",
533
                          RadioSettingValueList(LIST_MODE, LIST_MODE[
534
                              _mem.settings.mdfb]))
535
        basic.append(rs)
536

    
537
        rs = RadioSetting("settings.sync", "Sync A & B",
538
                          RadioSettingValueBoolean(_mem.settings.sync))
539
        basic.append(rs)
540

    
541
        rs = RadioSetting("settings.wtled", "Standby LED Color",
542
                          RadioSettingValueList(
543
                              LIST_COLOR, LIST_COLOR[_mem.settings.wtled]))
544
        basic.append(rs)
545

    
546
        rs = RadioSetting("settings.rxled", "RX LED Color",
547
                          RadioSettingValueList(
548
                              LIST_COLOR, LIST_COLOR[_mem.settings.rxled]))
549
        basic.append(rs)
550

    
551
        rs = RadioSetting("settings.txled", "TX LED Color",
552
                          RadioSettingValueList(
553
                              LIST_COLOR, LIST_COLOR[_mem.settings.txled]))
554
        basic.append(rs)
555

    
556
        if _mem.settings.almod > 0x02:
557
            val = 0x00
558
        else:
559
            val = _mem.settings.almod
560
        rs = RadioSetting("settings.almod", "Alarm Mode",
561
                          RadioSettingValueList(
562
                              LIST_ALMOD, LIST_ALMOD[val]))
563
        basic.append(rs)
564

    
565
        if _mem.settings.tdrab > 0x02:
566
            val = 0x00
567
        else:
568
            val = _mem.settings.tdrab
569
        rs = RadioSetting("settings.tdrab", "Dual Watch TX Priority",
570
                          RadioSettingValueList(
571
                              LIST_OFFAB, LIST_OFFAB[val]))
572
        basic.append(rs)
573

    
574
        rs = RadioSetting("settings.ste", "Squelch Tail Eliminate (HT to HT)",
575
                          RadioSettingValueBoolean(_mem.settings.ste))
576
        basic.append(rs)
577

    
578
        if _mem.settings.rpste > 0x0A:
579
            val = 0x00
580
        else:
581
            val = _mem.settings.rpste
582
        rs = RadioSetting("settings.rpste",
583
                          "Squelch Tail Eliminate (repeater)",
584
                          RadioSettingValueList(
585
                              LIST_RPSTE, LIST_RPSTE[val]))
586
        basic.append(rs)
587

    
588
        if _mem.settings.rptrl > 0x0A:
589
            val = 0x00
590
        else:
591
            val = _mem.settings.rptrl
592
        rs = RadioSetting("settings.rptrl", "STE Repeater Delay",
593
                          RadioSettingValueList(
594
                              LIST_STEDELAY, LIST_STEDELAY[val]))
595
        basic.append(rs)
596

    
597
        rs = RadioSetting("settings.ponmsg", "Power-On Message",
598
                          RadioSettingValueList(LIST_PONMSG, LIST_PONMSG[
599
                              _mem.settings.ponmsg]))
600
        basic.append(rs)
601

    
602
        rs = RadioSetting("settings.roger", "Roger Beep",
603
                          RadioSettingValueBoolean(_mem.settings.roger))
604
        basic.append(rs)
605

    
606
        rs = RadioSetting("settings.dani", "Decode ANI",
607
                          RadioSettingValueBoolean(_mem.settings.dani))
608
        basic.append(rs)
609

    
610
        if _mem.settings.dtmfg > 0x3C:
611
            val = 0x14
612
        else:
613
            val = _mem.settings.dtmfg
614
        rs = RadioSetting("settings.dtmfg", "DTMF Gain",
615
                          RadioSettingValueInteger(0, 60, val))
616
        basic.append(rs)
617

    
618
        # Advanced settings
619
        rs = RadioSetting("settings.reset", "RESET Menu",
620
                          RadioSettingValueBoolean(_mem.settings.reset))
621
        advanced.append(rs)
622

    
623
        rs = RadioSetting("settings.menu", "All Menus",
624
                          RadioSettingValueBoolean(_mem.settings.menu))
625
        advanced.append(rs)
626

    
627
        rs = RadioSetting("settings.fmradio", "Broadcast FM Radio",
628
                          RadioSettingValueBoolean(_mem.settings.fmradio))
629
        advanced.append(rs)
630

    
631
        rs = RadioSetting("settings.alarm", "Alarm Sound",
632
                          RadioSettingValueBoolean(_mem.settings.alarm))
633
        advanced.append(rs)
634

    
635
        # Other settings
636
        def _filter(name):
637
            filtered = ""
638
            for char in str(name):
639
                if char in chirp_common.CHARSET_ASCII:
640
                    filtered += char
641
                else:
642
                    filtered += " "
643
            return filtered
644

    
645
        _msg = _mem.firmware_msg
646
        val = RadioSettingValueString(0, 7, _filter(_msg.line1))
647
        val.set_mutable(False)
648
        rs = RadioSetting("firmware_msg.line1", "Firmware Message 1", val)
649
        other.append(rs)
650

    
651
        val = RadioSettingValueString(0, 7, _filter(_msg.line2))
652
        val.set_mutable(False)
653
        rs = RadioSetting("firmware_msg.line2", "Firmware Message 2", val)
654
        other.append(rs)
655

    
656
        _msg = _mem.sixpoweron_msg
657
        val = RadioSettingValueString(0, 7, _filter(_msg.line1))
658
        val.set_mutable(False)
659
        rs = RadioSetting("sixpoweron_msg.line1", "6+Power-On Message 1", val)
660
        other.append(rs)
661
        val = RadioSettingValueString(0, 7, _filter(_msg.line2))
662
        val.set_mutable(False)
663
        rs = RadioSetting("sixpoweron_msg.line2", "6+Power-On Message 2", val)
664
        other.append(rs)
665

    
666
        _msg = _mem.poweron_msg
667
        rs = RadioSetting("poweron_msg.line1", "Power-On Message 1",
668
                          RadioSettingValueString(
669
                              0, 7, _filter(_msg.line1)))
670
        other.append(rs)
671
        rs = RadioSetting("poweron_msg.line2", "Power-On Message 2",
672
                          RadioSettingValueString(
673
                              0, 7, _filter(_msg.line2)))
674
        other.append(rs)
675

    
676
        if str(_mem.firmware_msg.line1) == ("UVVG302" or "5R31709"):
677
            lower = 136
678
            upper = 174
679
        else:
680
            lower = 130
681
            upper = 179
682
        if int(_mem.limits.vhf.lower) < lower:
683
            val = lower
684
        else:
685
            val = int(_mem.limits.vhf.lower)
686
        rs = RadioSetting("limits.vhf.lower", "VHF Lower Limit (MHz)",
687
                          RadioSettingValueInteger(lower, upper, val))
688
        other.append(rs)
689

    
690
        if int(_mem.limits.vhf.upper) > upper:
691
            val = upper
692
        else:
693
            val = int(_mem.limits.vhf.upper)
694
        rs = RadioSetting("limits.vhf.upper", "VHF Upper Limit (MHz)",
695
                          RadioSettingValueInteger(lower, upper, val))
696
        other.append(rs)
697

    
698
        if str(_mem.firmware_msg.line1) == "UVVG302":
699
            lower = 200
700
            upper = 230
701
        elif str(_mem.firmware_msg.line1) == "5R31709":
702
            lower = 200
703
            upper = 260
704
        else:
705
            lower = 220
706
            upper = 225
707
        if int(_mem.limits.vhf2.lower) < lower:
708
            val = lower
709
        else:
710
            val = int(_mem.limits.vhf2.lower)
711
        rs = RadioSetting("limits.vhf2.lower", "VHF2 Lower Limit (MHz)",
712
                          RadioSettingValueInteger(lower, upper, val))
713
        other.append(rs)
714

    
715
        if int(_mem.limits.vhf2.upper) > upper:
716
            val = upper
717
        else:
718
            val = int(_mem.limits.vhf2.upper)
719
        rs = RadioSetting("limits.vhf2.upper", "VHF2 Upper Limit (MHz)",
720
                          RadioSettingValueInteger(lower, upper, val))
721
        other.append(rs)
722

    
723
        if str(_mem.firmware_msg.line1) == "UVVG302":
724
            lower = 400
725
            upper = 480
726
        else:
727
            lower = 400
728
            upper = 520
729
        if int(_mem.limits.uhf.lower) < lower:
730
            val = lower
731
        else:
732
            val = int(_mem.limits.uhf.lower)
733
        rs = RadioSetting("limits.uhf.lower", "UHF Lower Limit (MHz)",
734
                          RadioSettingValueInteger(lower, upper, val))
735
        other.append(rs)
736

    
737
        if int(_mem.limits.uhf.upper) > upper:
738
            val = upper
739
        else:
740
            val = int(_mem.limits.uhf.upper)
741
        rs = RadioSetting("limits.uhf.upper", "UHF Upper Limit (MHz)",
742
                          RadioSettingValueInteger(lower, upper, val))
743
        other.append(rs)
744

    
745
        # Work mode settings
746
        rs = RadioSetting("settings.displayab", "Display",
747
                          RadioSettingValueList(
748
                              LIST_AB, LIST_AB[_mem.settings.displayab]))
749
        work.append(rs)
750

    
751
        rs = RadioSetting("settings.workmode", "VFO/MR Mode",
752
                          RadioSettingValueList(
753
                              LIST_WORKMODE,
754
                              LIST_WORKMODE[_mem.settings.workmode]))
755
        work.append(rs)
756

    
757
        rs = RadioSetting("settings.keylock", "Keypad Lock",
758
                          RadioSettingValueBoolean(_mem.settings.keylock))
759
        work.append(rs)
760

    
761
        rs = RadioSetting("wmchannel.mrcha", "MR A Channel",
762
                          RadioSettingValueInteger(0, 127,
763
                                                   _mem.wmchannel.mrcha))
764
        work.append(rs)
765

    
766
        rs = RadioSetting("wmchannel.mrchb", "MR B Channel",
767
                          RadioSettingValueInteger(0, 127,
768
                                                   _mem.wmchannel.mrchb))
769
        work.append(rs)
770

    
771
        def convert_bytes_to_freq(bytes):
772
            real_freq = 0
773
            for byte in bytes:
774
                real_freq = (real_freq * 10) + byte
775
            return chirp_common.format_freq(real_freq * 10)
776

    
777
        def my_validate(value):
778
            _vhf_lower = int(_mem.limits.vhf.lower)
779
            _vhf_upper = int(_mem.limits.vhf.upper)
780
            _vhf2_lower = int(_mem.limits.vhf2.lower)
781
            _vhf2_upper = int(_mem.limits.vhf2.upper)
782
            _uhf_lower = int(_mem.limits.uhf.lower)
783
            _uhf_upper = int(_mem.limits.uhf.upper)
784
            value = chirp_common.parse_freq(value)
785
            msg = ("Can't be less than %i.0000")
786
            if value > 99000000 and value < _vhf_lower * 1000000:
787
                raise InvalidValueError(msg % (_vhf_lower))
788
            msg = ("Can't be between %i.9975-%i.0000")
789
            if (_vhf_upper + 1) * 1000000 <= value and \
790
                    value < _vhf2_lower * 1000000:
791
                raise InvalidValueError(msg % (_vhf_upper, _vhf2_lower))
792
            if (_vhf2_upper + 1) * 1000000 <= value and \
793
                    value < _uhf_lower * 1000000:
794
                raise InvalidValueError(msg % (_vhf2_upper, _uhf_lower))
795
            msg = ("Can't be greater than %i.9975")
796
            if value > 99000000 and value >= (_uhf_upper + 1) * 1000000:
797
                raise InvalidValueError(msg % (_uhf_upper))
798
            return chirp_common.format_freq(value)
799

    
800
        def apply_freq(setting, obj):
801
            value = chirp_common.parse_freq(str(setting.value)) / 10
802
            for i in range(7, -1, -1):
803
                obj.freq[i] = value % 10
804
                value /= 10
805

    
806
        val1a = RadioSettingValueString(0, 10,
807
                                        convert_bytes_to_freq(_mem.vfo.a.freq))
808
        val1a.set_validate_callback(my_validate)
809
        rs = RadioSetting("vfo.a.freq", "VFO A Frequency", val1a)
810
        rs.set_apply_callback(apply_freq, _mem.vfo.a)
811
        work.append(rs)
812

    
813
        val1b = RadioSettingValueString(0, 10,
814
                                        convert_bytes_to_freq(_mem.vfo.b.freq))
815
        val1b.set_validate_callback(my_validate)
816
        rs = RadioSetting("vfo.b.freq", "VFO B Frequency", val1b)
817
        rs.set_apply_callback(apply_freq, _mem.vfo.b)
818
        work.append(rs)
819

    
820
        rs = RadioSetting("vfo.a.sftd", "VFO A Shift",
821
                          RadioSettingValueList(
822
                              LIST_SHIFTD, LIST_SHIFTD[_mem.vfo.a.sftd]))
823
        work.append(rs)
824

    
825
        rs = RadioSetting("vfo.b.sftd", "VFO B Shift",
826
                          RadioSettingValueList(
827
                              LIST_SHIFTD, LIST_SHIFTD[_mem.vfo.b.sftd]))
828
        work.append(rs)
829

    
830
        def convert_bytes_to_offset(bytes):
831
            real_offset = 0
832
            for byte in bytes:
833
                real_offset = (real_offset * 10) + byte
834
            return chirp_common.format_freq(real_offset * 1000)
835

    
836
        def apply_offset(setting, obj):
837
            value = chirp_common.parse_freq(str(setting.value)) / 1000
838
            for i in range(5, -1, -1):
839
                obj.offset[i] = value % 10
840
                value /= 10
841

    
842
        val1a = RadioSettingValueString(
843
                    0, 10, convert_bytes_to_offset(_mem.vfo.a.offset))
844
        rs = RadioSetting("vfo.a.offset",
845
                          "VFO A Offset", val1a)
846
        rs.set_apply_callback(apply_offset, _mem.vfo.a)
847
        work.append(rs)
848

    
849
        val1b = RadioSettingValueString(
850
                    0, 10, convert_bytes_to_offset(_mem.vfo.b.offset))
851
        rs = RadioSetting("vfo.b.offset",
852
                          "VFO B Offset", val1b)
853
        rs.set_apply_callback(apply_offset, _mem.vfo.b)
854
        work.append(rs)
855

    
856
        rs = RadioSetting("vfo.a.txpower", "VFO A Power",
857
                          RadioSettingValueList(
858
                              LIST_TXPOWER,
859
                              LIST_TXPOWER[_mem.vfo.a.txpower]))
860
        work.append(rs)
861

    
862
        rs = RadioSetting("vfo.b.txpower", "VFO B Power",
863
                          RadioSettingValueList(
864
                              LIST_TXPOWER,
865
                              LIST_TXPOWER[_mem.vfo.b.txpower]))
866
        work.append(rs)
867

    
868
        rs = RadioSetting("vfo.a.widenarr", "VFO A Bandwidth",
869
                          RadioSettingValueList(
870
                              LIST_BANDWIDTH,
871
                              LIST_BANDWIDTH[_mem.vfo.a.widenarr]))
872
        work.append(rs)
873

    
874
        rs = RadioSetting("vfo.b.widenarr", "VFO B Bandwidth",
875
                          RadioSettingValueList(
876
                              LIST_BANDWIDTH,
877
                              LIST_BANDWIDTH[_mem.vfo.b.widenarr]))
878
        work.append(rs)
879

    
880
        rs = RadioSetting("vfo.a.scode", "VFO A S-CODE",
881
                          RadioSettingValueList(
882
                              LIST_SCODE,
883
                              LIST_SCODE[_mem.vfo.a.scode]))
884
        work.append(rs)
885

    
886
        rs = RadioSetting("vfo.b.scode", "VFO B S-CODE",
887
                          RadioSettingValueList(
888
                              LIST_SCODE,
889
                              LIST_SCODE[_mem.vfo.b.scode]))
890
        work.append(rs)
891

    
892
        rs = RadioSetting("vfo.a.step", "VFO A Tuning Step",
893
                          RadioSettingValueList(
894
                              LIST_STEP, LIST_STEP[_mem.vfo.a.step]))
895
        work.append(rs)
896
        rs = RadioSetting("vfo.b.step", "VFO B Tuning Step",
897
                          RadioSettingValueList(
898
                              LIST_STEP, LIST_STEP[_mem.vfo.b.step]))
899
        work.append(rs)
900

    
901
        # broadcast FM settings
902
        _fm_presets = self._memobj.fm_presets
903
        if _fm_presets <= 108.0 * 10 - 650:
904
            preset = _fm_presets / 10.0 + 65
905
        elif _fm_presets >= 65.0 * 10 and _fm_presets <= 108.0 * 10:
906
            preset = _fm_presets / 10.0
907
        else:
908
            preset = 76.0
909
        rs = RadioSetting("fm_presets", "FM Preset(MHz)",
910
                          RadioSettingValueFloat(65, 108.0, preset, 0.1, 1))
911
        fm_preset.append(rs)
912

    
913
        # DTMF encode settings
914
        for i in range(0, 15):
915
            _codeobj = self._memobj.pttid[i].code
916
            _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
917
            val = RadioSettingValueString(0, 16, _code, False)
918
            val.set_charset(DTMF_CHARS)
919
            rs = RadioSetting("pttid/%i.code" % i,
920
                              "Signal Code %i" % (i + 1), val)
921

    
922
            def apply_code(setting, obj):
923
                code = []
924
                for j in range(0, 16):
925
                    try:
926
                        code.append(DTMF_CHARS.index(str(setting.value)[j]))
927
                    except IndexError:
928
                        code.append(0xFF)
929
                obj.code = code
930
            rs.set_apply_callback(apply_code, self._memobj.pttid[i])
931
            dtmfe.append(rs)
932

    
933
        if _mem.ani.dtmfon > 0xC3:
934
            val = 0x03
935
        else:
936
            val = _mem.ani.dtmfon
937
        rs = RadioSetting("ani.dtmfon", "DTMF Speed (on)",
938
                          RadioSettingValueList(LIST_DTMFSPEED,
939
                                                LIST_DTMFSPEED[val]))
940
        dtmfe.append(rs)
941

    
942
        if _mem.ani.dtmfoff > 0xC3:
943
            val = 0x03
944
        else:
945
            val = _mem.ani.dtmfoff
946
        rs = RadioSetting("ani.dtmfoff", "DTMF Speed (off)",
947
                          RadioSettingValueList(LIST_DTMFSPEED,
948
                                                LIST_DTMFSPEED[val]))
949
        dtmfe.append(rs)
950

    
951
        _codeobj = self._memobj.ani.code
952
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
953
        val = RadioSettingValueString(0, 7, _code, False)
954
        val.set_charset(DTMF_CHARS)
955
        rs = RadioSetting("ani.code", "ANI Code", val)
956

    
957
        def apply_code(setting, obj):
958
            code = []
959
            for j in range(0, 7):
960
                try:
961
                    code.append(DTMF_CHARS.index(str(setting.value)[j]))
962
                except IndexError:
963
                    code.append(0xFF)
964
            obj.code = code
965
        rs.set_apply_callback(apply_code, self._memobj.ani)
966
        dtmfe.append(rs)
967

    
968
        rs = RadioSetting("ani.aniid", "When to send ANI ID",
969
                          RadioSettingValueList(LIST_PTTID,
970
                                                LIST_PTTID[_mem.ani.aniid]))
971
        dtmfe.append(rs)
972

    
973
        # DTMF decode settings
974
        rs = RadioSetting("ani.mastervice", "Master and Vice ID",
975
                          RadioSettingValueBoolean(_mem.ani.mastervice))
976
        dtmfd.append(rs)
977

    
978
        _codeobj = _mem.ani.masterid
979
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
980
        val = RadioSettingValueString(0, 5, _code, False)
981
        val.set_charset(DTMF_CHARS)
982
        rs = RadioSetting("ani.masterid", "Master Control ID", val)
983

    
984
        def apply_code(setting, obj):
985
            code = []
986
            for j in range(0, 5):
987
                try:
988
                    code.append(DTMF_CHARS.index(str(setting.value)[j]))
989
                except IndexError:
990
                    code.append(0xFF)
991
            obj.masterid = code
992
        rs.set_apply_callback(apply_code, self._memobj.ani)
993
        dtmfd.append(rs)
994

    
995
        rs = RadioSetting("ani.minspection", "Master Inspection",
996
                          RadioSettingValueBoolean(_mem.ani.minspection))
997
        dtmfd.append(rs)
998

    
999
        rs = RadioSetting("ani.mmonitor", "Master Monitor",
1000
                          RadioSettingValueBoolean(_mem.ani.mmonitor))
1001
        dtmfd.append(rs)
1002

    
1003
        rs = RadioSetting("ani.mstun", "Master Stun",
1004
                          RadioSettingValueBoolean(_mem.ani.mstun))
1005
        dtmfd.append(rs)
1006

    
1007
        rs = RadioSetting("ani.mkill", "Master Kill",
1008
                          RadioSettingValueBoolean(_mem.ani.mkill))
1009
        dtmfd.append(rs)
1010

    
1011
        rs = RadioSetting("ani.mrevive", "Master Revive",
1012
                          RadioSettingValueBoolean(_mem.ani.mrevive))
1013
        dtmfd.append(rs)
1014

    
1015
        _codeobj = _mem.ani.viceid
1016
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
1017
        val = RadioSettingValueString(0, 5, _code, False)
1018
        val.set_charset(DTMF_CHARS)
1019
        rs = RadioSetting("ani.viceid", "Vice Control ID", val)
1020

    
1021
        def apply_code(setting, obj):
1022
            code = []
1023
            for j in range(0, 5):
1024
                try:
1025
                    code.append(DTMF_CHARS.index(str(setting.value)[j]))
1026
                except IndexError:
1027
                    code.append(0xFF)
1028
            obj.viceid = code
1029
        rs.set_apply_callback(apply_code, self._memobj.ani)
1030
        dtmfd.append(rs)
1031

    
1032
        rs = RadioSetting("ani.vinspection", "Vice Inspection",
1033
                          RadioSettingValueBoolean(_mem.ani.vinspection))
1034
        dtmfd.append(rs)
1035

    
1036
        rs = RadioSetting("ani.vmonitor", "Vice Monitor",
1037
                          RadioSettingValueBoolean(_mem.ani.vmonitor))
1038
        dtmfd.append(rs)
1039

    
1040
        rs = RadioSetting("ani.vstun", "Vice Stun",
1041
                          RadioSettingValueBoolean(_mem.ani.vstun))
1042
        dtmfd.append(rs)
1043

    
1044
        rs = RadioSetting("ani.vkill", "Vice Kill",
1045
                          RadioSettingValueBoolean(_mem.ani.vkill))
1046
        dtmfd.append(rs)
1047

    
1048
        rs = RadioSetting("ani.vrevive", "Vice Revive",
1049
                          RadioSettingValueBoolean(_mem.ani.vrevive))
1050
        dtmfd.append(rs)
1051

    
1052
        _codeobj = _mem.ani.inspection
1053
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
1054
        val = RadioSettingValueString(0, 8, _code, False)
1055
        val.set_charset(DTMF_CHARS)
1056
        rs = RadioSetting("ani.inspection", "Inspection Code", val)
1057

    
1058
        def apply_code(setting, obj):
1059
            code = []
1060
            for j in range(0, 8):
1061
                try:
1062
                    code.append(DTMF_CHARS.index(str(setting.value)[j]))
1063
                except IndexError:
1064
                    code.append(0xFF)
1065
            obj.inspection = code
1066
        rs.set_apply_callback(apply_code, self._memobj.ani)
1067
        dtmfd.append(rs)
1068

    
1069
        _codeobj = _mem.ani.monitor
1070
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
1071
        val = RadioSettingValueString(0, 8, _code, False)
1072
        val.set_charset(DTMF_CHARS)
1073
        rs = RadioSetting("ani.monitor", "Monitor Code", val)
1074

    
1075
        def apply_code(setting, obj):
1076
            code = []
1077
            for j in range(0, 8):
1078
                try:
1079
                    code.append(DTMF_CHARS.index(str(setting.value)[j]))
1080
                except IndexError:
1081
                    code.append(0xFF)
1082
            obj.monitor = code
1083
        rs.set_apply_callback(apply_code, self._memobj.ani)
1084
        dtmfd.append(rs)
1085

    
1086
        _codeobj = _mem.ani.alarmcode
1087
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
1088
        val = RadioSettingValueString(0, 8, _code, False)
1089
        val.set_charset(DTMF_CHARS)
1090
        rs = RadioSetting("ani.alarm", "Alarm Code", val)
1091

    
1092
        def apply_code(setting, obj):
1093
            code = []
1094
            for j in range(0, 8):
1095
                try:
1096
                    code.append(DTMF_CHARS.index(str(setting.value)[j]))
1097
                except IndexError:
1098
                    code.append(0xFF)
1099
            obj.alarmcode = code
1100
        rs.set_apply_callback(apply_code, self._memobj.ani)
1101
        dtmfd.append(rs)
1102

    
1103
        _codeobj = _mem.ani.stun
1104
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
1105
        val = RadioSettingValueString(0, 8, _code, False)
1106
        val.set_charset(DTMF_CHARS)
1107
        rs = RadioSetting("ani.stun", "Stun Code", val)
1108

    
1109
        def apply_code(setting, obj):
1110
            code = []
1111
            for j in range(0, 8):
1112
                try:
1113
                    code.append(DTMF_CHARS.index(str(setting.value)[j]))
1114
                except IndexError:
1115
                    code.append(0xFF)
1116
            obj.stun = code
1117
        rs.set_apply_callback(apply_code, self._memobj.ani)
1118
        dtmfd.append(rs)
1119

    
1120
        _codeobj = _mem.ani.kill
1121
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
1122
        val = RadioSettingValueString(0, 8, _code, False)
1123
        val.set_charset(DTMF_CHARS)
1124
        rs = RadioSetting("ani.kill", "Kill Code", val)
1125

    
1126
        def apply_code(setting, obj):
1127
            code = []
1128
            for j in range(0, 8):
1129
                try:
1130
                    code.append(DTMF_CHARS.index(str(setting.value)[j]))
1131
                except IndexError:
1132
                    code.append(0xFF)
1133
            obj.kill = code
1134
        rs.set_apply_callback(apply_code, self._memobj.ani)
1135
        dtmfd.append(rs)
1136

    
1137
        _codeobj = _mem.ani.revive
1138
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
1139
        val = RadioSettingValueString(0, 8, _code, False)
1140
        val.set_charset(DTMF_CHARS)
1141
        rs = RadioSetting("ani.revive", "Revive Code", val)
1142

    
1143
        def apply_code(setting, obj):
1144
            code = []
1145
            for j in range(0, 8):
1146
                try:
1147
                    code.append(DTMF_CHARS.index(str(setting.value)[j]))
1148
                except IndexError:
1149
                    code.append(0xFF)
1150
            obj.revive = code
1151
        rs.set_apply_callback(apply_code, self._memobj.ani)
1152
        dtmfd.append(rs)
1153

    
1154
        def apply_dmtf_listvalue(setting, obj):
1155
            LOG.debug("Setting value: " + str(setting.value) + " from list")
1156
            val = str(setting.value)
1157
            index = LIST_DTMF_SPECIAL_DIGITS.index(val)
1158
            val = LIST_DTMF_SPECIAL_VALUES[index]
1159
            obj.set_value(val)
1160

    
1161
        if _mem.ani.groupcode in LIST_DTMF_SPECIAL_VALUES:
1162
            idx = LIST_DTMF_SPECIAL_VALUES.index(_mem.ani.groupcode)
1163
        else:
1164
            idx = LIST_DTMF_SPECIAL_VALUES.index(0x0B)
1165
        rs = RadioSetting("ani.groupcode", "Group Code",
1166
                          RadioSettingValueList(LIST_DTMF_SPECIAL_DIGITS,
1167
                                                LIST_DTMF_SPECIAL_DIGITS[idx]))
1168
        rs.set_apply_callback(apply_dmtf_listvalue, _mem.ani.groupcode)
1169
        dtmfd.append(rs)
1170

    
1171
        if _mem.ani.spacecode in LIST_DTMF_SPECIAL_VALUES:
1172
            idx = LIST_DTMF_SPECIAL_VALUES.index(_mem.ani.spacecode)
1173
        else:
1174
            idx = LIST_DTMF_SPECIAL_VALUES.index(0x0C)
1175
        rs = RadioSetting("ani.spacecode", "Space Code",
1176
                          RadioSettingValueList(LIST_DTMF_SPECIAL_DIGITS,
1177
                                                LIST_DTMF_SPECIAL_DIGITS[idx]))
1178
        rs.set_apply_callback(apply_dmtf_listvalue, _mem.ani.spacecode)
1179
        dtmfd.append(rs)
1180

    
1181
        if _mem.ani.resettime > 0x9F:
1182
            val = 0x4F
1183
        else:
1184
            val = _mem.ani.resettime
1185
        rs = RadioSetting("ani.resettime", "Reset Time",
1186
                          RadioSettingValueList(LIST_RESETTIME,
1187
                                                LIST_RESETTIME[val]))
1188
        dtmfd.append(rs)
1189

    
1190
        if _mem.ani.delayproctime > 0x27:
1191
            val = 0x04
1192
        else:
1193
            val = _mem.ani.delayproctime
1194
        rs = RadioSetting("ani.delayproctime", "Delay Processing Time",
1195
                          RadioSettingValueList(LIST_DELAYPROCTIME,
1196
                                                LIST_DELAYPROCTIME[val]))
1197
        dtmfd.append(rs)
1198

    
1199
        # Service settings
1200
        for band in ["vhf", "vhf2", "uhf"]:
1201
            for index in range(0, 10):
1202
                key = "squelch.%s.sql%i" % (band, index)
1203
                if band == "vhf":
1204
                    _obj = self._memobj.squelch.vhf
1205
                    _name = "VHF"
1206
                elif band == "vhf2":
1207
                    _obj = self._memobj.squelch.vhf2
1208
                    _name = "220"
1209
                elif band == "uhf":
1210
                    _obj = self._memobj.squelch.uhf
1211
                    _name = "UHF"
1212
                val = RadioSettingValueInteger(0, 123,
1213
                                               getattr(_obj, "sql%i" % (
1214
                                                       index)))
1215
                if index == 0:
1216
                    val.set_mutable(False)
1217
                name = "%s Squelch %i" % (_name, index)
1218
                rs = RadioSetting(key, name, val)
1219
                service.append(rs)
1220

    
1221
        return top
1222

    
1223
    @classmethod
1224
    def match_model(cls, filedata, filename):
1225
        match_size = False
1226
        match_model = False
1227

    
1228
        # testing the file data size
1229
        if len(filedata) == 0x200E:
1230
            match_size = True
1231

    
1232
        # testing the firmware model fingerprint
1233
        match_model = model_match(cls, filedata)
1234

    
1235
        if match_size and match_model:
1236
            return True
1237
        else:
1238
            return False
1239

    
1240

    
1241
@directory.register
1242
class MTCUV5R3Radio(UV5X3):
1243
    VENDOR = "MTC"
1244
    MODEL = "UV-5R-3"
1245

    
1246
    _fileid = [UV5R3_fp1, ]
1247

    
1248
    _magic = [MSTRING_UV5R3, ]
1249

    
1250
    VALID_BANDS = [(136000000, 174000000),
1251
                   (200000000, 260000000),
1252
                   (400000000, 521000000)]
(1-1/6)