Project

General

Profile

Bug #5333 ยป uv5x3(vhf-220-uhf_squelch).py

Jim Unroe, 11/11/2017 04:31 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
LOG = logging.getLogger(__name__)
23

    
24
from chirp.drivers import baofeng_common
25
from chirp import chirp_common, directory, memmap
26
from chirp import bitwise, errors, util
27
from chirp.settings import RadioSettingGroup, RadioSetting, \
28
    RadioSettingValueBoolean, RadioSettingValueList, \
29
    RadioSettingValueString, RadioSettingValueInteger, \
30
    RadioSettingValueFloat, RadioSettings, \
31
    InvalidValueError
32
from textwrap import dedent
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
def model_match(cls, data):
84
    """Match the opened/downloaded image to the correct version"""
85
    match_rid1 = False
86
    match_rid2 = False
87

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

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

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

    
98

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

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

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

    
116
    _ranges = [(0x0000, 0x0DF0),
117
               (0x0E00, 0x1800),
118
               (0x1EE0, 0x1EF0),
119
               (0x1F60, 0x1F90),
120
               (0x1FA0, 0x1FB0),
121
               (0x1FE0, 0x2000)]
122
    _send_block_size = 0x10
123

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

    
138

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

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

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

    
206
    #seekto 0x0E20;
207
    struct {
208
      u8 unused00:4,
209
         squelch:4;
210
      u8 unused01:5,     
211
         step:3;
212
      u8 unknown00;      
213
      u8 unused02:5,
214
         save:3;
215
      u8 unused03:4,
216
         vox:4;
217
      u8 unknown01;      
218
      u8 unused04:4,     
219
         abr:4;
220
      u8 unused05:7,     
221
         tdr:1;
222
      u8 unused06:7,     
223
         beep:1;
224
      u8 unused07:2,     
225
         timeout:6;
226
      u8 unknown02[4];
227
      u8 unused09:6,
228
         voice:2;
229
      u8 unknown03;      
230
      u8 unused10:6,
231
         dtmfst:2;
232
      u8 unknown04;
233
      u8 unused11:6,
234
         screv:2;
235
      u8 unused12:6,
236
         pttid:2;
237
      u8 unused13:2,
238
         pttlt:6;
239
      u8 unused14:6,
240
         mdfa:2;
241
      u8 unused15:6,
242
         mdfb:2;
243
      u8 unknown05;
244
      u8 unused16:7,
245
         sync:1;
246
      u8 unknown06[4];
247
      u8 unused17:6,
248
         wtled:2;
249
      u8 unused18:6,
250
         rxled:2;
251
      u8 unused19:6,
252
         txled:2;
253
      u8 unused20:6,
254
         almod:2;
255
      u8 unknown07;
256
      u8 unused21:6,
257
         tdrab:2;
258
      u8 unused22:7,
259
         ste:1;
260
      u8 unused23:4,
261
         rpste:4;
262
      u8 unused24:4,
263
         rptrl:4;
264
      u8 unused25:7,
265
         ponmsg:1;
266
      u8 unused26:7,
267
         roger:1;
268
      u8 unused27:7,
269
         dani:1;
270
      u8 unused28:2,
271
         dtmfg:6;
272
      u8 unknown08:6,    
273
         reset:1,
274
         unknown09:1;
275
      u8 unknown10[3];   
276
      u8 cht;            
277
      u8 unknown11[13];  
278
      u8 displayab:1,
279
         unknown12:2,
280
         fmradio:1,
281
         alarm:1,
282
         unknown13:2,
283
         menu:1;
284
      u8 unknown14;      
285
      u8 unused29:7,
286
         workmode:1;
287
      u8 unused30:7,
288
         keylock:1;
289
    } settings;
290
    
291
    #seekto 0x0E76;
292
    struct {
293
      u8 unused0:1,
294
         mrcha:7;
295
      u8 unused1:1,
296
         mrchb:7;
297
    } wmchannel;
298
    
