Project

General

Profile

Bug #9515 » uv5x3_6VFOs_#4.py

VFO A VHF/VHF2/UHF (Saved), VFO B VHF/VHF2/UHF (Saved) - Jim Unroe, 11/25/2021 12:07 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
    struct subvfo {
338
      u8 freq[8];
339
      u8 unknown0[8];
340
    };
341

    
342
    #seekto 0x1E00;
343
    struct {
344
      struct subvfo vhf;
345
      struct subvfo vhf2;
346
      struct subvfo uhf;
347
    } subvfoa;
348

    
349
    #seekto 0x1E40;
350
    struct {
351
      struct subvfo vhf;
352
      struct subvfo vhf2;
353
      struct subvfo uhf;
354
    } subvfob;
355

    
356
    #seekto 0x1ED0;
357
    struct {
358
      char line1[7];
359
      char line2[7];
360
    } sixpoweron_msg;
361

    
362
    #seekto 0x1EF0;
363
    struct {
364
      char line1[7];
365
      char line2[7];
366
    } firmware_msg;
367

    
368
    struct squelch {
369
      u8 sql0;
370
      u8 sql1;
371
      u8 sql2;
372
      u8 sql3;
373
      u8 sql4;
374
      u8 sql5;
375
      u8 sql6;
376
      u8 sql7;
377
      u8 sql8;
378
      u8 sql9;
379
    };
380

    
381
    #seekto 0x1F60;
382
    struct {
383
      struct squelch vhf;
384
      u8 unknown0[6];
385
      u8 unknown1[16];
386
      struct squelch vhf2;
387
      u8 unknown2[6];
388
      u8 unknown3[16];
389
      struct squelch uhf;
390
    } squelch;
391

    
392
    #seekto 0x1FE0;
393
    struct {
394
      char line1[7];
395
      char line2[7];
396
    } poweron_msg;
397

    
398
    struct limit {
399
      u8 enable;
400
      bbcd lower[2];
401
      bbcd upper[2];
402
    };
403

    
404
    #seekto 0x1FF0;
405
    struct {
406
      struct limit vhf;
407
      struct limit vhf2;
408
      struct limit uhf;
409
    } limits;
410

    
411
    """
412

    
413
    @classmethod
414
    def get_prompts(cls):
415
        rp = chirp_common.RadioPrompts()
416
        rp.experimental = \
417
            ('Please save an unedited copy of your first successful\n'
418
             'download to a CHIRP Radio Images(*.img) file.'
419
             )
420
        rp.pre_download = _(dedent("""\
421
            Follow these instructions to download your info:
422

    
423
            1 - Turn off your radio
424
            2 - Connect your interface cable
425
            3 - Turn on your radio
426
            4 - Do the download of your radio data
427
            """))
428
        rp.pre_upload = _(dedent("""\
429
            Follow this instructions to upload your info:
430

    
431
            1 - Turn off your radio
432
            2 - Connect your interface cable
433
            3 - Turn on your radio
434
            4 - Do the upload of your radio data
