Project

General

Profile

Bug #9515 » uv5x3_6VFOs_#2.py

Jim Unroe, 11/21/2021 11:30 AM

 
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
        def apply_freq(setting, obj):
820
            value = chirp_common.parse_freq(str(setting.value)) / 10
821
            for i in range(7, -1, -1):
822
                obj.freq[i] = value % 10
823
                value /= 10
824

    
825
        val1a = RadioSettingValueString(0, 10,
826
                                        convert_bytes_to_freq(_mem.vfo.a.freq))
827
        val1a.set_validate_callback(my_validate)
828
        rs = RadioSetting("vfo.a.freq", "VFO A Frequency", val1a)
829
        rs.set_apply_callback(apply_freq, _mem.vfo.a)
830
        work.append(rs)
831

    
832
        val1b = RadioSettingValueString(0, 10,
833
                                        convert_bytes_to_freq(_mem.vfo.b.freq))
834
        val1b.set_validate_callback(my_validate)
835
        rs = RadioSetting("vfo.b.freq", "VFO B Frequency", val1b)
836
        rs.set_apply_callback(apply_freq, _mem.vfo.b)
837
        work.append(rs)
838

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

    
850
        def my_vhf2_validate(value):
851
            _vhf2_lower = int(_mem.limits.vhf2.lower)
852
            _vhf2_upper = int(_mem.limits.vhf2.upper)
853
            value = chirp_common.parse_freq(value)
854
            msg = ("Must be between %i.0000-%i.9975")
855
            if (_vhf2_upper + 1) * 1000000 <= value or \
856
                    value < _vhf2_lower * 1000000:
857
                raise InvalidValueError(msg % (_vhf2_lower, _vhf2_upper))
858
            return chirp_common.format_freq(value)
859

    
860
        def my_uhf_validate(value):
861
            _uhf_lower = int(_mem.limits.uhf.lower)
862
            _uhf_upper = int(_mem.limits.uhf.upper)
863
            value = chirp_common.parse_freq(value)
864
            msg = ("Must be between %i.0000-%i.9975")
865
            if (_uhf_upper + 1) * 1000000 <= value or \
866
                    value < _uhf_lower * 1000000:
867
                raise InvalidValueError(msg % (_uhf_lower, _uhf_upper))
868
            return chirp_common.format_freq(value)
869

    
870
        val1a = RadioSettingValueString(0, 10,
871
                                        convert_bytes_to_freq(_mem.subvfoa.vhf.freq))
872
        val1a.set_validate_callback(my_vhf_validate)
873
        rs = RadioSetting("subvfoa.vhf.freq", "subVFO A VHF Frequency", val1a)
874
        rs.set_apply_callback(apply_freq, _mem.subvfoa.vhf)
875
        other.append(rs)
876

    
877
        val1a = RadioSettingValueString(0, 10,
878
                                        convert_bytes_to_freq(_mem.subvfoa.vhf2.freq))
879
        val1a.set_validate_callback(my_vhf2_validate)
880
        rs = RadioSetting("subvfoa.vhf2.freq", "subVFO A VHF2 Frequency", val1a)
881
        rs.set_apply_callback(apply_freq, _mem.subvfoa.vhf2)
882
        other.append(rs)
883

    
884
        val1a = RadioSettingValueString(0, 10,
885
                                        convert_bytes_to_freq(_mem.subvfoa.uhf.freq))
886
        val1a.set_validate_callback(my_uhf_validate)
887
        rs = RadioSetting("subvfoa.uhf.freq", "subVFO A UHF Frequency", val1a)
888
        rs.set_apply_callback(apply_freq, _mem.subvfoa.uhf)
889
        other.append(rs)
890

    
891
        val1b = RadioSettingValueString(0, 10,
892
                                        convert_bytes_to_freq(_mem.subvfob.vhf.freq))
893
        val1b.set_validate_callback(my_vhf_validate)
894
        rs = RadioSetting("subvfob.vhf.freq", "subVFO B VHF Frequency", val1b)
895
        rs.set_apply_callback(apply_freq, _mem.subvfob.vhf)
896
        other.append(rs)
897

    
898
        val1b = RadioSettingValueString(0, 10,
899
                                        convert_bytes_to_freq(_mem.subvfob.vhf2.freq))
900
        val1b.set_validate_callback(my_vhf2_validate)
901
        rs = RadioSetting("subvfob.vhf2.freq", "subVFO B VHF2 Frequency", val1b)
902
        rs.set_apply_callback(apply_freq, _mem.subvfob.vhf2)
903
        other.append(rs)
904

    
905
        val1b = RadioSettingValueString(0, 10,
906
                                        convert_bytes_to_freq(_mem.subvfob.uhf.freq))
907
        val1b.set_validate_callback(my_uhf_validate)
908
        rs = RadioSetting("subvfob.uhf.freq", "subVFO B UHF Frequency", val1b)
909
        rs.set_apply_callback(apply_freq, _mem.subvfob.uhf)
910
        other.append(rs)
911
        ##########
912

    
913
        rs = RadioSetting("vfo.a.sftd", "VFO A Shift",
914
                          RadioSettingValueList(
915
                              LIST_SHIFTD, LIST_SHIFTD[_mem.vfo.a.sftd]))
916
        work.append(rs)
917

    
918
        rs = RadioSetting("vfo.b.sftd", "VFO B Shift",
919
                          RadioSettingValueList(
920
                              LIST_SHIFTD, LIST_SHIFTD[_mem.vfo.b.sftd]))
921
        work.append(rs)
922

    
923
        def convert_bytes_to_offset(bytes):
924
            real_offset = 0