299
    struct vfo {
300
      u8 unknown0[8];
301
      u8 freq[8];
302
      u8 offset[6];
303
      ul16 rxtone;
304
      ul16 txtone;
305
      u8 unused0:7,
306
         band:1;
307
      u8 unknown3;
308
      u8 unknown4:2,
309
         sftd:2,
310
         scode:4;
311
      u8 unknown5;
312
      u8 unknown6:1,
313
         step:3,
314
         unknown7:4;
315
      u8 txpower:1,
316
         widenarr:1,
317
         unknown8:6;
318
    };
319
    
320
    #seekto 0x0F00;
321
    struct {
322
      struct vfo a;
323
      struct vfo b;
324
    } vfo;
325
    
326
    #seekto 0x0F4E;
327
    u16 fm_presets;
328

    
329
    #seekto 0x1000;
330
    struct {
331
      char name[7];
332
      u8 unknown[9];
333
    } names[128];
334
    
335
    #seekto 0x1ED0;
336
    struct {
337
      char line1[7];
338
      char line2[7];
339
    } sixpoweron_msg;
340
    
341
    #seekto 0x1EF0;
342
    struct {
343
      char line1[7];
344
      char line2[7];
345
    } firmware_msg;
346
    
347
    struct squelch {
348
      u8 sql0;
349
      u8 sql1;
350
      u8 sql2;
351
      u8 sql3;
352
      u8 sql4;
353
      u8 sql5;
354
      u8 sql6;
355
      u8 sql7;
356
      u8 sql8;
357
      u8 sql9;
358
    };
359
    
360
    #seekto 0x1F60;
361
    struct {
362
      struct squelch vhf;
363
      u8 unknown0[6];
364
      u8 unknown1[16];
365
      struct squelch vhf2;
366
      u8 unknown2[6];
367
      u8 unknown3[16];
368
      struct squelch uhf;
369
    } squelch;
370

    
371
    #seekto 0x1FE0;
372
    struct {
373
      char line1[7];
374
      char line2[7];
375
    } poweron_msg;
376
    
377
    struct limit {
378
      u8 enable;
379
      bbcd lower[2];
380
      bbcd upper[2];
381
    };