435
            """))
436
        return rp
437

    
438
    def process_mmap(self):
439
        """Process the mem map into the mem object"""
440
        self._memobj = bitwise.parse(self.MEM_FORMAT, self._mmap)
441

    
442
    def get_settings(self):
443
        """Translate the bit in the mem_struct into settings in the UI"""
444
        _mem = self._memobj
445
        basic = RadioSettingGroup("basic", "Basic Settings")
446
        advanced = RadioSettingGroup("advanced", "Advanced Settings")
447
        other = RadioSettingGroup("other", "Other Settings")
448
        work = RadioSettingGroup("work", "Work Mode Settings")
449
        fm_preset = RadioSettingGroup("fm_preset", "FM Preset")
450
        dtmfe = RadioSettingGroup("dtmfe", "DTMF Encode Settings")
451
        dtmfd = RadioSettingGroup("dtmfd", "DTMF Decode Settings")
452
        service = RadioSettingGroup("service", "Service Settings")
453
        top = RadioSettings(basic, advanced, other, work, fm_preset, dtmfe,
454
                            dtmfd, service)
455

    
456
        # Basic settings
457
        if _mem.settings.squelch > 0x09:
458
            val = 0x00
459
        else:
460
            val = _mem.settings.squelch
461
        rs = RadioSetting("settings.squelch", "Squelch",
462
                          RadioSettingValueList(
463
                              LIST_OFF1TO9, LIST_OFF1TO9[val]))
464
        basic.append(rs)
465

    
466
        if _mem.settings.save > 0x04:
467
            val = 0x00
468
        else:
469
            val = _mem.settings.save
470
        rs = RadioSetting("settings.save", "Battery Saver",
471
                          RadioSettingValueList(
472
                              LIST_SAVE, LIST_SAVE[val]))
473
        basic.append(rs)
474

    
475
        if _mem.settings.vox > 0x0A:
476
            val = 0x00
477
        else:
478
            val = _mem.settings.vox
479
        rs = RadioSetting("settings.vox", "Vox",
480
                          RadioSettingValueList(
481
                              LIST_OFF1TO10, LIST_OFF1TO10[val]))
482
        basic.append(rs)
483

    
484
        if _mem.settings.abr > 0x0A:
485
            val = 0x00
486
        else:
487
            val = _mem.settings.abr
488
        rs = RadioSetting("settings.abr", "Backlight Timeout",
489
                          RadioSettingValueList(
490
                              LIST_OFF1TO10, LIST_OFF1TO10[val]))
491
        basic.append(rs)
492

    
493
        rs = RadioSetting("settings.tdr", "Dual Watch",
494
                          RadioSettingValueBoolean(_mem.settings.tdr))
495
        basic.append(rs)
496

    
497
        rs = RadioSetting("settings.beep", "Beep",
498
                          RadioSettingValueBoolean(_mem.settings.beep))
499
        basic.append(rs)
500

    
501
        if _mem.settings.timeout > 0x27:
502
            val = 0x03
503
        else:
504
            val = _mem.settings.timeout
505
        rs = RadioSetting("settings.timeout", "Timeout Timer",
506
                          RadioSettingValueList(
507
                              LIST_TIMEOUT, LIST_TIMEOUT[val]))
508
        basic.append(rs)
509

    
510
        if _mem.settings.voice > 0x02:
511
            val = 0x01
512
        else:
513
            val = _mem.settings.voice
514
        rs = RadioSetting("settings.voice", "Voice Prompt",
515
                          RadioSettingValueList(
516
                              LIST_VOICE, LIST_VOICE[val]))
517
        basic.append(rs)
518

    
519
        rs = RadioSetting("settings.dtmfst", "DTMF Sidetone",
520
                          RadioSettingValueList(LIST_DTMFST, LIST_DTMFST[
521
                              _mem.settings.dtmfst]))
522
        basic.append(rs)
523

    
524
        if _mem.settings.screv > 0x02:
525
            val = 0x01
526
        else:
527
            val = _mem.settings.screv
528
        rs = RadioSetting("settings.screv", "Scan Resume",
529
                          RadioSettingValueList(
530
                              LIST_RESUME, LIST_RESUME[val]))
531
        basic.append(rs)
532

    
533
        rs = RadioSetting("settings.pttid", "When to send PTT ID",
534
                          RadioSettingValueList(LIST_PTTID, LIST_PTTID[
535
                              _mem.settings.pttid]))
536
        basic.append(rs)
537

    
538
        if _mem.settings.pttlt > 0x1E:
539
            val = 0x05
540
        else:
541
            val = _mem.settings.pttlt
542
        rs = RadioSetting("pttlt", "PTT ID Delay",
543
                          RadioSettingValueInteger(0, 50, val))
544
        basic.append(rs)
545

    
546
        rs = RadioSetting("settings.mdfa", "Display Mode (A)",
547
                          RadioSettingValueList(LIST_MODE, LIST_MODE[
548
                              _mem.settings.mdfa]))
549
        basic.append(rs)
550

    
551
        rs = RadioSetting("settings.mdfb", "Display Mode (B)",
552
                          RadioSettingValueList(LIST_MODE, LIST_MODE[
553
                              _mem.settings.mdfb]))
554
        basic.append(rs)
555

    
556
        rs = RadioSetting("settings.sync", "Sync A & B",
557
                          RadioSettingValueBoolean(_mem.settings.sync))
558
        basic.append(rs)
559

    
560
        rs = RadioSetting("settings.wtled", "Standby LED Color",
561
                          RadioSettingValueList(
562
                              LIST_COLOR, LIST_COLOR[_mem.settings.wtled]))
563
        basic.append(rs)
564

    
565
        rs = RadioSetting("settings.rxled", "RX LED Color",
566
                          RadioSettingValueList(
567
                              LIST_COLOR, LIST_COLOR[_mem.settings.rxled]))
568
        basic.append(rs)
569

    
570
        rs = RadioSetting("settings.txled", "TX LED Color",
571
                          RadioSettingValueList(
572
                              LIST_COLOR, LIST_COLOR[_mem.settings.txled]))
573
        basic.append(rs)
574

    
575
        if _mem.settings.almod > 0x02:
576
            val = 0x00
577
        else:
578
            val = _mem.settings.almod
579
        rs = RadioSetting("settings.almod", "Alarm Mode",
580
                          RadioSettingValueList(
581
                              LIST_ALMOD, LIST_ALMOD[val]))
582
        basic.append(rs)
583

    
584
        if _mem.settings.tdrab > 0x02:
585
            val = 0x00
586
        else:
587
            val = _mem.settings.tdrab
588
        rs = RadioSetting("settings.tdrab", "Dual Watch TX Priority",
589
                          RadioSettingValueList(
590
                              LIST_OFFAB, LIST_OFFAB[val]))
591
        basic.append(rs)
592

    
593
        rs = RadioSetting("settings.ste", "Squelch Tail Eliminate (HT to HT)",
594
                          RadioSettingValueBoolean(_mem.settings.ste))
595
        basic.append(rs)
596

    
597
        if _mem.settings.rpste > 0x0A:
598
            val = 0x00
599
        else:
600
            val = _mem.settings.rpste
601
        rs = RadioSetting("settings.rpste",
602
                          "Squelch Tail Eliminate (repeater)",
603
                          RadioSettingValueList(
604
                              LIST_RPSTE, LIST_RPSTE[val]))
605
        basic.append(rs)
606

    
607
        if _mem.settings.rptrl > 0x0A:
608
            val = 0x00
609
        else:
610
            val = _mem.settings.rptrl
611
        rs = RadioSetting("settings.rptrl", "STE Repeater Delay",
612
                          RadioSettingValueList(
613
                              LIST_STEDELAY, LIST_STEDELAY[val]))
614
        basic.append(rs)
615

    
616
        rs = RadioSetting("settings.ponmsg", "Power-On Message",
617
                          RadioSettingValueList(LIST_PONMSG, LIST_PONMSG[
618
                              _mem.settings.ponmsg]))
619
        basic.append(rs)
620

    
621
        rs = RadioSetting("settings.roger", "Roger Beep",
622
                          RadioSettingValueBoolean(_mem.settings.roger))
623
        basic.append(rs)
624

    
625
        rs = RadioSetting("settings.dani", "Decode ANI",
626
                          RadioSettingValueBoolean(_mem.settings.dani))
627
        basic.append(rs)
628

    
629
        if _mem.settings.dtmfg > 0x3C:
630
            val = 0x14
631
        else:
632
            val = _mem.settings.dtmfg
633
        rs = RadioSetting("settings.dtmfg", "DTMF Gain",
634
                          RadioSettingValueInteger(0, 60, val))
635
        basic.append(rs)
636

    
637
        # Advanced settings
638
        rs = RadioSetting("settings.reset", "RESET Menu",
639
                          RadioSettingValueBoolean(_mem.settings.reset))
640
        advanced.append(rs)
641

    
642
        rs = RadioSetting("settings.menu", "All Menus",
643
                          RadioSettingValueBoolean(_mem.settings.menu))
644
        advanced.append(rs)
645

    
646
        rs = RadioSetting("settings.fmradio", "Broadcast FM Radio",
647
                          RadioSettingValueBoolean(_mem.settings.fmradio))
648
        advanced.append(rs)
649

    
650
        rs = RadioSetting("settings.alarm", "Alarm Sound",
651
                          RadioSettingValueBoolean(_mem.settings.alarm))
652
        advanced.append(rs)
653

    
654
        # Other settings
655
        def _filter(name):
656
            filtered = ""
657
            for char in str(name):
658
                if char in chirp_common.CHARSET_ASCII:
659
                    filtered += char
660
                else:
661
                    filtered += " "
662
            return filtered
663

    
664
        _msg = _mem.firmware_msg
665
        val = RadioSettingValueString(0, 7, _filter(_msg.line1))
666
        val.set_mutable(False)
667
        rs = RadioSetting("firmware_msg.line1", "Firmware Message 1", val)
668
        other.append(rs)
669

    
670
        val = RadioSettingValueString(0, 7, _filter(_msg.line2))
671
        val.set_mutable(False)
672
        rs = RadioSetting("firmware_msg.line2", "Firmware Message 2", val)
673
        other.append(rs)
674

    
675
        _msg = _mem.sixpoweron_msg
676
        val = RadioSettingValueString(0, 7, _filter(_msg.line1))
677
        val.set_mutable(False)
678
        rs = RadioSetting("sixpoweron_msg.line1", "6+Power-On Message 1", val)
679
        other.append(rs)
680
        val = RadioSettingValueString(0, 7, _filter(_msg.line2))
681
        val.set_mutable(False)
682
        rs = RadioSetting("sixpoweron_msg.line2", "6+Power-On Message 2", val)
683
        other.append(rs)
684

    
685
        _msg = _mem.poweron_msg
686
        rs = RadioSetting("poweron_msg.line1", "Power-On Message 1",
687
                          RadioSettingValueString(
688
                              0, 7, _filter(_msg.line1)))
689
        other.append(rs)
690
        rs = RadioSetting("poweron_msg.line2", "Power-On Message 2",
691
                          RadioSettingValueString(
692
                              0, 7, _filter(_msg.line2)))
693
        other.append(rs)
694

    
695
        if str(_mem.firmware_msg.line1) == ("UVVG302" or "5R31709"):
696
            lower = 136
697
            upper = 174
698
        else:
699
            lower = 130
700
            upper = 179
701
        if int(_mem.limits.vhf.lower) < lower:
702
            val = lower
703
        else:
704
            val = int(_mem.limits.vhf.lower)
705
        rs = RadioSetting("limits.vhf.lower", "VHF Lower Limit (MHz)",
706
                          RadioSettingValueInteger(lower, upper, val))
707
        other.append(rs)
708

    
709
        if int(_mem.limits.vhf.upper) > upper:
710
            val = upper
711
        else:
712
            val = int(_mem.limits.vhf.upper)
713
        rs = RadioSetting("limits.vhf.upper", "VHF Upper Limit (MHz)",
714
                          RadioSettingValueInteger(lower, upper, val))
715
        other.append(rs)
716

    
717
        if str(_mem.firmware_msg.line1) == "UVVG302":
718
            lower = 200
719
            upper = 230
720
        elif str(_mem.firmware_msg.line1) == "5R31709":
721
            lower = 200
722
            upper = 260
723
        else:
724
            lower = 220
725
            upper = 225
726
        if int(_mem.limits.vhf2.lower) < lower:
727
            val = lower
728
        else:
729
            val = int(_mem.limits.vhf2.lower)
730
        rs = RadioSetting("limits.vhf2.lower", "VHF2 Lower Limit (MHz)",
731
                          RadioSettingValueInteger(lower, upper, val))
732
        other.append(rs)
733

    
734
        if int(_mem.limits.vhf2.upper) > upper:
735
            val = upper
736
        else:
737
            val = int(_mem.limits.vhf2.upper)
738
        rs = RadioSetting("limits.vhf2.upper", "VHF2 Upper Limit (MHz)",
739
                          RadioSettingValueInteger(lower, upper, val))
740
        other.append(rs)
741

    
742
        if str(_mem.firmware_msg.line1) == "UVVG302":
743
            lower = 400
744
            upper = 480
745
        else:
746
            lower = 400
747
            upper = 520
748
        if int(_mem.limits.uhf.lower) < lower:
749
            val = lower
750
        else:
751
            val = int(_mem.limits.uhf.lower)
752
        rs = RadioSetting("limits.uhf.lower", "UHF Lower Limit (MHz)",
753
                          RadioSettingValueInteger(lower, upper, val))
754
        other.append(rs)
755

    
756
        if int(_mem.limits.uhf.upper) > upper:
757
            val = upper
758
        else:
759
            val = int(_mem.limits.uhf.upper)
760
        rs = RadioSetting("limits.uhf.upper", "UHF Upper Limit (MHz)",
761
                          RadioSettingValueInteger(lower, upper, val))
762
        other.append(rs)
763

    
764
        # Work mode settings
765
        rs = RadioSetting("settings.displayab", "Display",
766
                          RadioSettingValueList(
767
                              LIST_AB, LIST_AB[_mem.settings.displayab]))
768
        work.append(rs)
769

    
770
        rs = RadioSetting("settings.workmode", "VFO/MR Mode",
771
                          RadioSettingValueList(
772
                              LIST_WORKMODE,
773
                              LIST_WORKMODE[_mem.settings.workmode]))
774
        work.append(rs)
775

    
776
        rs = RadioSetting("settings.keylock", "Keypad Lock",
777
                          RadioSettingValueBoolean(_mem.settings.keylock))
778
        work.append(rs)
779

    
780
        rs = RadioSetting("wmchannel.mrcha", "MR A Channel",
781
                          RadioSettingValueInteger(0, 127,
782
                                                   _mem.wmchannel.mrcha))
783
        work.append(rs)
784

    
785
        rs = RadioSetting("wmchannel.mrchb", "MR B Channel",
786
                          RadioSettingValueInteger(0, 127,
787
                                                   _mem.wmchannel.mrchb))
788
        work.append(rs)
789

    
790
        def convert_bytes_to_freq(bytes):
791
            real_freq = 0
792
            for byte in bytes:
793
                real_freq = (real_freq * 10) + byte
794
            return chirp_common.format_freq(real_freq * 10)
795

    
796
        def my_validate(value):
797
            _vhf_lower = int(_mem.limits.vhf.lower)
798
            _vhf_upper = int(_mem.limits.vhf.upper)
799
            _vhf2_lower = int(_mem.limits.vhf2.lower)
800
            _vhf2_upper = int(_mem.limits.vhf2.upper)
801
            _uhf_lower = int(_mem.limits.uhf.lower)
802
            _uhf_upper = int(_mem.limits.uhf.upper)
803
            value = chirp_common.parse_freq(value)
804
            msg = ("Can't be less than %i.0000")
805
            if value > 99000000 and value < _vhf_lower * 1000000:
806
                raise InvalidValueError(msg % (_vhf_lower))
807
            msg = ("Can't be between %i.9975-%i.0000")
808
            if (_vhf_upper + 1) * 1000000 <= value and \
809
                    value < _vhf2_lower * 1000000:
810
                raise InvalidValueError(msg % (_vhf_upper, _vhf2_lower))
811
            if (_vhf2_upper + 1) * 1000000 <= value and \
812
                    value < _uhf_lower * 1000000:
813
                raise InvalidValueError(msg % (_vhf2_upper, _uhf_lower))
814
            msg = ("Can't be greater than %i.9975")
815
            if value > 99000000 and value >= (_uhf_upper + 1) * 1000000:
816
                raise InvalidValueError(msg % (_uhf_upper))
817
            return chirp_common.format_freq(value)
818

    
819
        ##########
820
        def my_vhf_validate(value):
821
            _vhf_lower = int(_mem.limits.vhf.lower)
822
            _vhf_upper = int(_mem.limits.vhf.upper)
823
            value = chirp_common.parse_freq(value)
824
            msg = ("Must be between %i.0000-%i.9975")
825
            if (_vhf_upper + 1) * 1000000 <= value or \
826
                    value < _vhf_lower * 1000000:
827
                raise InvalidValueError(msg % (_vhf_lower, _vhf_upper))
828
            return chirp_common.format_freq(value)
829

    
830
        def my_vhf2_validate(value):
831
            _vhf2_lower = int(_mem.limits.vhf2.lower)
832
            _vhf2_upper = int(_mem.limits.vhf2.upper)
833
            value = chirp_common.parse_freq(value)
834
            msg = ("Must be between %i.0000-%i.9975")
835
            if (_vhf2_upper + 1) * 1000000 <= value or \
836
                    value < _vhf2_lower * 1000000:
837
                raise InvalidValueError(msg % (_vhf2_lower, _vhf2_upper))
838
            return chirp_common.format_freq(value)
839

    
840
        def my_uhf_validate(value):
841
            _uhf_lower = int(_mem.limits.uhf.lower)
842
            _uhf_upper = int(_mem.limits.uhf.upper)
843
            value = chirp_common.parse_freq(value)
844
            msg = ("Must be between %i.0000-%i.9975")
845
            if (_uhf_upper + 1) * 1000000 <= value or \
846
                    value < _uhf_lower * 1000000:
847
                raise InvalidValueError(msg % (_uhf_lower, _uhf_upper))
848
            return chirp_common.format_freq(value)
849
        ##########
850

    
851
        def apply_freq(setting, obj):
852
            value = chirp_common.parse_freq(str(setting.value)) / 10
853
            for i in range(7, -1, -1):
854
                obj.freq[i] = value % 10
855
                value /= 10
856

    
857
        val1a = RadioSettingValueString(0, 10,
858
                                        convert_bytes_to_freq(_mem.vfo.a.freq))
859
        val1a.set_validate_callback(my_validate)
860
        rs = RadioSetting("vfo.a.freq", "VFO A Frequency", val1a)
861
        rs.set_apply_callback(apply_freq, _mem.vfo.a)
862
        work.append(rs)
863

    
864
        val1b = RadioSettingValueString(0, 10,
865
                                        convert_bytes_to_freq(_mem.vfo.b.freq))
866
        val1b.set_validate_callback(my_validate)
867
        rs = RadioSetting("vfo.b.freq", "VFO B Frequency", val1b)
868
        rs.set_apply_callback(apply_freq, _mem.vfo.b)
869
        work.append(rs)
870

    
871
        ##########
872
        val1a = RadioSettingValueString(0, 10,
873
                                        convert_bytes_to_freq(_mem.subvfoa.vhf.freq))
874
        val1a.set_validate_callback(my_vhf_validate)
875
        rs = RadioSetting("subvfoa.vhf.freq", "VFO A VHF (Saved)", val1a)
876
        rs.set_apply_callback(apply_freq, _mem.subvfoa.vhf)
877
        work.append(rs)
878

    
879
        val1a = RadioSettingValueString(0, 10,
880
                                        convert_bytes_to_freq(_mem.subvfoa.vhf2.freq))
881
        val1a.set_validate_callback(my_vhf2_validate)
882
        rs = RadioSetting("subvfoa.vhf2.freq", "VFO A VHF2 (Saved)", val1a)
883
        rs.set_apply_callback(apply_freq, _mem.subvfoa.vhf2)
884
        work.append(rs)
885

    
886
        val1a = RadioSettingValueString(0, 10,
887
                                        convert_bytes_to_freq(_mem.subvfoa.uhf.freq))
888
        val1a.set_validate_callback(my_uhf_validate)
889
        rs = RadioSetting("subvfoa.uhf.freq", "VFO A UHF (Saved)", val1a)
890
        rs.set_apply_callback(apply_freq, _mem.subvfoa.uhf)
891
        work.append(rs)
892
        ##########
893

    
894
        ##########
895
        val1b = RadioSettingValueString(0, 10,
896
                                        convert_bytes_to_freq(_mem.subvfob.vhf.freq))
897
        val1b.set_validate_callback(my_vhf_validate)
898
        rs = RadioSetting("subvfob.vhf.freq", "VFO B VHF (Saved)", val1b)
899
        rs.set_apply_callback(apply_freq, _mem.subvfob.vhf)
900
        work.append(rs)
901

    
902
        val1b = RadioSettingValueString(0, 10,
903
                                        convert_bytes_to_freq(_mem.subvfob.vhf2.freq))
904
        val1b.set_validate_callback(my_vhf2_validate)
905
        rs = RadioSetting("subvfob.vhf2.freq", "VFO B VHF2 (Saved)", val1b)
906
        rs.set_apply_callback(apply_freq, _mem.subvfob.vhf2)
907
        work.append(rs)
908

    
909
        val1b = RadioSettingValueString(0, 10,
910
                                        convert_bytes_to_freq(_mem.subvfob.uhf.freq))
911
        val1b.set_validate_callback(my_uhf_validate)
912
        rs = RadioSetting("subvfob.uhf.freq", "VFO B UHF (Saved)", val1b)
913
        rs.set_apply_callback(apply_freq, _mem.subvfob.uhf)
914
        work.append(rs)
915
        ##########
916

    
917
        rs = RadioSetting("vfo.a.sftd", "VFO A Shift",
918
                          RadioSettingValueList(
919
                              LIST_SHIFTD, LIST_SHIFTD[_mem.vfo.a.sftd]))
920
        work.append(rs)
921

    
922
        rs = RadioSetting("vfo.b.sftd", "VFO B Shift",
923
                          RadioSettingValueList(
924
                              LIST_SHIFTD, LIST_SHIFTD[_mem.vfo.b.sftd]))
925
        work.append(rs)
926

    
927
        def convert_bytes_to_offset(bytes):
928
            real_offset = 0
929
            for byte in bytes:
930
                real_offset = (real_offset * 10) + byte
931
            return chirp_common.format_freq(real_offset * 1000)
932

    
933
        def apply_offset(setting, obj):
934
            value = chirp_common.parse_freq(str(setting.value)) / 1000
935
            for i in range(5, -1, -1):
936
                obj.offset[i] = value % 10
937
                value /= 10
938

    
939
        val1a = RadioSettingValueString(
940
                    0, 10, convert_bytes_to_offset(_mem.vfo.a.offset))
941
        rs = RadioSetting("vfo.a.offset",
942
                          "VFO A Offset", val1a)
943
        rs.set_apply_callback(apply_offset, _mem.vfo.a)
944
        work.append(rs)
945

    
946
        val1b = RadioSettingValueString(
947
                    0, 10, convert_bytes_to_offset(_mem.vfo.b.offset))
948
        rs = RadioSetting("vfo.b.offset",
949
                          "VFO B Offset", val1b)
950
        rs.set_apply_callback(apply_offset, _mem.vfo.b)
951
        work.append(rs)
952

    
953
        rs = RadioSetting("vfo.a.txpower", "VFO A Power",
954
                          RadioSettingValueList(
955
                              LIST_TXPOWER,
956
                              LIST_TXPOWER[_mem.vfo.a.txpower]))
957
        work.append(rs)
958

    
959
        rs = RadioSetting("vfo.b.txpower", "VFO B Power",
960
                          RadioSettingValueList(
961
                              LIST_TXPOWER,
962
                              LIST_TXPOWER[_mem.vfo.b.txpower]))
963
        work.append(rs)
964

    
965
        rs = RadioSetting("vfo.a.widenarr", "VFO A Bandwidth",
966
                          RadioSettingValueList(
967
                              LIST_BANDWIDTH,
968
                              LIST_BANDWIDTH[_mem.vfo.a.widenarr]))
969
        work.append(rs)
970

    
971
        rs = RadioSetting("vfo.b.widenarr", "VFO B Bandwidth",
972
                          RadioSettingValueList(
973
                              LIST_BANDWIDTH,
974
                              LIST_BANDWIDTH[_mem.vfo.b.widenarr]))
975
        work.append(rs)
976

    
977
        rs = RadioSetting("vfo.a.scode", "VFO A S-CODE",
978
                          RadioSettingValueList(
979
                              LIST_SCODE,
980
                              LIST_SCODE[_mem.vfo.a.scode]))
981
        work.append(rs)
982

    
983
        rs = RadioSetting("vfo.b.scode", "VFO B S-CODE",
984
                          RadioSettingValueList(
985
                              LIST_SCODE,
986
                              LIST_SCODE[_mem.vfo.b.scode]))
987
        work.append(rs)
988

    
989
        rs = RadioSetting("vfo.a.step", "VFO A Tuning Step",
990
                          RadioSettingValueList(
991
                              LIST_STEP, LIST_STEP[_mem.vfo.a.step]))
992
        work.append(rs)
993
        rs = RadioSetting("vfo.b.step", "VFO B Tuning Step",
994
                          RadioSettingValueList(
995
                              LIST_STEP, LIST_STEP[_mem.vfo.b.step]))
996
        work.append(rs)
997

    
998
        # broadcast FM settings
999
        _fm_presets = self._memobj.fm_presets
1000
        if _fm_presets <= 108.0 * 10 - 650:
1001
            preset = _fm_presets / 10.0 + 65
1002
        elif _fm_presets >= 65.0 * 10 and _fm_presets <= 108.0 * 10:
1003
            preset = _fm_presets / 10.0
1004
        else:
1005
            preset = 76.0
1006
        rs = RadioSetting("fm_presets", "FM Preset(MHz)",
1007
                          RadioSettingValueFloat(65, 108.0, preset, 0.1, 1))
1008
        fm_preset.append(rs)
1009

    
1010
        # DTMF encode settings
1011
        for i in range(0, 15):
1012
            _codeobj = self._memobj.pttid[i].code
1013
            _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
1014
            val = RadioSettingValueString(0, 16, _code, False)
1015
            val.set_charset(DTMF_CHARS)
1016
            rs = RadioSetting("pttid/%i.code" % i,
1017
                              "Signal Code %i" % (i + 1), val)
1018

    
1019
            def apply_code(setting, obj):
1020
                code = []
1021
                for j in range(0, 16):
1022
                    try:
1023
                        code.append(DTMF_CHARS.index(str(setting.value)[j]))
1024
                    except IndexError:
1025
                        code.append(0xFF)
1026
                obj.code = code
1027
            rs.set_apply_callback(apply_code, self._memobj.pttid[i])
1028
            dtmfe.append(rs)
1029

    
1030
        if _mem.ani.dtmfon > 0xC3:
1031
            val = 0x03
1032
        else:
1033
            val = _mem.ani.dtmfon
1034
        rs = RadioSetting("ani.dtmfon", "DTMF Speed (on)",
1035
                          RadioSettingValueList(LIST_DTMFSPEED,
1036
                                                LIST_DTMFSPEED[val]))
1037
        dtmfe.append(rs)
1038

    
1039
        if _mem.ani.dtmfoff > 0xC3:
1040
            val = 0x03
1041
        else:
1042
            val = _mem.ani.dtmfoff
1043
        rs = RadioSetting("ani.dtmfoff", "DTMF Speed (off)",
1044
                          RadioSettingValueList(LIST_DTMFSPEED,
1045
                                                LIST_DTMFSPEED[val]))
1046
        dtmfe.append(rs)
1047

    
1048
        _codeobj = self._memobj.ani.code
1049
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
1050
        val = RadioSettingValueString(0, 7, _code, False)
1051
        val.set_charset(DTMF_CHARS)
1052
        rs = RadioSetting("ani.code", "ANI Code", val)
1053

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

    
1065
        rs = RadioSetting("ani.aniid", "When to send ANI ID",
1066
                          RadioSettingValueList(LIST_PTTID,
1067
                                                LIST_PTTID[_mem.ani.aniid]))
1068
        dtmfe.append(rs)
1069

    
1070
        # DTMF decode settings
1071
        rs = RadioSetting("ani.mastervice", "Master and Vice ID",
1072
                          RadioSettingValueBoolean(_mem.ani.mastervice))
1073
        dtmfd.append(rs)
1074

    
1075
        _codeobj = _mem.ani.masterid
1076
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
1077
        val = RadioSettingValueString(0, 5, _code, False)
1078
        val.set_charset(DTMF_CHARS)
1079
        rs = RadioSetting("ani.masterid", "Master Control ID", val)
1080

    
1081
        def apply_code(setting, obj):
1082
            code = []
1083
            for j in range(0, 5):
1084
                try:
1085
                    code.append(DTMF_CHARS.index(str(setting.value)[j]))
1086
                except IndexError:
1087
                    code.append(0xFF)
1088
            obj.masterid = code
1089
        rs.set_apply_callback(apply_code, self._memobj.ani)
1090
        dtmfd.append(rs)
1091

    
1092
        rs = RadioSetting("ani.minspection", "Master Inspection",
1093
                          RadioSettingValueBoolean(_mem.ani.minspection))
1094
        dtmfd.append(rs)
1095

    
1096
        rs = RadioSetting("ani.mmonitor", "Master Monitor",
1097
                          RadioSettingValueBoolean(_mem.ani.mmonitor))
1098
        dtmfd.append(rs)
1099

    
1100
        rs = RadioSetting("ani.mstun", "Master Stun",
1101
                          RadioSettingValueBoolean(_mem.ani.mstun))
1102
        dtmfd.append(rs)
1103

    
1104
        rs = RadioSetting("ani.mkill", "Master Kill",
1105
                          RadioSettingValueBoolean(_mem.ani.mkill))
1106
        dtmfd.append(rs)
1107

    
1108
        rs = RadioSetting("ani.mrevive", "Master Revive",
1109
                          RadioSettingValueBoolean(_mem.ani.mrevive))
1110
        dtmfd.append(rs)
1111

    
1112
        _codeobj = _mem.ani.viceid
1113
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
1114
        val = RadioSettingValueString(0, 5, _code, False)
1115
        val.set_charset(DTMF_CHARS)
1116
        rs = RadioSetting("ani.viceid", "Vice Control ID", val)
1117

    
1118
        def apply_code(setting, obj):
1119
            code = []
1120
            for j in range(0, 5):
1121
                try:
1122
                    code.append(DTMF_CHARS.index(str(setting.value)[j]))
1123
                except IndexError:
1124
                    code.append(0xFF)
1125
            obj.viceid = code
1126
        rs.set_apply_callback(apply_code, self._memobj.ani)
1127
        dtmfd.append(rs)
1128

    
1129
        rs = RadioSetting("ani.vinspection", "Vice Inspection",
1130
                          RadioSettingValueBoolean(_mem.ani.vinspection))
1131
        dtmfd.append(rs)
1132

    
1133
        rs = RadioSetting("ani.vmonitor", "Vice Monitor",
1134
                          RadioSettingValueBoolean(_mem.ani.vmonitor))
1135
        dtmfd.append(rs)
1136

    
1137
        rs = RadioSetting("ani.vstun", "Vice Stun",
1138
                          RadioSettingValueBoolean(_mem.ani.vstun))
1139
        dtmfd.append(rs)
1140

    
1141
        rs = RadioSetting("ani.vkill", "Vice Kill",
1142
                          RadioSettingValueBoolean(_mem.ani.vkill))
1143
        dtmfd.append(rs)
1144

    
1145
        rs = RadioSetting("ani.vrevive", "Vice Revive",
1146
                          RadioSettingValueBoolean(_mem.ani.vrevive))
1147
        dtmfd.append(rs)
1148

    
1149
        _codeobj = _mem.ani.inspection
1150
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
1151
        val = RadioSettingValueString(0, 8, _code, False)
1152
        val.set_charset(DTMF_CHARS)
1153
        rs = RadioSetting("ani.inspection", "Inspection Code", val)
1154

    
1155
        def apply_code(setting, obj):
1156
            code = []
1157
            for j in range(0, 8):
1158
                try:
1159
                    code.append(DTMF_CHARS.index(str(setting.value)[j]))
1160
                except IndexError:
1161
                    code.append(0xFF)
1162
            obj.inspection = code
1163
        rs.set_apply_callback(apply_code, self._memobj.ani)
1164
        dtmfd.append(rs)
1165

    
1166
        _codeobj = _mem.ani.monitor
1167
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
1168
        val = RadioSettingValueString(0, 8, _code, False)
1169
        val.set_charset(DTMF_CHARS)
1170
        rs = RadioSetting("ani.monitor", "Monitor Code", val)
1171

    
1172
        def apply_code(setting, obj):
1173
            code = []
1174
            for j in range(0, 8):
1175
                try:
1176
                    code.append(DTMF_CHARS.index(str(setting.value)[j]))
1177
                except IndexError:
1178
                    code.append(0xFF)
1179
            obj.monitor = code
1180
        rs.set_apply_callback(apply_code, self._memobj.ani)
1181
        dtmfd.append(rs)
1182

    
1183
        _codeobj = _mem.ani.alarmcode
1184
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
1185
        val = RadioSettingValueString(0, 8, _code, False)
1186
        val.set_charset(DTMF_CHARS)
1187
        rs = RadioSetting("ani.alarm", "Alarm Code", val)
1188

    
1189
        def apply_code(setting, obj):
1190
            code = []
1191
            for j in range(0, 8):
1192
                try:
1193
                    code.append(DTMF_CHARS.index(str(setting.value)[j]))
1194
                except IndexError:
1195
                    code.append(0xFF)
1196
            obj.alarmcode = code
1197
        rs.set_apply_callback(apply_code, self._memobj.ani)
1198
        dtmfd.append(rs)
1199

    
1200
        _codeobj = _mem.ani.stun
1201
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
1202
        val = RadioSettingValueString(0, 8, _code, False)
1203
        val.set_charset(DTMF_CHARS)
1204
        rs = RadioSetting("ani.stun", "Stun Code", val)
1205

    
1206
        def apply_code(setting, obj):
1207
            code = []
1208
            for j in range(0, 8):
1209
                try:
1210
                    code.append(DTMF_CHARS.index(str(setting.value)[j]))
1211
                except IndexError:
1212
                    code.append(0xFF)
1213
            obj.stun = code
1214
        rs.set_apply_callback(apply_code, self._memobj.ani)
1215
        dtmfd.append(rs)
1216

    
1217
        _codeobj = _mem.ani.kill
1218
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
1219
        val = RadioSettingValueString(0, 8, _code, False)
1220
        val.set_charset(DTMF_CHARS)
1221
        rs = RadioSetting("ani.kill", "Kill Code", val)
1222

    
1223
        def apply_code(setting, obj):
1224
            code = []
1225
            for j in range(0, 8):
1226
                try:
1227
                    code.append(DTMF_CHARS.index(str(setting.value)[j]))
1228
                except IndexError:
1229
                    code.append(0xFF)
1230
            obj.kill = code
1231
        rs.set_apply_callback(apply_code, self._memobj.ani)
1232
        dtmfd.append(rs)
1233

    
1234
        _codeobj = _mem.ani.revive
1235
        _code = "".join([DTMF_CHARS[x] for x in _codeobj if int(x) < 0x1F])
1236
        val = RadioSettingValueString(0, 8, _code, False)
1237
        val.set_charset(DTMF_CHARS)
1238
        rs = RadioSetting("ani.revive", "Revive Code", val)
1239

    
1240
        def apply_code(setting, obj):
1241
            code = []
1242
            for j in range(0, 8):
1243
                try:
1244
                    code.append(DTMF_CHARS.index(str(setting.value)[j]))
1245
                except IndexError:
1246
                    code.append(0xFF)
1247
            obj.revive = code
1248
        rs.set_apply_callback(apply_code, self._memobj.ani)
1249
        dtmfd.append(rs)
1250

    
1251
        def apply_dmtf_listvalue(setting, obj):
1252
            LOG.debug("Setting value: " + str(setting.value) + " from list")
1253
            val = str(setting.value)
1254
            index = LIST_DTMF_SPECIAL_DIGITS.index(val)
1255
            val = LIST_DTMF_SPECIAL_VALUES[index]
1256
            obj.set_value(val)
1257

    
1258
        if _mem.ani.groupcode in LIST_DTMF_SPECIAL_VALUES:
1259
            idx = LIST_DTMF_SPECIAL_VALUES.index(_mem.ani.groupcode)
1260
        else:
1261
            idx = LIST_DTMF_SPECIAL_VALUES.index(0x0B)
1262
        rs = RadioSetting("ani.groupcode", "Group Code",
1263
                          RadioSettingValueList(LIST_DTMF_SPECIAL_DIGITS,
1264
                                                LIST_DTMF_SPECIAL_DIGITS[idx]))
1265
        rs.set_apply_callback(apply_dmtf_listvalue, _mem.ani.groupcode)
1266
        dtmfd.append(rs)
1267

    
1268
        if _mem.ani.spacecode in LIST_DTMF_SPECIAL_VALUES:
1269
            idx = LIST_DTMF_SPECIAL_VALUES.index(_mem.ani.spacecode)
1270
        else:
1271
            idx = LIST_DTMF_SPECIAL_VALUES.index(0x0C)
1272
        rs = RadioSetting("ani.spacecode", "Space Code",
1273
                          RadioSettingValueList(LIST_DTMF_SPECIAL_DIGITS,
1274
                                                LIST_DTMF_SPECIAL_DIGITS[idx]))
1275
        rs.set_apply_callback(apply_dmtf_listvalue, _mem.ani.spacecode)
1276
        dtmfd.append(rs)
1277

    
1278
        if _mem.ani.resettime > 0x9F:
1279
            val = 0x4F
1280
        else:
1281
            val = _mem.ani.resettime
1282
        rs = RadioSetting("ani.resettime", "Reset Time",
1283
                          RadioSettingValueList(LIST_RESETTIME,
1284
                                                LIST_RESETTIME[val]))
1285
        dtmfd.append(rs)
1286

    
1287
        if _mem.ani.delayproctime > 0x27:
1288
            val = 0x04
1289
        else:
1290
            val = _mem.ani.delayproctime
1291
        rs = RadioSetting("ani.delayproctime", "Delay Processing Time",
1292
                          RadioSettingValueList(LIST_DELAYPROCTIME,
1293
                                                LIST_DELAYPROCTIME[val]))
1294
        dtmfd.append(rs)
1295

    
1296
        # Service settings
1297
        for band in ["vhf", "vhf2", "uhf"]:
1298
            for index in range(0, 10):
1299
                key = "squelch.%s.sql%i" % (band, index)
1300
                if band == "vhf":
1301
                    _obj = self._memobj.squelch.vhf
1302
                    _name = "VHF"
1303
                elif band == "vhf2":
1304
                    _obj = self._memobj.squelch.vhf2
1305
                    _name = "220"
1306
                elif band == "uhf":
1307
                    _obj = self._memobj.squelch.uhf
1308
                    _name = "UHF"
1309
                val = RadioSettingValueInteger(0, 123,
1310
                                               getattr(_obj, "sql%i" % (
1311
                                                       index)))
1312
                if index == 0:
1313
                    val.set_mutable(False)
1314
                name = "%s Squelch %i" % (_name, index)
1315
                rs = RadioSetting(key, name, val)
1316
                service.append(rs)
1317

    
1318
        return top
1319

    
1320
    @classmethod
1321
    def match_model(cls, filedata, filename):
1322
        match_size = False
1323
        match_model = False
1324

    
1325
        # testing the file data size
1326
        if len(filedata) == 0x200E:
1327
            match_size = True
1328

    
1329
        # testing the firmware model fingerprint
1330
        match_model = model_match(cls, filedata)
1331

    
1332
        if match_size and match_model:
1333
            return True
1334
        else:
1335
            return False
1336

    
1337

    
1338
@directory.register
1339
class MTCUV5R3Radio(UV5X3):
1340
    VENDOR = "MTC"
1341
    MODEL = "UV-5R-3"
1342

    
1343
    _fileid = [UV5R3_fp1, ]
1344

    
1345
    _magic = [MSTRING_UV5R3, ]
1346

    
1347
    VALID_BANDS = [(136000000, 174000000),
1348
                   (200000000, 260000000),
1349
                   (400000000, 521000000)]
(4-4/6)