925
            for byte in bytes:
926
                real_offset = (real_offset * 10) + byte
927
            return chirp_common.format_freq(real_offset * 1000)
928

    
929
        def apply_offset(setting, obj):
930
            value = chirp_common.parse_freq(str(setting.value)) / 1000
931
            for i in range(5, -1, -1):
932
                obj.offset[i] = value % 10
933
                value /= 10
934

    
935
        val1a = RadioSettingValueString(
936
                    0, 10, convert_bytes_to_offset(_mem.vfo.a.offset))
937
        rs = RadioSetting("vfo.a.offset",
938
                          "VFO A Offset", val1a)
939
        rs.set_apply_callback(apply_offset, _mem.vfo.a)
940
        work.append(rs)
941

    
942
        val1b = RadioSettingValueString(
943
                    0, 10, convert_bytes_to_offset(_mem.vfo.b.offset))
944
        rs = RadioSetting("vfo.b.offset",
945
                          "VFO B Offset", val1b)
946
        rs.set_apply_callback(apply_offset, _mem.vfo.b)
947
        work.append(rs)
948

    
949
        rs = RadioSetting("vfo.a.txpower", "VFO A Power",
950
                          RadioSettingValueList(
951
                              LIST_TXPOWER,
952
                              LIST_TXPOWER[_mem.vfo.a.txpower]))
953
        work.append(rs)
954

    
955
        rs = RadioSetting("vfo.b.txpower", "VFO B Power",
956
                          RadioSettingValueList(
957
                              LIST_TXPOWER,
958
                              LIST_TXPOWER[_mem.vfo.b.txpower]))
959
        work.append(rs)
960

    
961
        rs = RadioSetting("vfo.a.widenarr", "VFO A Bandwidth",
962
                          RadioSettingValueList(
963
                              LIST_BANDWIDTH,
964
                              LIST_BANDWIDTH[_mem.vfo.a.widenarr]))
965
        work.append(rs)
966

    
967
        rs = RadioSetting("vfo.b.widenarr", "VFO B Bandwidth",
968
                          RadioSettingValueList(
969
                              LIST_BANDWIDTH,
970
                              LIST_BANDWIDTH[_mem.vfo.b.widenarr]))
971
        work.append(rs)
972

    
973
        rs = RadioSetting("vfo.a.scode", "VFO A S-CODE",
974
                          RadioSettingValueList(
975
                              LIST_SCODE,
976
                              LIST_SCODE[_mem.vfo.a.scode]))
977
        work.append(rs)
978

    
979
        rs = RadioSetting("vfo.b.scode", "VFO B S-CODE",
980
                          RadioSettingValueList(
981
                              LIST_SCODE,
982
                              LIST_SCODE[_mem.vfo.b.scode]))
983
        work.append(rs)
984

    
985
        rs = RadioSetting("vfo.a.step", "VFO A Tuning Step",
986
                          RadioSettingValueList(
987
                              LIST_STEP, LIST_STEP[_mem.vfo.a.step]))
988
        work.append(rs)
989
        rs = RadioSetting("vfo.b.step", "VFO B Tuning Step",
990
                          RadioSettingValueList(
991
                              LIST_STEP, LIST_STEP[_mem.vfo.b.step]))
992
        work.append(rs)
993

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

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

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

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

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

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

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

    
1061
        rs = RadioSetting("ani.aniid", "When to send ANI ID",
1062
                          RadioSettingValueList(LIST_PTTID,
1063
                                                LIST_PTTID[_mem.ani.aniid]))
1064
        dtmfe.append(rs)
1065

    
1066
        # DTMF decode settings
1067
        rs = RadioSetting("ani.mastervice", "Master and Vice ID",
1068
                          RadioSettingValueBoolean(_mem.ani.mastervice))
1069
        dtmfd.append(rs)
1070

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

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

    
1088
        rs = RadioSetting("ani.minspection", "Master Inspection",
1089
                          RadioSettingValueBoolean(_mem.ani.minspection))
1090
        dtmfd.append(rs)
1091

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

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

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

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

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

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

    
1125
        rs = RadioSetting("ani.vinspection", "Vice Inspection",
1126
                          RadioSettingValueBoolean(_mem.ani.vinspection))
1127
        dtmfd.append(rs)
1128

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1247
        def apply_dmtf_listvalue(setting, obj):
1248
            LOG.debug("Setting value: " + str(setting.value) + " from list")
1249
            val = str(setting.value)
1250
            index = LIST_DTMF_SPECIAL_DIGITS.index(val)
1251
            val = LIST_DTMF_SPECIAL_VALUES[index]
1252
            obj.set_value(val)
1253

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

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

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

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

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

    
1314
        return top
1315

    
1316
    @classmethod
1317
    def match_model(cls, filedata, filename):
1318
        match_size = False
1319
        match_model = False
1320

    
1321
        # testing the file data size
1322
        if len(filedata) == 0x200E:
1323
            match_size = True
1324

    
1325
        # testing the firmware model fingerprint
1326
        match_model = model_match(cls, filedata)
1327

    
1328
        if match_size and match_model:
1329
            return True
1330
        else:
1331
            return False
1332

    
1333

    
1334
@directory.register
1335
class MTCUV5R3Radio(UV5X3):
1336
    VENDOR = "MTC"
1337
    MODEL = "UV-5R-3"
1338

    
1339
    _fileid = [UV5R3_fp1, ]
1340

    
1341
    _magic = [MSTRING_UV5R3, ]
1342

    
1343
    VALID_BANDS = [(136000000, 174000000),
1344
                   (200000000, 260000000),
1345
                   (400000000, 521000000)]
(2-2/6)