Project

General

Profile

Bug #9515 » uv5x3_6VFOs_#6.py

MR VFO A/B VHF, MR VFO A/B VHF2, MR VFO A/B UHF - 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", "MR VFO A VHF", val1a)
876
        rs.set_apply_callback(apply_freq, _mem.subvfoa.vhf)
877
        work.append(rs)
878

    
879
        val1b = RadioSettingValueString(0, 10,
880
                                        convert_bytes_to_freq(_mem.subvfob.vhf.freq))
881
        val1b.set_validate_callback(my_vhf_validate)
882
        rs = RadioSetting("subvfob.vhf.freq", "MR VFO B VHF", val1b)
883
        rs.set_apply_callback(apply_freq, _mem.subvfob.vhf)
884
        work.append(rs)
885

    
886
        val1a = RadioSettingValueString(0, 10,
887
                                        convert_bytes_to_freq(_mem.subvfoa.vhf2.freq))
888
        val1a.set_validate_callback(my_vhf2_validate)
889
        rs = RadioSetting("subvfoa.vhf2.freq", "MR VFO A VHF2", val1a)
890
        rs.set_apply_callback(apply_freq, _mem.subvfoa.vhf2)
891
        work.append(rs)
892

    
893
        val1b = RadioSettingValueString(0, 10,
894
                                        convert_bytes_to_freq(_mem.subvfob.vhf2.freq))
895
        val1b.set_validate_callback(my_vhf2_validate)
896
        rs = RadioSetting("subvfob.vhf2.freq", "MR VFO B VHF2", val1b)
897
        rs.set_apply_callback(apply_freq, _mem.subvfob.vhf2)
898
        work.append(rs)
899

    
900
        val1a = RadioSettingValueString(0, 10,
901
                                        convert_bytes_to_freq(_mem.subvfoa.uhf.freq))
902
        val1a.set_validate_callback(my_uhf_validate)
903
        rs = RadioSetting("subvfoa.uhf.freq", "MR VFO A UHF", val1a)
904
        rs.set_apply_callback(apply_freq, _mem.subvfoa.uhf)
905
        work.append(rs)
906

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1316
        return top
1317

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

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

    
1327
        # testing the firmware model fingerprint
1328
        match_model = model_match(cls, filedata)
1329

    
1330
        if match_size and match_model:
1331
            return True
1332
        else:
1333
            return False
1334

    
1335

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

    
1341
    _fileid = [UV5R3_fp1, ]
1342

    
1343
    _magic = [MSTRING_UV5R3, ]
1344

    
1345
    VALID_BANDS = [(136000000, 174000000),
1346
                   (200000000, 260000000),
1347
                   (400000000, 521000000)]
(6-6/6)