382

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

    
390
    """
391

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
685
        rs = RadioSetting("limits.vhf.upper", "VHF Upper Limit (MHz)",
686
                          RadioSettingValueInteger(
687
                              lower, upper, _mem.limits.vhf.upper))
688
        other.append(rs)
689

    
690
        if str(_mem.firmware_msg.line1) == "UVVG302":
691
            lower = 200
692
            upper = 230
693
        elif str(_mem.firmware_msg.line1) == "5R31709":
694
            lower = 200
695
            upper = 260
696
        else:
697
            lower = 220
698
            upper = 225
699
        rs = RadioSetting("limits.vhf2.lower", "VHF2 Lower Limit (MHz)",
700
                          RadioSettingValueInteger(
701
                              lower, upper, _mem.limits.vhf2.lower))
702
        other.append(rs)
703

    
704
        rs = RadioSetting("limits.vhf2.upper", "VHF2 Upper Limit (MHz)",
705
                          RadioSettingValueInteger(
706
                              lower, upper, _mem.limits.vhf2.upper))
707
        other.append(rs)
708

    
709
        if str(_mem.firmware_msg.line1) == "UVVG302":
710
            lower = 400
711
            upper = 480
712
        else:
713
            lower = 400
714
            upper = 520
715
        rs = RadioSetting("limits.uhf.lower", "UHF Lower Limit (MHz)",
716
                          RadioSettingValueInteger(
717
                              lower, upper, _mem.limits.uhf.lower))
718
        other.append(rs)
719

    
720
        rs = RadioSetting("limits.uhf.upper", "UHF Upper Limit (MHz)",
721
                          RadioSettingValueInteger(
722
                              lower, upper, _mem.limits.uhf.upper))
723
        other.append(rs)
724

    
725
        # Work mode settings
726
        rs = RadioSetting("settings.displayab", "Display",
727
                          RadioSettingValueList(
728
                              LIST_AB, LIST_AB[_mem.settings.displayab]))
729
        work.append(rs)
730

    
731
        rs = RadioSetting("settings.workmode", "VFO/MR Mode",
732
                          RadioSettingValueList(
733
                              LIST_WORKMODE,
734
                              LIST_WORKMODE[_mem.settings.workmode]))
735
        work.append(rs)
736

    
737
        rs = RadioSetting("settings.keylock", "Keypad Lock",
738
                          RadioSettingValueBoolean(_mem.settings.keylock))
739
        work.append(rs)
740

    
741
        rs = RadioSetting("wmchannel.mrcha", "MR A Channel",
742
                          RadioSettingValueInteger(0, 127,
743
                                                      _mem.wmchannel.mrcha))
744
        work.append(rs)
745

    
746
        rs = RadioSetting("wmchannel.mrchb", "MR B Channel",
747
                          RadioSettingValueInteger(0, 127,
748
                                                      _mem.wmchannel.mrchb))
749
        work.append(rs)
750

    
751
        def convert_bytes_to_freq(bytes):
752
            real_freq = 0
753
            for byte in bytes:
754
                real_freq = (real_freq * 10) + byte
755
            return chirp_common.format_freq(real_freq * 10)
756

    
757
        def my_validate(value):
758
            _vhf_lower = int(_mem.limits.vhf.lower)
759
            _vhf_upper = int(_mem.limits.vhf.upper)
760
            _vhf2_lower = int(_mem.limits.vhf2.lower)
761
            _vhf2_upper = int(_mem.limits.vhf2.upper)
762
            _uhf_lower = int(_mem.limits.uhf.lower)
763
            _uhf_upper = int(_mem.limits.uhf.upper)
764
            value = chirp_common.parse_freq(value)
765
            msg = ("Can't be less than %i.0000")
766
            if value > 99000000 and value < _vhf_lower * 1000000:
767
                raise InvalidValueError(msg % (_vhf_lower))
768
            msg = ("Can't be between %i.9975-%i.0000")
769
            if (_vhf_upper + 1) * 1000000 <= value and \
770
                value < _vhf2_lower * 1000000:
771
                raise InvalidValueError(msg % (_vhf_upper, _vhf2_lower))
772
            if (_vhf2_upper + 1) * 1000000 <= value and \
773
                value < _uhf_lower * 1000000:
774
                raise InvalidValueError(msg % (_vhf2_upper, _uhf_lower))
775
            msg = ("Can't be greater than %i.9975")
776
            if value > 99000000 and value >= (_uhf_upper + 1) * 1000000:
777
                raise InvalidValueError(msg % (_uhf_upper))
778
            return chirp_common.format_freq(value)
779

    
780
        def apply_freq(setting, obj):
781
            value = chirp_common.parse_freq(str(setting.value)) / 10
782
            for i in range(7, -1, -1):
783
                obj.freq[i] = value % 10
784
                value /= 10
785

    
786
        val1a = RadioSettingValueString(0, 10,
787
                                        convert_bytes_to_freq(_mem.vfo.a.freq))
788
        val1a.set_validate_callback(my_validate)
789
        rs = RadioSetting("vfo.a.freq", "VFO A Frequency", val1a)
790
        rs.set_apply_callback(apply_freq, _mem.vfo.a)
791
        work.append(rs)
792

    
793
        val1b = RadioSettingValueString(0, 10,
794
                                        convert_bytes_to_freq(_mem.vfo.b.freq))
795
        val1b.set_validate_callback(my_validate)
796
        rs = RadioSetting("vfo.b.freq", "VFO B Frequency", val1b)
797
        rs.set_apply_callback(apply_freq, _mem.vfo.b)
798
        work.append(rs)
799

    
800
        rs = RadioSetting("vfo.a.sftd", "VFO A Shift",
801
                          RadioSettingValueList(
802
                              LIST_SHIFTD, LIST_SHIFTD[_mem.vfo.a.sftd]))
803
        work.append(rs)
804

    
805
        rs = RadioSetting("vfo.b.sftd", "VFO B Shift",
806
                          RadioSettingValueList(
807
                              LIST_SHIFTD, LIST_SHIFTD[_mem.vfo.b.sftd]))
808
        work.append(rs)
809

    
810
        def convert_bytes_to_offset(bytes):
811
            real_offset = 0
812
            for byte in bytes:
813
                real_offset = (real_offset * 10) + byte
814
            return chirp_common.format_freq(real_offset * 1000)
815

    
816
        def apply_offset(setting, obj):
817
            value = chirp_common.parse_freq(str(setting.value)) / 1000
818
            for i in range(5, -1, -1):
819
                obj.offset[i] = value % 10
820
                value /= 10
821

    
822
        val1a = RadioSettingValueString(
823
                    0, 10, convert_bytes_to_offset(_mem.vfo.a.offset))
824
        rs = RadioSetting("vfo.a.offset",
825
                          "VFO A Offset", val1a)
826
        rs.set_apply_callback(apply_offset, _mem.vfo.a)
827
        work.append(rs)
828

    
829
        val1b = RadioSettingValueString(
830
                    0, 10, convert_bytes_to_offset(_mem.vfo.b.offset))
831
        rs = RadioSetting("vfo.b.offset",
832
                          "VFO B Offset", val1b)
833
        rs.set_apply_callback(apply_offset, _mem.vfo.b)
834
        work.append(rs)
835

    
836
        rs = RadioSetting("vfo.a.txpower", "VFO A Power",
837
                          RadioSettingValueList(
838
                              LIST_TXPOWER,
839
                              LIST_TXPOWER[_mem.vfo.a.txpower]))
840
        work.append(rs)
841

    
842
        rs = RadioSetting("vfo.b.txpower", "VFO B Power",
843
                          RadioSettingValueList(
844
                              LIST_TXPOWER,
845
                              LIST_TXPOWER[_mem.vfo.b.txpower]))
846
        work.append(rs)
847

    
848
        rs = RadioSetting("vfo.a.widenarr", "VFO A Bandwidth",
849
                          RadioSettingValueList(
850
                              LIST_BANDWIDTH,
851
                              LIST_BANDWIDTH[_mem.vfo.a.widenarr]))
852
        work.append(rs)
853

    
854
        rs = RadioSetting("vfo.b.widenarr", "VFO B Bandwidth",
855
                          RadioSettingValueList(
856
                              LIST_BANDWIDTH,
857
                              LIST_BANDWIDTH[_mem.vfo.b.widenarr]))
858
        work.append(rs)
859

    
860
        rs = RadioSetting("vfo.a.scode", "VFO A S-CODE",
861
                          RadioSettingValueList(
862
                              LIST_SCODE,
863
                              LIST_SCODE[_mem.vfo.a.scode]))
864
        work.append(rs)
865

    
866
        rs = RadioSetting("vfo.b.scode", "VFO B S-CODE",
867
                          RadioSettingValueList(
868
                              LIST_SCODE,
869
                              LIST_SCODE[_mem.vfo.b.scode]))
870
        work.append(rs)
871

    
872
        rs = RadioSetting("vfo.a.step", "VFO A Tuning Step",
873
                          RadioSettingValueList(
874
                              LIST_STEP, LIST_STEP[_mem.vfo.a.step]))
875
        work.append(rs)
876
        rs = RadioSetting("vfo.b.step", "VFO B Tuning Step",
877
                          RadioSettingValueList(
878
                              LIST_STEP, LIST_STEP[_mem.vfo.b.step]))
879
        work.append(rs)
880

    
881
        # broadcast FM settings
882
        _fm_presets = self._memobj.fm_presets
883
        if _fm_presets <= 108.0 * 10 - 650:
884
            preset = _fm_presets / 10.0 + 65
885
        elif _fm_presets >= 65.0 * 10 and _fm_presets <= 108.0 * 10:
886
            preset = _fm_presets / 10.0
887
        else:
888
            preset = 76.0
889
        rs = RadioSetting("fm_presets", "FM Preset(MHz)",
890
                          RadioSettingValueFloat(65, 108.0, preset, 0.1, 1))
891
        fm_preset.append(rs)
892

    
893
        # DTMF encode settings
894
        for i in range(0, 15):
895
            _codeobj = self._memobj.pttid[i].code
896
            _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
897
            val = RadioSettingValueString(0, 16, _code, False)
898
            val.set_charset(DTMF_CHARS)
899
            rs = RadioSetting("pttid/%i.code" % i,
900
                              "Signal Code %i" % (i + 1), val)
901

    
902
            def apply_code(setting, obj):
903
                code = []
904
                for j in range(0, 16):
905
                    try:
906
                        code.append(DTMF_CHARS.index(str(setting.value)[j]))
907
                    except IndexError:
908
                        code.append(0xFF)
909
                obj.code = code
910
            rs.set_apply_callback(apply_code, self._memobj.pttid[i])
911
            dtmfe.append(rs)
912

    
913
        if _mem.ani.dtmfon > 0xC3:
914
            val = 0x03
915
        else:
916
            val = _mem.ani.dtmfon
917
        rs = RadioSetting("ani.dtmfon", "DTMF Speed (on)",
918
                          RadioSettingValueList(LIST_DTMFSPEED,
919
                                                LIST_DTMFSPEED[val]))
920
        dtmfe.append(rs)
921

    
922
        if _mem.ani.dtmfoff > 0xC3:
923
            val = 0x03
924
        else:
925
            val = _mem.ani.dtmfoff
926
        rs = RadioSetting("ani.dtmfoff", "DTMF Speed (off)",
927
                          RadioSettingValueList(LIST_DTMFSPEED,
928
                                                LIST_DTMFSPEED[val]))
929
        dtmfe.append(rs)
930

    
931
        _codeobj = self._memobj.ani.code
932
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
933
        val = RadioSettingValueString(0, 7, _code, False)
934
        val.set_charset(DTMF_CHARS)
935
        rs = RadioSetting("ani.code", "ANI Code", val)
936

    
937
        def apply_code(setting, obj):
938
            code = []
939
            for j in range(0, 7):
940
                try:
941
                    code.append(DTMF_CHARS.index(str(setting.value)[j]))
942
                except IndexError:
943
                    code.append(0xFF)
944
            obj.code = code
945
        rs.set_apply_callback(apply_code, self._memobj.ani)
946
        dtmfe.append(rs)
947

    
948
        rs = RadioSetting("ani.aniid", "When to send ANI ID",
949
                          RadioSettingValueList(LIST_PTTID,
950
                                                LIST_PTTID[_mem.ani.aniid]))
951
        dtmfe.append(rs)
952

    
953
        # DTMF decode settings
954
        rs = RadioSetting("ani.mastervice", "Master and Vice ID",
955
                          RadioSettingValueBoolean(_mem.ani.mastervice))
956
        dtmfd.append(rs)
957

    
958
        _codeobj = _mem.ani.masterid
959
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
960
        val = RadioSettingValueString(0, 5, _code, False)
961
        val.set_charset(DTMF_CHARS)
962
        rs = RadioSetting("ani.masterid", "Master Control ID", val)
963

    
964
        def apply_code(setting, obj):
965
            code = []
966
            for j in range(0, 5):
967
                try:
968
                    code.append(DTMF_CHARS.index(str(setting.value)[j]))
969
                except IndexError:
970
                    code.append(0xFF)
971
            obj.masterid = code
972
        rs.set_apply_callback(apply_code, self._memobj.ani)
973
        dtmfd.append(rs)
974

    
975
        rs = RadioSetting("ani.minspection", "Master Inspection",
976
                          RadioSettingValueBoolean(_mem.ani.minspection))
977
        dtmfd.append(rs)
978

    
979
        rs = RadioSetting("ani.mmonitor", "Master Monitor",
980
                          RadioSettingValueBoolean(_mem.ani.mmonitor))
981
        dtmfd.append(rs)
982

    
983
        rs = RadioSetting("ani.mstun", "Master Stun",
984
                          RadioSettingValueBoolean(_mem.ani.mstun))
985
        dtmfd.append(rs)
986

    
987
        rs = RadioSetting("ani.mkill", "Master Kill",
988
                          RadioSettingValueBoolean(_mem.ani.mkill))
989
        dtmfd.append(rs)
990

    
991
        rs = RadioSetting("ani.mrevive", "Master Revive",
992
                          RadioSettingValueBoolean(_mem.ani.mrevive))
993
        dtmfd.append(rs)
994

    
995
        _codeobj = _mem.ani.viceid
996
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
997
        val = RadioSettingValueString(0, 5, _code, False)
998
        val.set_charset(DTMF_CHARS)
999
        rs = RadioSetting("ani.viceid", "Vice Control ID", val)
1000

    
1001
        def apply_code(setting, obj):
1002
            code = []
1003
            for j in range(0, 5):
1004
                try:
1005
                    code.append(DTMF_CHARS.index(str(setting.value)[j]))
1006
                except IndexError:
1007
                    code.append(0xFF)
1008
            obj.viceid = code
1009
        rs.set_apply_callback(apply_code, self._memobj.ani)
1010
        dtmfd.append(rs)
1011

    
1012
        rs = RadioSetting("ani.vinspection", "Vice Inspection",
1013
                          RadioSettingValueBoolean(_mem.ani.vinspection))
1014
        dtmfd.append(rs)
1015

    
1016
        rs = RadioSetting("ani.vmonitor", "Vice Monitor",
1017
                          RadioSettingValueBoolean(_mem.ani.vmonitor))
1018
        dtmfd.append(rs)
1019

    
1020
        rs = RadioSetting("ani.vstun", "Vice Stun",
1021
                          RadioSettingValueBoolean(_mem.ani.vstun))
1022
        dtmfd.append(rs)
1023

    
1024
        rs = RadioSetting("ani.vkill", "Vice Kill",
1025
                          RadioSettingValueBoolean(_mem.ani.vkill))
1026
        dtmfd.append(rs)
1027

    
1028
        rs = RadioSetting("ani.vrevive", "Vice Revive",
1029
                          RadioSettingValueBoolean(_mem.ani.vrevive))
1030
        dtmfd.append(rs)
1031

    
1032
        _codeobj = _mem.ani.inspection
1033
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
1034
        val = RadioSettingValueString(0, 8, _code, False)
1035
        val.set_charset(DTMF_CHARS)
1036
        rs = RadioSetting("ani.inspection", "Inspection Code", val)
1037

    
1038
        def apply_code(setting, obj):
1039
            code = []
1040
            for j in range(0, 8):
1041
                try:
1042
                    code.append(DTMF_CHARS.index(str(setting.value)[j]))
1043
                except IndexError:
1044
                    code.append(0xFF)
1045
            obj.inspection = code
1046
        rs.set_apply_callback(apply_code, self._memobj.ani)
1047
        dtmfd.append(rs)
1048

    
1049
        _codeobj = _mem.ani.monitor
1050
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
1051
        val = RadioSettingValueString(0, 8, _code, False)
1052
        val.set_charset(DTMF_CHARS)
1053
        rs = RadioSetting("ani.monitor", "Monitor Code", val)
1054

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

    
1066
        _codeobj = _mem.ani.alarmcode
1067
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
1068
        val = RadioSettingValueString(0, 8, _code, False)
1069
        val.set_charset(DTMF_CHARS)
1070
        rs = RadioSetting("ani.alarm", "Alarm Code", val)
1071

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

    
1083
        _codeobj = _mem.ani.stun
1084
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
1085
        val = RadioSettingValueString(0, 8, _code, False)
1086
        val.set_charset(DTMF_CHARS)
1087
        rs = RadioSetting("ani.stun", "Stun Code", val)
1088

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

    
1100
        _codeobj = _mem.ani.kill
1101
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
1102
        val = RadioSettingValueString(0, 8, _code, False)
1103
        val.set_charset(DTMF_CHARS)
1104
        rs = RadioSetting("ani.kill", "Kill Code", val)
1105

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

    
1117
        _codeobj = _mem.ani.revive
1118
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
1119
        val = RadioSettingValueString(0, 8, _code, False)
1120
        val.set_charset(DTMF_CHARS)
1121
        rs = RadioSetting("ani.revive", "Revive Code", val)
1122

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

    
1134
        def apply_dmtf_listvalue(setting, obj):
1135
            LOG.debug("Setting value: "+ str(setting.value) + " from list")
1136
            val = str(setting.value)
1137
            index = LIST_DTMF_SPECIAL_DIGITS.index(val)
1138
            val = LIST_DTMF_SPECIAL_VALUES[index]
1139
            obj.set_value(val)
1140

    
1141
        if _mem.ani.groupcode in LIST_DTMF_SPECIAL_VALUES:
1142
            idx = LIST_DTMF_SPECIAL_VALUES.index(_mem.ani.groupcode)
1143
        else:
1144
            idx = LIST_DTMF_SPECIAL_VALUES.index(0x0B)
1145
        rs = RadioSetting("ani.groupcode", "Group Code",
1146
                          RadioSettingValueList(LIST_DTMF_SPECIAL_DIGITS,
1147
                                                LIST_DTMF_SPECIAL_DIGITS[idx]))
1148
        rs.set_apply_callback(apply_dmtf_listvalue, _mem.ani.groupcode)
1149
        dtmfd.append(rs)
1150

    
1151
        if _mem.ani.spacecode in LIST_DTMF_SPECIAL_VALUES:
1152
            idx = LIST_DTMF_SPECIAL_VALUES.index(_mem.ani.spacecode)
1153
        else:
1154
            idx = LIST_DTMF_SPECIAL_VALUES.index(0x0C)
1155
        rs = RadioSetting("ani.spacecode", "Space Code",
1156
                          RadioSettingValueList(LIST_DTMF_SPECIAL_DIGITS,
1157
                                                LIST_DTMF_SPECIAL_DIGITS[idx]))
1158
        rs.set_apply_callback(apply_dmtf_listvalue, _mem.ani.spacecode)
1159
        dtmfd.append(rs)
1160

    
1161
        if _mem.ani.resettime > 0x9F:
1162
            val = 0x4F
1163
        else:
1164
            val = _mem.ani.resettime
1165
        rs = RadioSetting("ani.resettime", "Reset Time",
1166
                          RadioSettingValueList(LIST_RESETTIME,
1167
                                                LIST_RESETTIME[val]))
1168
        dtmfd.append(rs)
1169

    
1170
        if _mem.ani.delayproctime > 0x27:
1171
            val = 0x04
1172
        else:
1173
            val = _mem.ani.delayproctime
1174
        rs = RadioSetting("ani.delayproctime", "Delay Processing Time",
1175
                          RadioSettingValueList(LIST_DELAYPROCTIME,
1176
                                                LIST_DELAYPROCTIME[val]))
1177
        dtmfd.append(rs)
1178

    
1179
        # Service settings
1180
        for band in ["vhf", "vhf2", "uhf"]:
1181
            for index in range(0, 10):
1182
                key = "squelch.%s.sql%i" % (band, index)
1183
                if band == "vhf":
1184
                    _obj = self._memobj.squelch.vhf
1185
                    _name = "VHF"
1186
                elif band == "vhf2":
1187
                    _obj = self._memobj.squelch.vhf2
1188
                    _name = "220"
1189
                elif band == "uhf":
1190
                    _obj = self._memobj.squelch.uhf
1191
                    _name = "UHF"
1192
                val = RadioSettingValueInteger(0, 123,
1193
                          getattr(_obj, "sql%i" % (index)))
1194
                if index == 0:
1195
                    val.set_mutable(False)
1196
                name = "%s Squelch %i" % (_name, index)
1197
                rs = RadioSetting(key, name, val)
1198
                service.append(rs)
1199

    
1200
        return top
1201

    
1202
    @classmethod
1203
    def match_model(cls, filedata, filename):
1204
        match_size = False
1205
        match_model = False
1206

    
1207
        # testing the file data size
1208
        if len(filedata) == 0x200E:
1209
            match_size = True
1210

    
1211
        # testing the firmware model fingerprint
1212
        match_model = model_match(cls, filedata)
1213

    
1214
        if match_size and match_model:
1215
            return True
1216
        else:
1217
            return False
1218

    
1219

    
1220
@directory.register
1221
class MTCUV5R3Radio(UV5X3):
1222
    VENDOR = "MTC"
1223
    MODEL = "UV-5R-3"
1224

    
1225
    _fileid = [UV5R3_fp1, ]
1226

    
1227
    _magic = [MSTRING_UV5R3, ]
1228

    
1229
    VALID_BANDS = [(136000000, 174000000),
1230
                   (200000000, 260000000),
1231
                   (400000000, 521000000)]
    (1-1/1)