Project

General

Profile

New Model #9489 » kg935g MRT test b1.4.py

Mel Terechenok, 08/01/2022 07:34 PM

 
1
# MRT Beta 1.4 - updated User Interface to support settings modifications through the settings tab
2
# melvin.terechenok@gmail.com
3

    
4
# MRT 935G BETA1.3 - Update to handle 935G
5
# MRT Mapped most Wouxon CPS settings in Chirp
6
# MRT Upload to Radio and Download from Radio are working
7
# MRT Settings are available under the Browser tab in Hex/Dec/Bin format
8
# MRT No limits or error checking is done on values entered
9
# MRT Incorrect/Invalid values may cause radio malfunctions
10

    
11

    
12

    
13
# Copyright 2019 Pavel Milanes CO7WT <pavelmc@gmail.com>
14
#
15
# Based on the work of Krystian Struzik <toner_82@tlen.pl>
16
# who figured out the crypt used and made possible the
17
# Wuoxun KG-UV8D Plus driver, in which this work is based.
18
#
19
# This program is free software: you can redistribute it and/or modify
20
# it under the terms of the GNU General Public License as published by
21
# the Free Software Foundation, either version 3 of the License, or
22
# (at your option) any later version.
23
#
24
# This program is distributed in the hope that it will be useful,
25
# but WITHOUT ANY WARRANTY; without even the implied warranty of
26
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27
# GNU General Public License for more details.
28
#
29
# You should have received a copy of the GNU General Public License
30
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
31

    
32
"""Wouxun KG-935G radio management module"""
33

    
34
import time
35
import os
36
import logging
37
from chirp import util, chirp_common, bitwise, memmap, errors, directory
38
from chirp.settings import RadioSetting, RadioSettingGroup, \
39
    RadioSettingValueBoolean, RadioSettingValueList, \
40
    RadioSettingValueInteger, RadioSettingValueString, \
41
    RadioSettings
42

    
43

    
44
LOG = logging.getLogger(__name__)
45

    
46
CMD_ID = 128    # \x80
47
CMD_END = 129   # \x81
48
CMD_RD = 130    # \82
49
CMD_WR = 131    # \83
50

    
51
MEM_VALID = 158
52

    
53
AB_LIST = ["A", "B"]
54
STEPS = [2.5, 5.0, 6.25, 10.0, 12.5, 25.0, 50.0, 100.0]
55
STEP_LIST = [str(x) for x in STEPS]
56
ROGER_LIST = ["Off", "Begin", "End", "Both"]
57
TIMEOUT_LIST = ["Off"] + [str(x) + "s" for x in range(15, 901, 15)]
58
VOX_LIST = ["Off"] + ["%s" % x for x in range(1, 10)]
59
BANDWIDTH_LIST = ["Narrow", "Wide"]
60
VOICE_LIST = ["Off", "On"]
61
LANGUAGE_LIST = ["Chinese", "English"]
62
SCANMODE_LIST = ["TO", "CO", "SE"]
63
#MRT - EDIT FOR 935G
64
PFKEYLONG_LIST = ["undef", "FRQ2-PTT", "Selec Call", "Scan", "Flashlight", "Alarm", "SOS", "FM Radio", "Moni", "Strobe", "Weather", "Tlk A", "Reverse", "CTC Scan", "DCS Scan", "BRT"]
65
PFKEYSHORT_LIST = ["undef", "Scan", "Flashlight", "Alarm", "SOS", "FM Radio", "Moni", "Strobe", "Weather", "Tlk A", "Reverse", "CTC Scan", "DCS Scan", "BRT"]
66
#
67
WORKMODE_LIST = ["VFO", "Ch.Number.", "Ch.Freq.", "Ch.Name"]
68
BACKLIGHT_LIST = ["Always On"] + [str(x) + "s" for x in range(1, 21)] + \
69
    ["Always Off"]
70
OFFSET_LIST = ["+", "-"]
71
PONMSG_LIST = ["MSG - Bitmap", "Battery Volts"]
72
SPMUTE_LIST = ["QT", "QT+DTMF", "QT*DTMF"]
73
DTMFST_LIST = ["OFF", "DTMF", "ANI", "DTMF+ANI"]
74
DTMF_TIMES = [str(x) + "ms" for x in range(0, 501, 10)]
75
RPTSET_LIST = ["", "X-DIRRPT", "X-TWRPT"] # TODO < what is index 0?
76
ALERTS = [1750, 2100, 1000, 1450]
77
ALERTS_LIST = [str(x) for x in ALERTS]
78
PTTID_LIST = ["BOT", "EOT", "Both"]
79
LIST_10 = ["Off"] + ["%s" % x for x in range(1, 11)]
80
SCANGRP_LIST = ["All"] + ["%s" % x for x in range(1, 11)]
81
SCQT_LIST = ["Decoder", "Encoder", "All"]
82
SMUTESET_LIST = ["Off", "Tx", "Rx", "Tx+Rx"]
83
POWER_LIST = ["Lo", "Mid", "Hi"]
84
HOLD_TIMES = ["Off"] + ["%s" % x for x in range(100, 5001, 100)]
85
RPTMODE_LIST = ["Radio", "Repeater"]
86
#MRT ADDED NEW LISTS
87
THEME_LIST = ["White-1", "White-2", "Black-1", "Black-2"]
88
DSPBRTSBY_LIST = ["OFF", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
89
DSPBRTACT_LIST = ["OFF-DO NOT USE", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
90
TONESCANSAVELIST= ["Rx", "Tx", "Tx/Rx"]
91
PTTDELAY_LIST = [str(x) + "ms" for x in range(0, 3001, 100)]
92
SCRAMBLE_LIST = ["OFF"] + [str(x) for x in range(1,9)]
93

    
94
# memory slot 0 is not used, start at 1 (so need 1000 slots, not 999)
95
# structure elements whose name starts with x are currently unidentified
96

    
97
# MRT made Power = 2 bits to handle 935G's 3 power levels
98
# MRT beta 1.3 - updates to structure to match KG935G Custom programming SW configuration settings, FM Radio presets, Key Settings
99
# MRT beta 1.4 - modified some value names and merged FM Radio memories with other settings to resolve errors in UI implementation
100
_MEM_FORMAT = """
101
    #seekto 0x0044;
102
    struct {
103
        u32    rx_start;
104
        u32    rx_stop;
105
        u32    tx_start;
106
        u32    tx_stop;
107
    } uhf_limits;
108

    
109
    #seekto 0x0054;
110
    struct {
111
        u32    rx_start;
112
        u32    rx_stop;
113
        u32    tx_start;
114
        u32    tx_stop;
115
    } vhf_limits;
116

    
117
    #seekto 0x0400;
118
    struct {
119
        char     oem1[8];
120
        char     unknown[2];
121
        u8     unknown2[10];
122
        u8     unknown3[10];
123
        u8     unknown4[8];
124
        char     oem2[10];
125
        u8     version[6];
126
        char     date[8];
127
        u8     unknown5[2];
128
        char     model[8];     
129
    } oem_info;
130

    
131
    #seekto 0x0480;
132
    struct {
133
        u16    Group_1_lower;
134
        u16    Group_1_upper;
135
        u16    Group_2_lower;
136
        u16    Group_2_upper;
137
        u16    Group_3_lower;
138
        u16    Group_3_upper;
139
        u16    Group_4_lower;
140
        u16    Group_4_upper;
141
        u16    Group_5_lower;
142
        u16    Group_5_upper;
143
        u16    Group_6_lower;
144
        u16    Group_6_upper;
145
        u16    Group_7_lower;
146
        u16    Group_7_upper;
147
        u16    Group_8_lower;
148
        u16    Group_8_upper;
149
        u16    Group_9_lower;
150
        u16    Group_9_upper;
151
        u16    Group_10_lower;
152
        u16    Group_10_upper;
153
    } scan_groups;
154

    
155
    #seekto 0x0500;
156
    struct {
157
        u8    call_code_1[6];
158
        u8    call_code_2[6];
159
        u8    call_code_3[6];
160
        u8    call_code_4[6];
161
        u8    call_code_5[6];
162
        u8    call_code_6[6];
163
        u8    call_code_7[6];
164
        u8    call_code_8[6];
165
        u8    call_code_9[6];
166
        u8    call_code_10[6];
167
        u8    call_code_11[6];
168
        u8    call_code_12[6];
169
        u8    call_code_13[6];
170
        u8    call_code_14[6];
171
        u8    call_code_15[6];
172
        u8    call_code_16[6];
173
        u8    call_code_17[6];
174
        u8    call_code_18[6];
175
        u8    call_code_19[6];
176
        u8    call_code_20[6];
177
    } call_groups;
178

    
179
    #seekto 0x0580;
180
    struct {
181
        char    call_name1[6];
182
        char    call_name2[6];
183
        char    call_name3[6];
184
        char    call_name4[6];
185
        char    call_name5[6];
186
        char    call_name6[6];
187
        char    call_name7[6];
188
        char    call_name8[6];
189
        char    call_name9[6];
190
        char    call_name10[6];
191
        char    call_name11[6];
192
        char    call_name12[6];
193
        char    call_name13[6];
194
        char    call_name14[6];
195
        char    call_name15[6];
196
        char    call_name16[6];
197
        char    call_name17[6];
198
        char    call_name18[6];
199
        char    call_name19[6];
200
        char    call_name20[6];
201
    } call_names;
202

    
203

    
204
    #seekto 0x0600;
205
    struct {
206
        u16    FM_radio1;
207
        u16    FM_radio2;
208
        u16    FM_radio3;
209
        u16    FM_radio4;
210
        u16    FM_radio5;
211
        u16    FM_radio6;
212
        u16    FM_radio7;
213
        u16    FM_radio8;
214
        u16    FM_radio9;
215
        u16    FM_radio10;
216
        u16    FM_radio11;
217
        u16    FM_radio12;
218
        u16    FM_radio13;
219
        u16    FM_radio14;
220
        u16    FM_radio15;
221
        u16    FM_radio16;
222
        u16    FM_radio17;
223
        u16    FM_radio18;
224
        u16    FM_radio19;
225
        u16    FM_radio20;
226
        u16 unknown_pad_x0640[235];
227
        u8 unknown07fe;
228
        u8 unknown07ff;
229
        u8      ponmsg;
230
        char    dispstr[15];
231
        u8 unknown0810;
232
        u8 unknown0811;
233
        u8 unknown0812;
234
        u8 unknown0813;
235
        u8 unknown0814;
236
        u8      voice;
237
        u8      timeout;
238
        u8      toalarm;
239
        u8      channel_menu;
240
        u8      power_save;
241
        u8      autolock;
242
        u8      keylock;
243
        u8      beep;
244
        u8      stopwatch;
245
        u8      vox;
246
        u8      scan_rev;
247
        u8      backlight;
248
        u8      roger_beep;
249
        char      node_sw_pwd[6];
250
        char      reset_pwd[6];
251
        u8 unknown082e;
252
        u8      pri_ch;
253
        u8      ani_sw;
254
        u8      ptt_delay;
255
        u8      ani_code[6];
256
        u8      dtmf_st;
257
        u8      BCL_A;
258
        u8      BCL_B;
259
        u8      ptt_id;
260
        u8      prich_sw;
261
        u8 unknown083d;
262
        u8 unknown083e;
263
        u8 unknown083f;
264
        u8      alert;
265
        u8      pf1_shrt;
266
        u8      pf1_long;
267
        u8      pf2_shrt;
268
        u8      pf2_long;
269
        u8 unknown0845;
270
        u8      work_mode_a;
271
        u8      work_mode_b;
272
        u8      dtmf_tx_time;
273
        u8      dtmf_interval;
274
        u8      main_band;
275
        u8 unknown084b;
276
        u8      work_ch_a;
277
        u8 unknown084d;
278
        u8      work_ch_b;
279
        u8 unknown084f;
280
        u8 unknown0850;
281
        u8 unknown0851;
282
        u8 unknown0852;
283
        u8 unknown0853;
284
        u8 unknown0854;
285
        u8 unknown0855;
286
        u8 unknown0856;
287
        u8 unknown0857;
288
        u8 unknown0858;
289
        u8 unknown0859;
290
        u8 unknown085a;
291
        u8 unknown085b;
292
        u8 unknown085c;
293
        u8 unknown085d;
294
        u8 unknown085e;
295
        u8 unknown085f;
296
        u8 unknown0860;
297
        u8      TDR_single_mode;
298
        u8      ring_time;
299
        u8      ScnGrpA_Act;
300
        u8      ScnGrpB_Act;
301
        u8 unknown0865;
302
        u8      rpt_tone;
303
        u8 unknown0867;
304
        u8      scan_det;
305
        u8      ToneScnSave;
306
        u8 unknown086a;
307
        u8      smuteset;
308
        u8 unknown086c;
309
        u8      DspBrtAct;
310
        u8      DspBrtSby;
311
        u8 unknown086f;
312
        u8      theme;
313
        u8      wxalert;
314
        u8      VFO_repeater_a;
315
        u8      VFO_repeater_b;
316
        u8 unknown0874;
317
        u8 unknown0875;
318
        u8 unknown0876;
319
        u8 unknown0877;
320
        u8 unknown0878;
321
        u8 unknown0879;
322
        u8 unknown087a;
323
        u8 unknown087b;
324
        u8 unknown087c;
325
        u8 unknown087d;
326
        u8 unknown087e;
327
        u8 unknown087f;
328
    } settings;
329

    
330
    #seekto 0x0880;
331
    struct {
332
        u32     rxfreq;
333
        u32     unknown0;
334
        u16     rxtone;
335
        u16     txtone;
336
        u8      scrambler:4,
337
                unknown1:2,
338
                power:2; 
339
        u8      unknown3:1,
340
                unknown5:2
341
                unknown4:1,
342
                compander:1,
343
                mute_mode:2,
344
                iswide:1;
345
        u8      step;
346
        u8      squelch;
347
      } vfoa;
348

    
349
    #seekto 0x08c0;
350
    struct {
351
        u32     rxfreq;
352
        u32     unknown0;
353
        u16     rxtone;
354
        u16     txtone;
355
        u8      scrambler:4,
356
                unknown1:2,
357
                power:2; 
358
        u8      unknown3:1,
359
                unknown5:2
360
                unknown4:1,
361
                compander:1,
362
                mute_mode:2,
363
                iswide:1;
364
        u8      step;
365
        u8      squelch;
366
    } vfob;
367

    
368
    #seekto 0x0900;
369
    struct {
370
        u32     rxfreq;
371
        u32     txfreq;
372
        u16     rxtone;
373
        u16     txtone;
374
        u8      scrambler:4,
375
                unknown1:2,
376
                power:2; 
377
        u8      unknown3:2,
378
                scan_add:1,
379
                unknown4:1,
380
                compander:1,
381
                mute_mode:2,
382
                iswide:1;
383
        u16     padding;
384
    } memory[1000];
385

    
386
    #seekto 0x4780;
387
    struct {
388
        u8    name[8];
389
                u8    unknown[4];
390
    } names[1000];
391

    
392
    #seekto 0x7670;
393
    u8          valid[1000];
394
    """
395

    
396
    # Support for the Wouxun KG-935G radio
397
    # Serial coms are at 19200 baud
398
    # The data is passed in variable length records
399
    # Record structure:
400
    #  Offset   Usage
401
    #    0      start of record (\x7c)
402
    #    1      Command (\x80 Identify \x81 End/Reboot \x82 Read \x83 Write)
403
    #    2      direction (\xff PC-> Radio, \x00 Radio -> PC)
404
    #    3      length of payload (excluding header/checksum) (n)
405
    #    4      payload (n bytes)
406
    #    4+n+1  checksum - byte sum (% 256) of bytes 1 -> 4+n
407
    #
408
    # Memory Read Records:
409
    # the payload is 3 bytes, first 2 are offset (big endian),
410
    # 3rd is number of bytes to read
411
    # Memory Write Records:
412
    # the maximum payload size (from the Wouxun software) seems to be 66 bytes
413
    #  (2 bytes location + 64 bytes data).
414

    
415
#MRT 1.2 correct spelling of Wouxon
416
class KGUV8TRadio(chirp_common.Alias):
417
    VENDOR = "Wouxun"
418
    MODEL = "KG-935G"
419

    
420
@directory.register
421
class KG935GRadio(chirp_common.CloneModeRadio,
422
                  chirp_common.ExperimentalRadio):
423

    
424
    """Wouxun KG-935G"""
425
    VENDOR = "Wouxun"
426
    MODEL = "KG-935G"
427
    _model = "KG-UV8D-B"
428
    _file_ident = "935G"
429
    BAUD_RATE = 19200
430
# MRT - Added Medium Power level for 935G support
431
    POWER_LEVELS = [chirp_common.PowerLevel("L", watts=0.5),
432
                    chirp_common.PowerLevel("M", watts=4.5),
433
                    chirp_common.PowerLevel("H", watts=5.5)]
434
    _mmap = ""
435
    ALIASES = [KGUV8TRadio,]
436

    
437
    def _checksum(self, data):
438
        cs = 0
439
        for byte in data:
440
            cs += ord(byte)
441
        return chr(cs % 256)
442

    
443
    def _write_record(self, cmd, payload = None):
444
        # build the packet
445
        _header = '\x7c' + chr(cmd) + '\xff'
446

    
447
        _length = 0
448
        if payload:
449
            _length = len(payload)
450

    
451
        # update the length field
452
        _header += chr(_length)
453

    
454
        if payload:
455
            # calculate checksum then add it with the payload to the packet and encrypt
456
            crc = self._checksum(_header[1:] + payload)
457
            payload += crc
458
            _header += self.encrypt(payload)
459
        else:
460
            # calculate and add encrypted checksum to the packet
461
            crc = self._checksum(_header[1:])
462
            _header += self.strxor(crc, '\x57')
463

    
464
        try:
465
            self.pipe.write(_header)
466
        except Exception, e:
467
            raise errors.RadioError("Failed to communicate with radio: %s" % e)
468

    
469
    def _read_record(self):
470
        # read 4 chars for the header
471
        _header = self.pipe.read(4)
472
        if len(_header) != 4:
473
            raise errors.RadioError('Radio did not respond')
474
        _length = ord(_header[3])
475
        _packet = self.pipe.read(_length)
476
        _rcs_xor = _packet[-1]
477
        _packet = self.decrypt(_packet)
478
        _cs = ord(self._checksum(_header[1:] + _packet))
479
        # read the checksum and decrypt it
480
        _rcs = ord(self.strxor(self.pipe.read(1), _rcs_xor))
481
        return (_rcs != _cs, _packet)
482

    
483
    def decrypt(self, data):
484
        result = ''
485
        for i in range(len(data)-1, 0, -1):
486
            result += self.strxor(data[i], data[i - 1])
487
        result += self.strxor(data[0], '\x57')
488
        return result[::-1]
489

    
490
    def encrypt(self, data):
491
        result = self.strxor('\x57', data[0])
492
        for i in range(1, len(data), 1):
493
            result += self.strxor(result[i - 1], data[i])
494
        return result
495

    
496
    def strxor (self, xora, xorb):
497
        return chr(ord(xora) ^ ord(xorb))
498

    
499
    # Identify the radio
500
    #
501
    # A Gotcha: the first identify packet returns a bad checksum, subsequent
502
    # attempts return the correct checksum... (well it does on my radio!)
503
    #
504
    # The ID record returned by the radio also includes the current frequency range
505
    # as 4 bytes big-endian in 10Hz increments
506
    #
507
    # Offset
508
    #  0:10     Model, zero padded (Looks for 'KG-UV8D-B')
509

    
510
    @classmethod
511
    def match_model(cls, filedata, filename):
512
        id = cls._file_ident 
513
        return cls._file_ident in filedata[0x426:0x430]
514

    
515
    def _identify(self):
516
        """Do the identification dance"""
517
        for _i in range(0, 10):
518
            self._write_record(CMD_ID)
519
            _chksum_err, _resp = self._read_record()
520
            LOG.debug("Got:\n%s" % util.hexprint(_resp))
521
            if _chksum_err:
522
                LOG.error("Checksum error: retrying ident...")
523
                time.sleep(0.100)
524
                continue
525
            LOG.debug("Model %s" % util.hexprint(_resp[0:9]))
526
            if _resp[0:9] == self._model:
527
                return
528
            if len(_resp) == 0:
529
                raise Exception("Radio not responding")
530
            else:
531
                raise Exception("Unable to identify radio")
532

    
533
    def _finish(self):
534
        self._write_record(CMD_END)
535

    
536
    def process_mmap(self):
537
        self._memobj = bitwise.parse(_MEM_FORMAT, self._mmap)
538

    
539
    def sync_in(self):
540
        try:
541
            self._mmap = self._download()
542
        except errors.RadioError:
543
            raise
544
        except Exception, e:
545
            raise errors.RadioError("Failed to communicate with radio: %s" % e)
546
        self.process_mmap()
547

    
548
    def sync_out(self):
549
        self._upload()
550

    
551
    # TODO: Load all memory.
552
    # It would be smarter to only load the active areas and none of
553
    # the padding/unused areas. Padding still need to be investigated.
554
    def _download(self):
555
        """Talk to a wouxun KG-935G and do a download"""
556
        try:
557
            self._identify()
558
            return self._do_download(0, 32768, 64)
559
        except errors.RadioError:
560
            raise
561
        except Exception, e:
562
            LOG.exception('Unknown error during download process')
563
            raise errors.RadioError("Failed to communicate with radio: %s" % e)
564

    
565
    def _do_download(self, start, end, blocksize):
566
        # allocate & fill memory
567
        image = ""
568
        for i in range(start, end, blocksize):
569
            req = chr(i / 256) + chr(i % 256) + chr(blocksize)
570
            self._write_record(CMD_RD, req)
571
            cs_error, resp = self._read_record()
572
            if cs_error:
573
                LOG.debug(util.hexprint(resp))
574
                raise Exception("Checksum error on read")
575
            # LOG.debug("Got:\n%s" % util.hexprint(resp))
576
            image += resp[2:]
577
            if self.status_fn:
578
                status = chirp_common.Status()
579
                status.cur = i
580
                status.max = end
581
                status.msg = "Cloning from radio"
582
                self.status_fn(status)
583
        self._finish()
584
        return memmap.MemoryMap(''.join(image))
585

    
586
    def _upload(self):
587
        """Talk to a wouxun KG-935G and do a upload"""
588
        try:
589
            self._identify()
590
            self._do_upload(0, 32768, 64)
591
        except errors.RadioError:
592
            raise
593
        except Exception, e:
594
            raise errors.RadioError("Failed to communicate with radio: %s" % e)
595
        return
596

    
597
    def _do_upload(self, start, end, blocksize):
598
        ptr = start
599
        for i in range(start, end, blocksize):
600
            req = chr(i / 256) + chr(i % 256)
601
            chunk = self.get_mmap()[ptr:ptr + blocksize]
602
            self._write_record(CMD_WR, req + chunk)
603
            LOG.debug(util.hexprint(req + chunk))
604
            cserr, ack = self._read_record()
605
            LOG.debug(util.hexprint(ack))
606
            j = ord(ack[0]) * 256 + ord(ack[1])
607
            if cserr or j != ptr:
608
                raise Exception("Radio did not ack block %i" % ptr)
609
            ptr += blocksize
610
            if self.status_fn:
611
                status = chirp_common.Status()
612
                status.cur = i
613
                status.max = end
614
                status.msg = "Cloning to radio"
615
                self.status_fn(status)
616
        self._finish()
617

    
618
    def get_features(self):
619
        rf = chirp_common.RadioFeatures()
620
        rf.has_settings = True
621
        rf.has_ctone = True
622
        rf.has_rx_dtcs = True
623
        rf.has_cross = True
624
        rf.has_tuning_step = False
625
        rf.has_bank = False
626
        rf.can_odd_split = True
627
        rf.valid_skips = ["", "S"]
628
        rf.valid_tmodes = ["", "Tone", "TSQL", "DTCS", "Cross"]
629
        rf.valid_cross_modes = [
630
            "Tone->Tone",
631
            "Tone->DTCS",
632
            "DTCS->Tone",
633
            "DTCS->",
634
            "->Tone",
635
            "->DTCS",
636
            "DTCS->DTCS",
637
        ]
638
        rf.valid_modes = ["FM", "NFM"]
639
        rf.valid_power_levels = self.POWER_LEVELS
640
        rf.valid_name_length = 8
641
        rf.valid_duplexes = ["", "-", "+", "split", "off"]
642
        rf.valid_bands = [(137000000, 175000000),  # supports 2m
643
                          (400000000, 480000000)]  # supports 70cm
644
        rf.valid_characters = chirp_common.CHARSET_ASCII
645
        rf.memory_bounds = (1, 999)  # 999 memories
646
        rf.valid_tuning_steps = STEPS
647
        return rf
648

    
649
    @classmethod
650
    def get_prompts(cls):
651
        rp = chirp_common.RadioPrompts()
652
        rp.experimental = \
653
            ('This driver is experimental.\n'
654
             '\n'
655
             'Please keep a copy of your memories with the original Wouxon CPS software '
656
             'if you treasure them, this driver is new and may contain bugs.\n'
657
             '\n'
658
             ' Upload and Download from/to the Radio are working\n'
659
             ' '
660
             ' User interface has been added. \n Most of the settings from the Wouxon Custom Programming'
661
             ' software have been mapped\n in addition to some bonus settings that were'
662
             ' found.\n'
663
             ' Changing the VHF/UHF Rx limits does appear to work - but radio performance\n'
664
             ' is not guaranteed-  and may void warranty or cause radio to malfunction.\n'
665
             ' You can also customize the bottom banner from the OEMINFO Model setting\n'
666
                          ' \n'
667
             ' There are no limits/error checking done on the settings when using the Browser tab.\n'
668
             ' \n'
669
             ' Incorrect/Illegal values for a setting may cause radio malfunctions\n'
670
             ' USE AT YOUR OWN RISK\n'
671
             '\n'
672
             )
673
        return rp
674

    
675
    def get_raw_memory(self, number):
676
        return repr(self._memobj.memory[number])
677
# MRT - corrected the Polarity decoding to match 935G implementation use 0x2000 bit mask for R
678
# MRT - 0x2000 appears to be the bit mask for Inverted DCS tones
679
# MRT - n DCS Tone will be 0x4xxx values - i DCS Tones will be 0x6xxx values.
680
# MRT - Chirp Uses N for n DCS Tones and R for i DCS Tones
681
    def _get_tone(self, _mem, mem):
682
        def _get_dcs(val):
683
            code = int("%03o" % (val & 0x07FF))
684
            pol = (val & 0x2000) and "R" or "N"
685
            return code, pol
686
# MRT - Modified the function below to bitwise AND with 0x4000 to check for 935G DCS Tone decoding
687
# MRT 0x4000 appears to be the bit mask for DCS tones
688
        tpol = False
689
# MRT Beta 1.1 - Fix the txtone compare to 0x4000 - was rxtone.
690
        if _mem.txtone != 0xFFFF and (_mem.txtone & 0x4000) == 0x4000:
691
            tcode, tpol = _get_dcs(_mem.txtone)
692
            mem.dtcs = tcode
693
            txmode = "DTCS"
694
        elif _mem.txtone != 0xFFFF and _mem.txtone != 0x0:
695
            mem.rtone = (_mem.txtone & 0x7fff) / 10.0
696
            txmode = "Tone"
697
        else:
698
            txmode = ""
699
# MRT - Modified the function below to bitwise AND with 0x4000 to check for 935G DCS Tone decoding
700
        rpol = False
701
        if _mem.rxtone != 0xFFFF and (_mem.rxtone & 0x4000) == 0x4000:
702
            rcode, rpol = _get_dcs(_mem.rxtone)
703
            mem.rx_dtcs = rcode
704
            rxmode = "DTCS"
705
        elif _mem.rxtone != 0xFFFF and _mem.rxtone != 0x0:
706
            mem.ctone = (_mem.rxtone & 0x7fff) / 10.0
707
            rxmode = "Tone"
708
        else:
709
            rxmode = ""
710

    
711
        if txmode == "Tone" and not rxmode:
712
            mem.tmode = "Tone"
713
        elif txmode == rxmode and txmode == "Tone" and mem.rtone == mem.ctone:
714
            mem.tmode = "TSQL"
715
        elif txmode == rxmode and txmode == "DTCS" and mem.dtcs == mem.rx_dtcs:
716
            mem.tmode = "DTCS"
717
        elif rxmode or txmode:
718
            mem.tmode = "Cross"
719
            mem.cross_mode = "%s->%s" % (txmode, rxmode)
720

    
721
        # always set it even if no dtcs is used
722
        mem.dtcs_polarity = "%s%s" % (tpol or "N", rpol or "N")
723

    
724
        LOG.debug("Got TX %s (%i) RX %s (%i)" %
725
                  (txmode, _mem.txtone, rxmode, _mem.rxtone))
726

    
727
    def get_memory(self, number):
728
        _mem = self._memobj.memory[number]
729
        _nam = self._memobj.names[number]
730

    
731
        mem = chirp_common.Memory()
732
        mem.number = number
733
        _valid = self._memobj.valid[mem.number]
734
        LOG.debug("%d %s", number, _valid == MEM_VALID)
735
        if _valid != MEM_VALID:
736
            mem.empty = True
737
            return mem
738
        else:
739
            mem.empty = False
740

    
741
        mem.freq = int(_mem.rxfreq) * 10
742

    
743
        if _mem.txfreq == 0xFFFFFFFF:
744
            # TX freq not set
745
            mem.duplex = "off"
746
            mem.offset = 0
747
        elif int(_mem.rxfreq) == int(_mem.txfreq):
748
            mem.duplex = ""
749
            mem.offset = 0
750
        elif abs(int(_mem.rxfreq) * 10 - int(_mem.txfreq) * 10) > 70000000:
751
            mem.duplex = "split"
752
            mem.offset = int(_mem.txfreq) * 10
753
        else:
754
            mem.duplex = int(_mem.rxfreq) > int(_mem.txfreq) and "-" or "+"
755
            mem.offset = abs(int(_mem.rxfreq) - int(_mem.txfreq)) * 10
756

    
757
        for char in _nam.name:
758
            if char != 0:
759
                mem.name += chr(char)
760
        mem.name = mem.name.rstrip()
761

    
762
        self._get_tone(_mem, mem)
763

    
764
        mem.skip = "" if bool(_mem.scan_add) else "S"
765

    
766
        mem.power = self.POWER_LEVELS[_mem.power]
767
        mem.mode = _mem.iswide and "FM" or "NFM"
768
        return mem
769

    
770
    def _set_tone(self, mem, _mem):
771
        def _set_dcs(code, pol):
772
#MRT Change from + 0x2800 to bitwise OR with 0x4000 to set the bit for DCS
773
            val = int("%i" % code, 8) | 0x4000
774
            if pol == "R":
775
#MRT Change to 0x2000 from 0x8000 to set the bit for i/R polarity
776
               val += 0x2000
777
            return val
778

    
779
        rx_mode = tx_mode = None
780
        rxtone = txtone = 0x0000
781

    
782
        if mem.tmode == "Tone":
783
            tx_mode = "Tone"
784
            rx_mode = None
785
            txtone = int(mem.rtone * 10) + 0x8000
786
        elif mem.tmode == "TSQL":
787
            rx_mode = tx_mode = "Tone"
788
            rxtone = txtone = int(mem.ctone * 10) + 0x8000
789
        elif mem.tmode == "DTCS":
790
            tx_mode = rx_mode = "DTCS"
791
            txtone = _set_dcs(mem.dtcs, mem.dtcs_polarity[0])
792
            rxtone = _set_dcs(mem.dtcs, mem.dtcs_polarity[1])
793
        elif mem.tmode == "Cross":
794
            tx_mode, rx_mode = mem.cross_mode.split("->")
795
            if tx_mode == "DTCS":
796
                txtone = _set_dcs(mem.dtcs, mem.dtcs_polarity[0])
797
            elif tx_mode == "Tone":
798
                txtone = int(mem.rtone * 10) + 0x8000
799
            if rx_mode == "DTCS":
800
                rxtone = _set_dcs(mem.rx_dtcs, mem.dtcs_polarity[1])
801
            elif rx_mode == "Tone":
802
                rxtone = int(mem.ctone * 10) + 0x8000
803

    
804
        _mem.rxtone = rxtone
805
        _mem.txtone = txtone
806

    
807
        LOG.debug("Set TX %s (%i) RX %s (%i)" %
808
                  (tx_mode, _mem.txtone, rx_mode, _mem.rxtone))
809

    
810
    def set_memory(self, mem):
811
        number = mem.number
812

    
813
        _mem = self._memobj.memory[number]
814
        _nam = self._memobj.names[number]
815

    
816
        if mem.empty:
817
            _mem.set_raw("\x00" * (_mem.size() / 8))
818
            self._memobj.valid[number] = 0
819
            self._memobj.names[number].set_raw("\x00" * (_nam.size() / 8))
820
            return
821

    
822
        _mem.rxfreq = int(mem.freq / 10)
823
        if mem.duplex == "off":
824
            _mem.txfreq = 0xFFFFFFFF
825
        elif mem.duplex == "split":
826
            _mem.txfreq = int(mem.offset / 10)
827
        elif mem.duplex == "off":
828
            for i in range(0, 4):
829
                _mem.txfreq[i].set_raw("\xFF")
830
        elif mem.duplex == "+":
831
            _mem.txfreq = int(mem.freq / 10) + int(mem.offset / 10)
832
        elif mem.duplex == "-":
833
            _mem.txfreq = int(mem.freq / 10) - int(mem.offset / 10)
834
        else:
835
            _mem.txfreq = int(mem.freq / 10)
836
        _mem.scan_add = int(mem.skip != "S")
837
        _mem.iswide = int(mem.mode == "FM")
838
        # set the tone
839
        self._set_tone(mem, _mem)
840
        # set the scrambler and compander to off by default
841
        _mem.scrambler = 0
842
        _mem.compander = 0
843
        # set the power
844
        if mem.power:
845
            _mem.power = self.POWER_LEVELS.index(mem.power)
846
        else:
847
            _mem.power = True
848
        # set to mute mode to QT (not QT+DTMF or QT*DTMF) by default
849
        _mem.mute_mode = 0
850

    
851
        for i in range(0, len(_nam.name)):
852
            if i < len(mem.name) and mem.name[i]:
853
                _nam.name[i] = ord(mem.name[i])
854
            else:
855
                _nam.name[i] = 0x0
856
        self._memobj.valid[mem.number] = MEM_VALID
857

    
858
    def _get_settings(self):
859
        _settings = self._memobj.settings
860
        _vfoa = self._memobj.vfoa
861
        _vfob = self._memobj.vfob
862
        _scan = self._memobj.scan_groups
863
        _call = self._memobj.call_groups
864
        _callname = self._memobj.call_names
865

    
866
        cfg_grp = RadioSettingGroup("cfg_grp", "Config Settings")
867
        vfoa_grp = RadioSettingGroup("vfoa_grp", "VFO A Settings")
868
        vfob_grp = RadioSettingGroup("vfob_grp", "VFO B Settings")
869
        key_grp = RadioSettingGroup("key_grp", "Key Settings")
870
        fmradio_grp = RadioSettingGroup("fmradio_grp", "FM Broadcast Memory")
871
        lmt_grp = RadioSettingGroup("lmt_grp", "Rx Frequency Limits")
872
        uhf_lmt_grp = RadioSettingGroup("uhf_lmt_grp", "UHF")
873
        vhf_lmt_grp = RadioSettingGroup("vhf_lmt_grp", "VHF")
874
        oem_grp = RadioSettingGroup("oem_grp", "OEM Info")
875
        scan_grp = RadioSettingGroup("scan_grp", "Scan Group")
876
        call_grp = RadioSettingGroup("call_grp", "Call Settings")
877
        extra_grp = RadioSettingGroup("extra_grp", "NOT CHANGED BY RESET OR CPS")
878
        # lmt_grp.append(vhf_lmt_grp);
879
        # lmt_grp.append(uhf_lmt_grp);
880
        extra_grp.append(lmt_grp);
881
        extra_grp.append(oem_grp);
882
        group = RadioSettings(cfg_grp, vfoa_grp, vfob_grp,
883
                             fmradio_grp, key_grp, scan_grp, call_grp, extra_grp)
884

    
885

    
886
    # Call Settings
887

    
888
        callchars = "0123456789"
889
 
890
        # # callnamechars = chirp_common.CHARSET_ASCII
891
        # _name = str(_callname.call_name1).split("\0")[0]
892
        # # if any((c in callnamechars) for c in _msg):
893
        # val = RadioSettingValueString(0, 6, _name)
894
        # val.set_mutable(True)
895
        # rs = RadioSetting("call_name1", "Call Name 1", val)
896
        # call_grp.append(rs)
897
        # # else:
898

    
899
        _codeobj = _call.call_code_1
900
        _code = "".join([callchars[x] for x in _codeobj if int(x) < 0x0A])
901
        val = RadioSettingValueString(3, 6, _code, False)
902
        val.set_charset(callchars)
903
        rs = RadioSetting("call_code_1", "Call Code 1", val)
904
        def apply_call_code(setting, obj):
905
            value = []
906
            for j in range(0, 6):
907
                try:
908
                    value.append(callchars.index(str(setting.value)[j]))
909
                except IndexError:
910
                    value.append(0xFF)
911
            obj.call_code = value
912
        rs.set_apply_callback(apply_call_code, _call.call_code_1)
913
        call_grp.append(rs)
914

    
915
        # _msg = str(_callname.call_name2).split("\0")[0]
916
        # val = RadioSettingValueString(0, 6, _msg)
917
        # val.set_mutable(True)
918
        # rs = RadioSetting("call_name2", "Call Name 2", val)
919
        # call_grp.append(rs)
920

    
921
        _codeobj = _call.call_code_2
922
        _code = "".join([callchars[x] for x in _codeobj if int(x) < 0x0A])
923
        val = RadioSettingValueString(3, 6, _code, False)
924
        val.set_charset(callchars)
925
        rs = RadioSetting("call_code_2", "Call Code 2", val)
926
        def apply_call_code(setting, obj):
927
            value = []
928
            for j in range(0, 6):
929
                try:
930
                    value.append(callchars.index(str(setting.value)[j]))
931
                except IndexError:
932
                    value.append(0xFF)
933
            obj.call_code = value
934
        rs.set_apply_callback(apply_call_code, _call.call_code_2)
935
        call_grp.append(rs)
936

    
937
        # _msg = str(_callname.call_name3).split("\0")[0]
938
        # val = RadioSettingValueString(0, 6, _msg)
939
        # val.set_mutable(True)
940
        # rs = RadioSetting("call_name3", "Call Name 3", val)
941
        # call_grp.append(rs)
942

    
943

    
944
        _codeobj = _call.call_code_3
945
        _code = "".join([callchars[x] for x in _codeobj if int(x) < 0x0A])
946
        val = RadioSettingValueString(3, 6, _code, False)
947
        val.set_charset(callchars)
948
        rs = RadioSetting("call_code_3", "Call Code 3", val)
949
        def apply_call_code(setting, obj):
950
            value = []
951
            for j in range(0, 6):
952
                try:
953
                    value.append(callchars.index(str(setting.value)[j]))
954
                except IndexError:
955
                    value.append(0xFF)
956
            obj.call_code = value
957
        rs.set_apply_callback(apply_call_code, _call.call_code_3)
958
        call_grp.append(rs)
959

    
960
        # _msg = str(_callname.call_name4).split("\0")[0]
961
        # val = RadioSettingValueString(0, 6, _msg)
962
        # val.set_mutable(True)
963
        # rs = RadioSetting("call_name4", "Call Name 4", val)
964
        # call_grp.append(rs)
965

    
966

    
967
        _codeobj = _call.call_code_4
968
        _code = "".join([callchars[x] for x in _codeobj if int(x) < 0x0A])
969
        val = RadioSettingValueString(3, 6, _code, False)
970
        val.set_charset(callchars)
971
        rs = RadioSetting("call_code_4", "Call Code 4", val)
972
        def apply_call_code(setting, obj):
973
            value = []
974
            for j in range(0, 6):
975
                try:
976
                    value.append(callchars.index(str(setting.value)[j]))
977
                except IndexError:
978
                    value.append(0xFF)
979
            obj.call_code = value
980
        rs.set_apply_callback(apply_call_code, _call.call_code_4)
981
        call_grp.append(rs)
982

    
983
        # _msg = str(_callname.call_name5).split("\0")[0]
984
        # val = RadioSettingValueString(0, 6, _msg)
985
        # val.set_mutable(True)
986
        # rs = RadioSetting("call_name5", "Call Name 5", val)
987
        # call_grp.append(rs)
988

    
989

    
990
        _codeobj = _call.call_code_5
991
        _code = "".join([callchars[x] for x in _codeobj if int(x) < 0x0A])
992
        val = RadioSettingValueString(3, 6, _code, False)
993
        val.set_charset(callchars)
994
        rs = RadioSetting("call_code_5", "Call Code 5", val)
995
        def apply_call_code(setting, obj):
996
            value = []
997
            for j in range(0, 6):
998
                try:
999
                    value.append(callchars.index(str(setting.value)[j]))
1000
                except IndexError:
1001
                    value.append(0xFF)
1002
            obj.call_code = value
1003
        rs.set_apply_callback(apply_call_code, _call.call_code_5)
1004
        call_grp.append(rs)
1005

    
1006
        # _msg = str(_callname.call_name6).split("\0")[0]
1007
        # val = RadioSettingValueString(0, 6, _msg)
1008
        # val.set_mutable(True)
1009
        # rs = RadioSetting("call_name6", "Call Name 6", val)
1010
        # call_grp.append(rs)
1011

    
1012

    
1013
        _codeobj = _call.call_code_6
1014
        _code = "".join([callchars[x] for x in _codeobj if int(x) < 0x0A])
1015
        val = RadioSettingValueString(3, 6, _code, False)
1016
        val.set_charset(callchars)
1017
        rs = RadioSetting("call_code_6", "Call Code 6", val)
1018
        def apply_call_code(setting, obj):
1019
            value = []
1020
            for j in range(0, 6):
1021
                try:
1022
                    value.append(callchars.index(str(setting.value)[j]))
1023
                except IndexError:
1024
                    value.append(0xFF)
1025
            obj.call_code = value
1026
        rs.set_apply_callback(apply_call_code, _call.call_code_6)
1027
        call_grp.append(rs)
1028

    
1029
        # _msg = str(_callname.call_name7).split("\0")[0]
1030
        # val = RadioSettingValueString(0, 6, _msg)
1031
        # val.set_mutable(True)
1032
        # rs = RadioSetting("call_name7", "Call Name 7", val)
1033
        # call_grp.append(rs)
1034

    
1035

    
1036
        _codeobj = _call.call_code_7
1037
        _code = "".join([callchars[x] for x in _codeobj if int(x) < 0x0A])
1038
        val = RadioSettingValueString(3, 6, _code, False)
1039
        val.set_charset(callchars)
1040
        rs = RadioSetting("call_code_7", "Call Code 7", val)
1041
        def apply_call_code(setting, obj):
1042
            value = []
1043
            for j in range(0, 6):
1044
                try:
1045
                    value.append(callchars.index(str(setting.value)[j]))
1046
                except IndexError:
1047
                    value.append(0xFF)
1048
            obj.call_code = value
1049
        rs.set_apply_callback(apply_call_code, _call.call_code_7)
1050
        call_grp.append(rs)
1051

    
1052
        # _msg = str(_callname.call_name8).split("\0")[0]
1053
        # val = RadioSettingValueString(0, 6, _msg)
1054
        # val.set_mutable(True)
1055
        # rs = RadioSetting("call_name8", "Call Name 8", val)
1056
        # call_grp.append(rs)
1057

    
1058

    
1059
        _codeobj = _call.call_code_8
1060
        _code = "".join([callchars[x] for x in _codeobj if int(x) < 0x0A])
1061
        val = RadioSettingValueString(3, 6, _code, False)
1062
        val.set_charset(callchars)
1063
        rs = RadioSetting("call_code_8", "Call Code 8", val)
1064
        def apply_call_code(setting, obj):
1065
            value = []
1066
            for j in range(0, 6):
1067
                try:
1068
                    value.append(callchars.index(str(setting.value)[j]))
1069
                except IndexError:
1070
                    value.append(0xFF)
1071
            obj.call_code = value
1072
        rs.set_apply_callback(apply_call_code, _call.call_code_8)
1073
        call_grp.append(rs)
1074

    
1075
        # _msg = str(_callname.call_name9).split("\0")[0]
1076
        # val = RadioSettingValueString(0, 6, _msg)
1077
        # val.set_mutable(True)
1078
        # rs = RadioSetting("call_name9", "Call Name 9", val)
1079
        # call_grp.append(rs)
1080

    
1081

    
1082
        _codeobj = _call.call_code_9
1083
        _code = "".join([callchars[x] for x in _codeobj if int(x) < 0x0A])
1084
        val = RadioSettingValueString(3, 6, _code, False)
1085
        val.set_charset(callchars)
1086
        rs = RadioSetting("call_code_9", "Call Code 9", val)
1087
        def apply_call_code(setting, obj):
1088
            value = []
1089
            for j in range(0, 6):
1090
                try:
1091
                    value.append(callchars.index(str(setting.value)[j]))
1092
                except IndexError:
1093
                    value.append(0xFF)
1094
            obj.call_code = value
1095
        rs.set_apply_callback(apply_call_code, _call.call_code_9)
1096
        call_grp.append(rs)
1097

    
1098
        # _msg = str(_callname.call_name10).split("\0")[0]
1099
        # val = RadioSettingValueString(0, 6, _msg)
1100
        # val.set_mutable(True)
1101
        # rs = RadioSetting("call_name10", "Call Name 10", val)
1102
        # call_grp.append(rs)
1103

    
1104

    
1105
        _codeobj = _call.call_code_10
1106
        _code = "".join([callchars[x] for x in _codeobj if int(x) < 0x0A])
1107
        val = RadioSettingValueString(3, 6, _code, False)
1108
        val.set_charset(callchars)
1109
        rs = RadioSetting("call_code_10", "Call Code 10", val)
1110
        def apply_call_code(setting, obj):
1111
            value = []
1112
            for j in range(0, 6):
1113
                try:
1114
                    value.append(callchars.index(str(setting.value)[j]))
1115
                except IndexError:
1116
                    value.append(0xFF)
1117
            obj.call_code = value
1118
        rs.set_apply_callback(apply_call_code, _call.call_code_10)
1119
        call_grp.append(rs)
1120

    
1121
        # _msg = str(_callname.call_name11).split("\0")[0]
1122
        # val = RadioSettingValueString(0, 6, _msg)
1123
        # val.set_mutable(True)
1124
        # rs = RadioSetting("call_name11", "Call Name 11", val)
1125
        # call_grp.append(rs)
1126

    
1127

    
1128
        _codeobj = _call.call_code_11
1129
        _code = "".join([callchars[x] for x in _codeobj if int(x) < 0x0A])
1130
        val = RadioSettingValueString(3, 6, _code, False)
1131
        val.set_charset(callchars)
1132
        rs = RadioSetting("call_code_11", "Call Code 11", val)
1133
        def apply_call_code(setting, obj):
1134
            value = []
1135
            for j in range(0, 6):
1136
                try:
1137
                    value.append(callchars.index(str(setting.value)[j]))
1138
                except IndexError:
1139
                    value.append(0xFF)
1140
            obj.call_code = value
1141
        rs.set_apply_callback(apply_call_code, _call.call_code_11)
1142
        call_grp.append(rs)
1143

    
1144
        # _msg = str(_callname.call_name12).split("\0")[0]
1145
        # val = RadioSettingValueString(0, 6, _msg)
1146
        # val.set_mutable(True)
1147
        # rs = RadioSetting("call_name12", "Call Name 12", val)
1148
        # call_grp.append(rs)
1149

    
1150

    
1151
        _codeobj = _call.call_code_12
1152
        _code = "".join([callchars[x] for x in _codeobj if int(x) < 0x0A])
1153
        val = RadioSettingValueString(3, 6, _code, False)
1154
        val.set_charset(callchars)
1155
        rs = RadioSetting("call_code_12", "Call Code 12", val)
1156
        def apply_call_code(setting, obj):
1157
            value = []
1158
            for j in range(0, 6):
1159
                try:
1160
                    value.append(callchars.index(str(setting.value)[j]))
1161
                except IndexError:
1162
                    value.append(0xFF)
1163
            obj.call_code = value
1164
        rs.set_apply_callback(apply_call_code, _call.call_code_12)
1165
        call_grp.append(rs)
1166

    
1167
        # _msg = str(_callname.call_name13).split("\0")[0]
1168
        # val = RadioSettingValueString(0, 6, _msg)
1169
        # val.set_mutable(True)
1170
        # rs = RadioSetting("call_name13", "Call Name 13", val)
1171
        # call_grp.append(rs)
1172

    
1173

    
1174
        _codeobj = _call.call_code_13
1175
        _code = "".join([callchars[x] for x in _codeobj if int(x) < 0x0A])
1176
        val = RadioSettingValueString(3, 6, _code, False)
1177
        val.set_charset(callchars)
1178
        rs = RadioSetting("call_code_13", "Call Code 13", val)
1179
        def apply_call_code(setting, obj):
1180
            value = []
1181
            for j in range(0, 6):
1182
                try:
1183
                    value.append(callchars.index(str(setting.value)[j]))
1184
                except IndexError:
1185
                    value.append(0xFF)
1186
            obj.call_code = value
1187
        rs.set_apply_callback(apply_call_code, _call.call_code_13)
1188
        call_grp.append(rs)
1189

    
1190
        # _msg = str(_callname.call_name14).split("\0")[0]
1191
        # val = RadioSettingValueString(0, 6, _msg)
1192
        # val.set_mutable(True)
1193
        # rs = RadioSetting("call_name14", "Call Name 14", val)
1194
        # call_grp.append(rs)
1195

    
1196

    
1197
        _codeobj = _call.call_code_14
1198
        _code = "".join([callchars[x] for x in _codeobj if int(x) < 0x0A])
1199
        val = RadioSettingValueString(3, 6, _code, False)
1200
        val.set_charset(callchars)
1201
        rs = RadioSetting("call_code_14", "Call Code 14", val)
1202
        def apply_call_code(setting, obj):
1203
            value = []
1204
            for j in range(0, 6):
1205
                try:
1206
                    value.append(callchars.index(str(setting.value)[j]))
1207
                except IndexError:
1208
                    value.append(0xFF)
1209
            obj.call_code = value
1210
        rs.set_apply_callback(apply_call_code, _call.call_code_14)
1211
        call_grp.append(rs)
1212

    
1213
        # _msg = str(_callname.call_name15).split("\0")[0]
1214
        # val = RadioSettingValueString(0, 6, _msg)
1215
        # val.set_mutable(True)
1216
        # rs = RadioSetting("call_name15", "Call Name 15", val)
1217
        # call_grp.append(rs)
1218

    
1219

    
1220
        _codeobj = _call.call_code_15
1221
        _code = "".join([callchars[x] for x in _codeobj if int(x) < 0x0A])
1222
        val = RadioSettingValueString(3, 6, _code, False)
1223
        val.set_charset(callchars)
1224
        rs = RadioSetting("call_code_15", "Call Code 15", val)
1225
        def apply_call_code(setting, obj):
1226
            value = []
1227
            for j in range(0, 6):
1228
                try:
1229
                    value.append(callchars.index(str(setting.value)[j]))
1230
                except IndexError:
1231
                    value.append(0xFF)
1232
            obj.call_code = value
1233
        rs.set_apply_callback(apply_call_code, _call.call_code_15)
1234
        call_grp.append(rs)
1235

    
1236
        # _msg = str(_callname.call_name16).split("\0")[0]
1237
        # val = RadioSettingValueString(0, 6, _msg)
1238
        # val.set_mutable(True)
1239
        # rs = RadioSetting("call_name16", "Call Name 16", val)
1240
        # call_grp.append(rs)
1241

    
1242

    
1243
        _codeobj = _call.call_code_16
1244
        _code = "".join([callchars[x] for x in _codeobj if int(x) < 0x0A])
1245
        val = RadioSettingValueString(3, 6, _code, False)
1246
        val.set_charset(callchars)
1247
        rs = RadioSetting("call_code_16", "Call Code 16", val)
1248
        def apply_call_code(setting, obj):
1249
            value = []
1250
            for j in range(0, 6):
1251
                try:
1252
                    value.append(callchars.index(str(setting.value)[j]))
1253
                except IndexError:
1254
                    value.append(0xFF)
1255
            obj.call_code = value
1256
        rs.set_apply_callback(apply_call_code, _call.call_code_16)
1257
        call_grp.append(rs)
1258

    
1259
        # _msg = str(_callname.call_name17).split("\0")[0]
1260
        # val = RadioSettingValueString(0, 6, _msg)
1261
        # val.set_mutable(True)
1262
        # rs = RadioSetting("call_name17", "Call Name 17", val)
1263
        # call_grp.append(rs)
1264

    
1265

    
1266
        _codeobj = _call.call_code_17
1267
        _code = "".join([callchars[x] for x in _codeobj if int(x) < 0x0A])
1268
        val = RadioSettingValueString(3, 6, _code, False)
1269
        val.set_charset(callchars)
1270
        rs = RadioSetting("call_code_17", "Call Code 17", val)
1271
        def apply_call_code(setting, obj):
1272
            value = []
1273
            for j in range(0, 6):
1274
                try:
1275
                    value.append(callchars.index(str(setting.value)[j]))
1276
                except IndexError:
1277
                    value.append(0xFF)
1278
            obj.call_code = value
1279
        rs.set_apply_callback(apply_call_code, _call.call_code_17)
1280
        call_grp.append(rs)
1281

    
1282
        # _msg = str(_callname.call_name18).split("\0")[0]
1283
        # val = RadioSettingValueString(0, 6, _msg)
1284
        # val.set_mutable(True)
1285
        # rs = RadioSetting("call_name18", "Call Name 18", val)
1286
        # call_grp.append(rs)
1287

    
1288

    
1289
        _codeobj = _call.call_code_18
1290
        _code = "".join([callchars[x] for x in _codeobj if int(x) < 0x0A])
1291
        val = RadioSettingValueString(3, 6, _code, False)
1292
        val.set_charset(callchars)
1293
        rs = RadioSetting("call_code_18", "Call Code 18", val)
1294
        def apply_call_code(setting, obj):
1295
            value = []
1296
            for j in range(0, 6):
1297
                try:
1298
                    value.append(callchars.index(str(setting.value)[j]))
1299
                except IndexError:
1300
                    value.append(0xFF)
1301
            obj.call_code = value
1302
        rs.set_apply_callback(apply_call_code, _call.call_code_18)
1303
        call_grp.append(rs)
1304

    
1305
        # _msg = str(_callname.call_name19).split("\0")[0]
1306
        # val = RadioSettingValueString(0, 6, _msg)
1307
        # val.set_mutable(True)
1308
        # rs = RadioSetting("call_name19", "Call Name 19", val)
1309
        # call_grp.append(rs)
1310

    
1311

    
1312
        _codeobj = _call.call_code_19
1313
        _code = "".join([callchars[x] for x in _codeobj if int(x) < 0x0A])
1314
        val = RadioSettingValueString(3, 6, _code, False)
1315
        val.set_charset(callchars)
1316
        rs = RadioSetting("call_code_19", "Call Code 19", val)
1317
        def apply_call_code(setting, obj):
1318
            value = []
1319
            for j in range(0, 6):
1320
                try:
1321
                    value.append(callchars.index(str(setting.value)[j]))
1322
                except IndexError:
1323
                    value.append(0xFF)
1324
            obj.call_code = value
1325
        rs.set_apply_callback(apply_call_code, _call.call_code_19)
1326
        call_grp.append(rs)
1327

    
1328
        # _msg = str(_callname.call_name20).split("\0")[0]
1329
        # val = RadioSettingValueString(0, 6, _msg)
1330
        # val.set_mutable(True)
1331
        # rs = RadioSetting("call_name20", "Call Name 20", val)
1332
        # call_grp.append(rs)
1333

    
1334

    
1335
        _codeobj = _call.call_code_20
1336
        _code = "".join([callchars[x] for x in _codeobj if int(x) < 0x0A])
1337
        val = RadioSettingValueString(3, 6, _code, False)
1338
        val.set_charset(callchars)
1339
        rs = RadioSetting("call_code_20", "Call Code 20", val)
1340
        def apply_call_code(setting, obj):
1341
            value = []
1342
            for j in range(0, 6):
1343
                try:
1344
                    value.append(callchars.index(str(setting.value)[j]))
1345
                except IndexError:
1346
                    value.append(0xFF)
1347
            obj.call_code = value
1348
        rs.set_apply_callback(apply_call_code, _call.call_code_20)
1349
        call_grp.append(rs)
1350

    
1351
        # Configuration Settings
1352
        #
1353
        rs = RadioSetting("DspBrtAct", "Display Brightnes ACTIVE",
1354
                          RadioSettingValueList(DSPBRTACT_LIST,
1355
                                                 DSPBRTACT_LIST[_settings.DspBrtAct]))
1356
        cfg_grp.append(rs)
1357
        rs = RadioSetting("DspBrtSby", "Display Brightnes STANDBY",
1358
                          RadioSettingValueList(DSPBRTSBY_LIST,
1359
                                                 DSPBRTSBY_LIST[_settings.DspBrtSby]))
1360
        cfg_grp.append(rs)
1361
        rs = RadioSetting("wxalert", "Weather Alert",
1362
                          RadioSettingValueBoolean(_settings.wxalert))
1363
        cfg_grp.append(rs)
1364
        rs = RadioSetting("power_save", "Battery Saver",
1365
                          RadioSettingValueBoolean(_settings.power_save))
1366
        cfg_grp.append(rs)
1367
        rs = RadioSetting("theme", "Theme",
1368
                          RadioSettingValueList(
1369
                              THEME_LIST, THEME_LIST[_settings.theme]))
1370
        cfg_grp.append(rs)
1371
        rs = RadioSetting("backlight", "Backlight Active Time",
1372
                          RadioSettingValueList(BACKLIGHT_LIST,
1373
                                                BACKLIGHT_LIST[_settings.
1374
                                                               backlight]))
1375
        cfg_grp.append(rs)
1376
        rs = RadioSetting("scan_rev", "Scan Mode",
1377
                          RadioSettingValueList(SCANMODE_LIST,
1378
                                                SCANMODE_LIST[_settings.
1379
                                                              scan_rev]))
1380
        cfg_grp.append(rs)
1381
        rs = RadioSetting("prich_sw", "Priority Channel Scan",
1382
                          RadioSettingValueBoolean(_settings.prich_sw))
1383
        cfg_grp.append(rs)
1384
        rs = RadioSetting("pri_ch", "Priority Channel - Can not be empty Channel",
1385
                          RadioSettingValueInteger(1, 999, _settings.pri_ch))
1386
        cfg_grp.append(rs)
1387
        rs = RadioSetting("scan_det", "Scan Mode Tone Detect",
1388
                          RadioSettingValueBoolean(_settings.scan_det))
1389
        cfg_grp.append(rs)
1390
        rs = RadioSetting("ToneScnSave", "Tone Scan Save",
1391
                          RadioSettingValueList(TONESCANSAVELIST,
1392
                                                TONESCANSAVELIST[_settings.ToneScnSave]))
1393
        cfg_grp.append(rs)
1394
        rs = RadioSetting("roger_beep", "Roger Beep",
1395
                          RadioSettingValueList(ROGER_LIST,
1396
                                                ROGER_LIST[_settings.roger_beep]))
1397
        cfg_grp.append(rs)
1398
        rs = RadioSetting("timeout", "Timeout Timer (TOT)",
1399
                          RadioSettingValueList(
1400
                              TIMEOUT_LIST, TIMEOUT_LIST[_settings.timeout]))
1401
        cfg_grp.append(rs)
1402
        rs = RadioSetting("toalarm", "Timeout Alarm (TOA)",
1403
                          RadioSettingValueInteger(0, 10, _settings.toalarm))
1404
        cfg_grp.append(rs)
1405
        rs = RadioSetting("vox", "VOX",
1406
                          RadioSettingValueList(LIST_10,
1407
                                                LIST_10[_settings.vox]))
1408
        cfg_grp.append(rs)
1409
        rs = RadioSetting("voice", "Voice Guide",
1410
                          RadioSettingValueBoolean(_settings.voice))
1411
        cfg_grp.append(rs)
1412
        rs = RadioSetting("beep", "Keypad Beep",
1413
                          RadioSettingValueBoolean(_settings.beep))
1414
        cfg_grp.append(rs)
1415
        rs = RadioSetting("BCL_B", "Busy Channel Lock-out A",
1416
                          RadioSettingValueBoolean(_settings.BCL_A))
1417
        cfg_grp.append(rs)
1418
        rs = RadioSetting("BCL_A", "Busy Channel Lock-out B",
1419
                          RadioSettingValueBoolean(_settings.BCL_B))
1420
        cfg_grp.append(rs)
1421
        rs = RadioSetting("smuteset", "Secondary Area Mute (SMUTESET)",
1422
                          RadioSettingValueList(SMUTESET_LIST,
1423
                                                SMUTESET_LIST[_settings.
1424
                                                              smuteset]))
1425
        cfg_grp.append(rs)
1426
        rs = RadioSetting("ani_sw", "ANI-ID Switch (ANI-SW)",
1427
                          RadioSettingValueBoolean(_settings.ani_sw))
1428
        cfg_grp.append(rs)
1429
        rs = RadioSetting("dtmf_st", "DTMF Sidetone (SIDETONE)",
1430
                          RadioSettingValueList(DTMFST_LIST,
1431
                                                DTMFST_LIST[_settings.
1432
                                                            dtmf_st]))
1433
        cfg_grp.append(rs)
1434
        rs = RadioSetting("alert", "Alert Tone",
1435
                          RadioSettingValueList(ALERTS_LIST,
1436
                                                ALERTS_LIST[_settings.alert]))
1437
        cfg_grp.append(rs)
1438
        rs = RadioSetting("ptt_delay", "PTT-DLY - MIN 100ms",
1439
                          RadioSettingValueList(PTTDELAY_LIST,
1440
                                                PTTDELAY_LIST[_settings.ptt_delay]))
1441
        cfg_grp.append(rs)
1442
        rs = RadioSetting("ptt_id", "PTT-ID",
1443
                          RadioSettingValueList(PTTID_LIST,
1444
                                                PTTID_LIST[_settings.ptt_id]))
1445
        cfg_grp.append(rs)
1446
        rs = RadioSetting("ring_time", "Ring Time",
1447
                          RadioSettingValueList(LIST_10,
1448
                                                LIST_10[_settings.ring_time]))
1449
        cfg_grp.append(rs)
1450
        rs = RadioSetting("rpt_tone", "Repeater Tone",
1451
                          RadioSettingValueBoolean(_settings.rpt_tone))
1452
        cfg_grp.append(rs)
1453
        rs = RadioSetting("stopwatch", "Timer / Stopwatch",
1454
                          RadioSettingValueBoolean(_settings.stopwatch))
1455
        cfg_grp.append(rs)
1456
        rs = RadioSetting("autolock", "Autolock",
1457
                          RadioSettingValueBoolean(_settings.autolock))
1458
        cfg_grp.append(rs)
1459
        rs = RadioSetting("keylock", "Keypad Lock",
1460
                          RadioSettingValueBoolean(_settings.keylock))
1461
        cfg_grp.append(rs)
1462
        rs = RadioSetting("ponmsg", "Poweron message",
1463
                          RadioSettingValueList(
1464
                              PONMSG_LIST, PONMSG_LIST[_settings.ponmsg]))
1465
        cfg_grp.append(rs)
1466
        rs = RadioSetting("dtmf_tx_time", "DTMF Transmit Time - MIN 50ms",
1467
                          RadioSettingValueList(DTMF_TIMES,
1468
                                                DTMF_TIMES[_settings.
1469
                                                           dtmf_tx_time]))
1470
        cfg_grp.append(rs)
1471
        rs = RadioSetting("dtmf_interval", "DTMF Interval Time - MIN 50ms",
1472
                          RadioSettingValueList(DTMF_TIMES,
1473
                                                DTMF_TIMES[_settings.
1474
                                                           dtmf_interval]))
1475
        cfg_grp.append(rs)
1476
        rs = RadioSetting("channel_menu", "Menu available in channel mode",
1477
                          RadioSettingValueBoolean(_settings.channel_menu))
1478
        cfg_grp.append(rs)
1479

    
1480
        # pswdchars = "0123456789"
1481
        # _codeobj = _settings.node_sw_pwd
1482
        # _code = "".join([pswdchars[x] for x in _codeobj if int(x) < 0x0A])
1483
        # val = RadioSettingValueString(3, 6, _code, False)
1484
        # val.set_charset(pswdchars)
1485
        # rs = RadioSetting("node_sw_pwd", "Node SW Password", val)
1486
        # def apply_node_pwd(setting, obj):
1487
        #     value = []
1488
        #     for j in range(0, 6):
1489
        #         try:
1490
        #             value.append(pswdchars.index(str(setting.value)[j]))
1491
        #         except IndexError:
1492
        #             value.append(0xFF)
1493
        #     obj.node_sw_pwd = value
1494
        # rs.set_apply_callback(apply_node_pwd, _settings)
1495
        # key_grp.append(rs)
1496

    
1497
        # pswdchars = "0123456789"
1498
        # _codeobj = _settings.reset_pwd
1499
        # _code = "".join([pswdchars[x] for x in _codeobj if int(x) < 0x0A])
1500
        # val = RadioSettingValueString(3, 6, _code, False)
1501
        # val.set_charset(pswdchars)
1502
        # rs = RadioSetting("reset_pwd", "Reset Password", val)
1503
        # def apply_pwd(setting, obj):
1504
        #     value = []
1505
        #     for j in range(0, 6):
1506
        #         try:
1507
        #             value.append(pswdchars.index(str(setting.value)[j]))
1508
        #         except IndexError:
1509
        #             value.append(0xFF)
1510
        #     obj.reset_pwd = value
1511
        # rs.set_apply_callback(apply_pwd, _settings)
1512
        # key_grp.append(rs)
1513

    
1514

    
1515
        # Key Settings
1516
        #
1517
        _msg = str(_settings.dispstr).split("\0")[0]
1518
        val = RadioSettingValueString(0, 15, _msg)
1519
        val.set_mutable(True)
1520
        rs = RadioSetting("dispstr", "Display Message - Interface Display Edit", val)
1521
        key_grp.append(rs)
1522

    
1523
        dtmfchars = "0123456789"
1524
        _codeobj = _settings.ani_code
1525
        _code = "".join([dtmfchars[x] for x in _codeobj if int(x) < 0x0A])
1526
        val = RadioSettingValueString(3, 6, _code, False)
1527
        val.set_charset(dtmfchars)
1528
        rs = RadioSetting("ani_code", "ANI Code", val)
1529
        def apply_ani_id(setting, obj):
1530
            value = []
1531
            for j in range(0, 6):
1532
                try:
1533
                    value.append(dtmfchars.index(str(setting.value)[j]))
1534
                except IndexError:
1535
                    value.append(0xFF)
1536
            obj.ani_code = value
1537
        rs.set_apply_callback(apply_ani_id, _settings)
1538
        key_grp.append(rs)
1539

    
1540
        rs = RadioSetting("pf1_shrt", "PF1 SHORT Key function",
1541
                          RadioSettingValueList(
1542
                              PFKEYSHORT_LIST,
1543
                              PFKEYSHORT_LIST[_settings.pf1_shrt]))
1544
        key_grp.append(rs)
1545
        rs = RadioSetting("pf1_long", "PF1 LONG Key function",
1546
                          RadioSettingValueList(
1547
                              PFKEYLONG_LIST,
1548
                              PFKEYLONG_LIST[_settings.pf1_long]))
1549
        key_grp.append(rs)
1550
        rs = RadioSetting("pf2_shrt", "PF2 SHORT Key function",
1551
                          RadioSettingValueList(
1552
                              PFKEYSHORT_LIST,
1553
                              PFKEYSHORT_LIST[_settings.pf2_shrt]))
1554
        key_grp.append(rs)
1555
        rs = RadioSetting("pf2_long", "PF2 LONG Key function",
1556
                          RadioSettingValueList(
1557
                              PFKEYLONG_LIST,
1558
                              PFKEYLONG_LIST[_settings.pf2_long]))
1559
        key_grp.append(rs)
1560

    
1561
#       SCAN GROUPs
1562
        rs = RadioSetting("ScnGrpA_Act", "Scan Group A Active",
1563
                          RadioSettingValueList(SCANGRP_LIST, SCANGRP_LIST[_settings.ScnGrpA_Act]))
1564
        scan_grp.append(rs)
1565
        rs = RadioSetting("ScnGrpB_Act", "Scan Group B Active",
1566
                          RadioSettingValueList(SCANGRP_LIST, SCANGRP_LIST[_settings.ScnGrpB_Act]))
1567
        scan_grp.append(rs)
1568

    
1569

    
1570
        # rs = RadioSetting("Group_1_lower", "Scan Group 1 Lower",
1571
        #                   RadioSettingValueInteger(1, 999, _scan_groups.Group_1_lower))
1572
        # scan_grp.append(rs)
1573
        # rs = RadioSetting("Group_1_upper", "Scan Group 1 Upper",
1574
        #                   RadioSettingValueInteger(1, 999, _scan_groups.Group_1_upper))
1575
        # scan_grp.append(rs)
1576
        # rs = RadioSetting("Group_2_lower", "Scan Group 2 Lower",
1577
        #                   RadioSettingValueInteger(1, 999, _scan_groups.Group_2_lower))
1578
        # scan_grp.append(rs)
1579
        # rs = RadioSetting("Group_2_upper", "Scan Group 2 Upper",
1580
        #                   RadioSettingValueInteger(1, 999, _scan_groups.Group_2_upper))
1581
        # scan_grp.append(rs)
1582
        # rs = RadioSetting("Group_3_lower", "Scan Group 3 Lower",
1583
        #                   RadioSettingValueInteger(1, 999, _scan_groups.Group_3_lower))
1584
        # scan_grp.append(rs)
1585
        # rs = RadioSetting("Group_3_upper", "Scan Group 3 Upper",
1586
        #                   RadioSettingValueInteger(1, 999, _scan_groups.Group_3_upper))
1587
        # scan_grp.append(rs)
1588
        # rs = RadioSetting("Group_4_lower", "Scan Group 4 Lower",
1589
        #                   RadioSettingValueInteger(1, 999, _scan_groups.Group_4_lower))
1590
        # scan_grp.append(rs)
1591
        # rs = RadioSetting("Group_4_upper", "Scan Group 4 Upper",
1592
        #                   RadioSettingValueInteger(1, 999, _scan_groups.Group_4_upper))
1593
        # scan_grp.append(rs)
1594
        # rs = RadioSetting("Group_5_lower", "Scan Group 5 Lower",
1595
        #                   RadioSettingValueInteger(1, 999, _scan_groups.Group_5_lower))
1596
        # scan_grp.append(rs)
1597
        # rs = RadioSetting("Group_5_upper", "Scan Group 5 Upper",
1598
        #                   RadioSettingValueInteger(1, 999, _scan_groups.Group_5_upper))
1599
        # scan_grp.append(rs)
1600
        # rs = RadioSetting("Group_6_lower", "Scan Group 6 Lower",
1601
        #                   RadioSettingValueInteger(1, 999, _scan_groups.Group_6_lower))
1602
        # scan_grp.append(rs)
1603
        # rs = RadioSetting("Group_6_upper", "Scan Group 6 Upper",
1604
        #                   RadioSettingValueInteger(1, 999, _scan_groups.Group_6_upper))
1605
        # scan_grp.append(rs)
1606
        # rs = RadioSetting("Group_7_lower", "Scan Group 7 Lower",
1607
        #                   RadioSettingValueInteger(1, 999, _scan_groups.Group_7_lower))
1608
        # scan_grp.append(rs)
1609
        # rs = RadioSetting("Group_7_upper", "Scan Group 7 Upper",
1610
        #                   RadioSettingValueInteger(1, 999, _scan_groups.Group_7_upper))
1611
        # scan_grp.append(rs)
1612
        # rs = RadioSetting("Group_8_lower", "Scan Group 8 Lower",
1613
        #                   RadioSettingValueInteger(1, 999, _scan_groups.Group_8_lower))
1614
        # scan_grp.append(rs)
1615
        # rs = RadioSetting("Group_8_upper", "Scan Group 8 Upper",
1616
        #                   RadioSettingValueInteger(1, 999, _scan_groups.Group_8_upper))
1617
        # scan_grp.append(rs)
1618
        # rs = RadioSetting("Group_9_lower", "Scan Group 9 Lower",
1619
        #                   RadioSettingValueInteger(1, 999, _scan_groups.Group_9_lower))
1620
        # scan_grp.append(rs)
1621
        # rs = RadioSetting("Group_9_upper", "Scan Group 9 Upper",
1622
        #                   RadioSettingValueInteger(1, 999, _scan_groups.Group_9_upper))
1623
        # scan_grp.append(rs)
1624
        # rs = RadioSetting("Group_10_lower", "Scan Group 10 Lower",
1625
        #                   RadioSettingValueInteger(1, 999, _scan_groups.Group_10_lower))
1626
        # scan_grp.append(rs)
1627
        # rs = RadioSetting("Group_10_upper", "Scan Group 10 Upper",
1628
        #                   RadioSettingValueInteger(1, 999, _scan_groups.Group_10_upper))
1629
        # scan_grp.append(rs)
1630

    
1631
        # VFO A Settings
1632
        #
1633
        rs = RadioSetting("work_mode_a", "VFO A Workmode",
1634
                          RadioSettingValueList(WORKMODE_LIST, WORKMODE_LIST[_settings.work_mode_a]))
1635
        vfoa_grp.append(rs)
1636
        rs = RadioSetting("work_ch_a", "VFO A Work Channel",
1637
                          RadioSettingValueInteger(1, 999, _settings.work_ch_a))
1638
        vfoa_grp.append(rs)
1639
        rs = RadioSetting("vfoa.rxfreq", "VFO A Rx Frequency (Hz)",
1640
                          RadioSettingValueInteger(
1641
                              134000000, 520000000, _vfoa.rxfreq * 10, 250))
1642
        vfoa_grp.append(rs)
1643
        rs = RadioSetting("vfoa.power", "VFO A Power",
1644
                          RadioSettingValueList(
1645
                              POWER_LIST, POWER_LIST[_vfoa.power]))
1646
        vfoa_grp.append(rs)
1647
        rs = RadioSetting("vfoa.iswide", "VFO A Wide/Narrow",
1648
                          RadioSettingValueList(
1649
                              BANDWIDTH_LIST, BANDWIDTH_LIST[_vfoa.iswide]))
1650
        vfoa_grp.append(rs)
1651
        rs = RadioSetting("vfoa.mute_mode", "VFO A Mute (SP Mute)",
1652
                          RadioSettingValueList(
1653
                              SPMUTE_LIST, SPMUTE_LIST[_vfoa.mute_mode]))
1654
        vfoa_grp.append(rs)
1655
        rs = RadioSetting("VFO_repeater_a", "VFO A Repeater",
1656
                          RadioSettingValueBoolean(_settings.VFO_repeater_a))
1657
        vfoa_grp.append(rs)
1658

    
1659
        rs = RadioSetting("vfoa.scrambler", "VFO A Descramble",
1660
                          RadioSettingValueList(
1661
                              SCRAMBLE_LIST, SCRAMBLE_LIST[_vfoa.scrambler]))
1662
        vfoa_grp.append(rs)
1663

    
1664
        # rs = RadioSetting("compander", "VFO A Compander",
1665
        #                  RadioSettingValueBoolean(_vfoa.compander))
1666
        # vfoa_grp.append(rs)
1667

    
1668
        rs = RadioSetting("vfoa.step", "VFO A Step (kHz)",
1669
                          RadioSettingValueList(
1670
                              STEP_LIST, STEP_LIST[_vfoa.step]))
1671
        vfoa_grp.append(rs)
1672
        rs = RadioSetting("vfoa.squelch", "VFO A Squelch",
1673
                          RadioSettingValueList(
1674
                              LIST_10, LIST_10[_vfoa.squelch]))
1675
        vfoa_grp.append(rs)
1676
        # VFO B Settings
1677
        #
1678
        rs = RadioSetting("work_mode_b", "VFO B Workmode",
1679
                          RadioSettingValueList(WORKMODE_LIST, WORKMODE_LIST[_settings.work_mode_b]))
1680
        vfob_grp.append(rs)
1681
        rs = RadioSetting("work_ch_b", "VFO B Work Channel",
1682
                          RadioSettingValueInteger(1, 999, _settings.work_ch_b))
1683
        vfob_grp.append(rs)
1684
        rs = RadioSetting("vfob.rxfreq", "VFO B Rx Frequency (Hz)",
1685
                          RadioSettingValueInteger(
1686
                              134000000, 520000000, _vfob.rxfreq * 10, 250))
1687
        vfob_grp.append(rs)
1688
        rs = RadioSetting("vfob.power", "VFO B Power",
1689
                          RadioSettingValueList(
1690
                              POWER_LIST, POWER_LIST[_vfob.power]))
1691
        vfob_grp.append(rs)
1692
        rs = RadioSetting("vfob.iswide", "VFO B Wide/Narrow",
1693
                          RadioSettingValueList(
1694
                              BANDWIDTH_LIST, BANDWIDTH_LIST[_vfob.iswide]))
1695
        vfob_grp.append(rs)
1696
        rs = RadioSetting("vfob.mute_mode", "VFO B Mute (SP Mute)",
1697
                          RadioSettingValueList(
1698
                              SPMUTE_LIST, SPMUTE_LIST[_vfob.mute_mode]))
1699
        vfob_grp.append(rs)
1700
        rs = RadioSetting("VFO_repeater_b", "VFO B Repeater",
1701
                          RadioSettingValueBoolean(_settings.VFO_repeater_b))
1702
        vfob_grp.append(rs)
1703

    
1704
        rs = RadioSetting("vfob.scrambler", "VFO B Descramble",
1705
                          RadioSettingValueList(
1706
                              SCRAMBLE_LIST, SCRAMBLE_LIST[_vfob.scrambler]))
1707
        vfob_grp.append(rs)
1708

    
1709
        #rs = RadioSetting("compander", "VFO B Compander",
1710
        #                  RadioSettingValueBoolean(_vfob.compander))
1711
        #vfob_grp.append(rs)
1712
        
1713
        rs = RadioSetting("vfob.step", "VFO B Step (kHz)",
1714
                          RadioSettingValueList(
1715
                              STEP_LIST, STEP_LIST[_vfob.step]))
1716
        vfob_grp.append(rs)
1717
        rs = RadioSetting("vfob.squelch", "VFO B Squelch",
1718
                          RadioSettingValueList(
1719
                              LIST_10, LIST_10[_vfob.squelch]))
1720
        vfob_grp.append(rs)
1721

    
1722
# FM RADIO PRESETS
1723
        rs = RadioSetting("FM_radio1", "FM1 in MHz*10",
1724
                          RadioSettingValueInteger(760, 1080, _settings.FM_radio1))
1725
        fmradio_grp.append(rs)
1726
        rs = RadioSetting("FM_radio2", "FM2 in MHz*10",
1727
                          RadioSettingValueInteger(760, 1080, _settings.FM_radio2))
1728
        fmradio_grp.append(rs)
1729
        rs = RadioSetting("FM_radio3", "FM3 in MHz*10",
1730
                          RadioSettingValueInteger(760, 1080, _settings.FM_radio3))
1731
        fmradio_grp.append(rs)
1732
        rs = RadioSetting("FM_radio4", "FM4 in MHz*10",
1733
                          RadioSettingValueInteger(760, 1080, _settings.FM_radio4))
1734
        fmradio_grp.append(rs)
1735
        rs = RadioSetting("FM_radio5", "FM5 in MHz*10",
1736
                          RadioSettingValueInteger(760, 1080, _settings.FM_radio5))
1737
        fmradio_grp.append(rs)
1738
        rs = RadioSetting("FM_radio6", "FM6 in MHz*10",
1739
                          RadioSettingValueInteger(760, 1080, _settings.FM_radio6))
1740
        fmradio_grp.append(rs)
1741
        rs = RadioSetting("FM_radio7", "FM7 in MHz*10",
1742
                          RadioSettingValueInteger(760, 1080, _settings.FM_radio7))
1743
        fmradio_grp.append(rs)
1744
        rs = RadioSetting("FM_radio8", "FM8 in MHz*10",
1745
                          RadioSettingValueInteger(760, 1080, _settings.FM_radio8))
1746
        fmradio_grp.append(rs)
1747
        rs = RadioSetting("FM_radio9", "FM9 in MHz*10",
1748
                          RadioSettingValueInteger(760, 1080, _settings.FM_radio9))
1749
        fmradio_grp.append(rs)
1750
        rs = RadioSetting("FM_radio10", "FM10 in MHz*10",
1751
                          RadioSettingValueInteger(760, 1080, _settings.FM_radio10))
1752
        fmradio_grp.append(rs)
1753
        rs = RadioSetting("FM_radio11", "FM11 in MHz*10",
1754
                          RadioSettingValueInteger(760, 1080, _settings.FM_radio11))
1755
        fmradio_grp.append(rs)
1756
        rs = RadioSetting("FM_radio12", "FM12 in MHz*10",
1757
                          RadioSettingValueInteger(760, 1080, _settings.FM_radio12))
1758
        fmradio_grp.append(rs)
1759
        rs = RadioSetting("FM_radio13", "FM13 in MHz*10",
1760
                          RadioSettingValueInteger(760, 1080, _settings.FM_radio13))
1761
        fmradio_grp.append(rs)
1762
        rs = RadioSetting("FM_radio14", "FM14 in MHz*10",
1763
                          RadioSettingValueInteger(760, 1080, _settings.FM_radio14))
1764
        fmradio_grp.append(rs)
1765
        rs = RadioSetting("FM_radio15", "FM15 in MHz*10",
1766
                          RadioSettingValueInteger(760, 1080, _settings.FM_radio15))
1767
        fmradio_grp.append(rs)
1768
        rs = RadioSetting("FM_radio16", "FM16 in MHz*10",
1769
                          RadioSettingValueInteger(760, 1080, _settings.FM_radio16))
1770
        fmradio_grp.append(rs)
1771
        rs = RadioSetting("FM_radio17", "FM17 in MHz*10",
1772
                          RadioSettingValueInteger(760, 1080, _settings.FM_radio17))
1773
        fmradio_grp.append(rs)
1774
        rs = RadioSetting("FM_radio18", "FM18 in MHz*10",
1775
                          RadioSettingValueInteger(760, 1080, _settings.FM_radio18))
1776
        fmradio_grp.append(rs)
1777
        rs = RadioSetting("FM_radio19", "FM19 in MHz*10",
1778
                          RadioSettingValueInteger(760, 1080, _settings.FM_radio19))
1779
        fmradio_grp.append(rs)
1780
        rs = RadioSetting("FM_radio20", "FM20 in MHz*10",
1781
                          RadioSettingValueInteger(760, 1080, _settings.FM_radio20))
1782
        fmradio_grp.append(rs)
1783

    
1784
# Freq Limits settings
1785
        #
1786
        rs = RadioSetting("vhf_limits.rx_start", "VHF RX Lower Limit (Hz)",
1787
                          RadioSettingValueInteger(
1788
                              10000000, 299999999,
1789
                              self._memobj.vhf_limits.rx_start * 10, 5000))
1790
        lmt_grp.append(rs)
1791
        rs = RadioSetting("vhf_limits.rx_stop", "VHF RX Upper Limit (Hz)",
1792
                          RadioSettingValueInteger(
1793
                              10000000, 299999999,
1794
                              self._memobj.vhf_limits.rx_stop * 10, 5000))
1795
        lmt_grp.append(rs)
1796
        # rs = RadioSetting("vhf_limits.tx_start", "VHF TX Lower Limit",
1797
        #                   RadioSettingValueInteger(
1798
        #                       10000000, 299999999,
1799
        #                       self._memobj.vhf_limits.tx_start * 10, 5000))
1800
        # val.set_mutable(False)
1801
        # vhf_lmt_grp.append(rs)
1802
        # rs = RadioSetting("vhf_limits.tx_stop", "VHF TX Upper Limit",
1803
        #                   RadioSettingValueInteger(
1804
        #                       10000000, 299999999,
1805
        #                       self._memobj.vhf_limits.tx_stop * 10, 5000))
1806
        # val.set_mutable(False)
1807
        # vhf_lmt_grp.append(rs)
1808

    
1809
        rs = RadioSetting("uhf_limits.rx_start", "UHF RX Lower Limit (Hz)",
1810
                          RadioSettingValueInteger(
1811
                              300000000, 999999999,
1812
                              self._memobj.uhf_limits.rx_start * 10, 5000))
1813
        lmt_grp.append(rs)
1814
        rs = RadioSetting("uhf_limits.rx_stop", "UHF RX Upper Limit (Hz)",
1815
                          RadioSettingValueInteger(
1816
                              300000000, 999999999,
1817
                              self._memobj.uhf_limits.rx_stop * 10, 5000))
1818
        lmt_grp.append(rs)
1819
        # rs = RadioSetting("uhf_limits.tx_start", "UHF TX Lower Limit",
1820
        #                   RadioSettingValueInteger(
1821
        #                       300000000, 999999999,
1822
        #                       self._memobj.uhf_limits.tx_start * 10, 5000))
1823
        # uhf_lmt_grp.append(rs)
1824
        # rs = RadioSetting("uhf_limits.tx_stop", "UHF TX Upper Limit",
1825
        #                   RadioSettingValueInteger(
1826
        #                       300000000, 999999999,
1827
        #                       self._memobj.uhf_limits.tx_stop * 10, 5000))
1828
        # uhf_lmt_grp.append(rs)
1829

    
1830

    
1831
# OEM info
1832
        #
1833
        def _decode(lst):
1834
            _str = ''.join([chr(c) for c in lst
1835
                            if chr(c) in chirp_common.CHARSET_ASCII])
1836
            return _str
1837

    
1838
        def do_nothing(setting, obj):
1839
            return
1840

    
1841
        _str = _decode(self._memobj.oem_info.model)
1842
        val = RadioSettingValueString(0, 8, _str)
1843
        val.set_mutable(True)
1844
        rs = RadioSetting("oem_info.model", "Model / Bottom Banner", val)
1845
        #rs.set_apply_callback(do_nothing, _settings)
1846
        oem_grp.append(rs)
1847
        _str = _decode(self._memobj.oem_info.oem1)
1848
        val = RadioSettingValueString(0, 15, _str)
1849
        val.set_mutable(False)
1850
        rs = RadioSetting("oem_info.oem1", "OEM String 1", val)
1851
        rs.set_apply_callback(do_nothing, _settings)
1852
        oem_grp.append(rs)
1853
        _str = _decode(self._memobj.oem_info.oem2)
1854
        val = RadioSettingValueString(0, 15, _str)
1855
        val.set_mutable(False)
1856
        rs = RadioSetting("oem_info.oem2", "Firmware Version ??", val)
1857
        rs.set_apply_callback(do_nothing, _settings)
1858
        oem_grp.append(rs)
1859
        # _str = _decode(self._memobj.oem_info.version)
1860
        # val = RadioSettingValueString(0, 15, _str)
1861
        # val.set_mutable(False)
1862
        # rs = RadioSetting("oem_info.version", "Software Version", val)
1863
        # rs.set_apply_callback(do_nothing, _settings)
1864
        # oem_grp.append(rs)
1865
        _str = _decode(self._memobj.oem_info.date)
1866
        val = RadioSettingValueString(0, 15, _str)
1867
        val.set_mutable(False)
1868
        rs = RadioSetting("oem_info.date", "OEM Date", val)
1869
        rs.set_apply_callback(do_nothing, _settings)
1870
        oem_grp.append(rs)
1871

    
1872
        return group
1873

    
1874

    
1875

    
1876

    
1877
        return group
1878

    
1879
    def get_settings(self):
1880
        try:
1881
            return self._get_settings()
1882
        except:
1883
            import traceback
1884
            LOG.error("Failed to parse settings: %s", traceback.format_exc())
1885
            return None
1886

    
1887
    def set_settings(self, settings):
1888
        for element in settings:
1889
            if not isinstance(element, RadioSetting):
1890
                self.set_settings(element)
1891
                continue
1892
            else:
1893
                try:
1894
                    if "." in element.get_name():
1895
                        bits = element.get_name().split(".")
1896
                        obj = self._memobj
1897
                        for bit in bits[:-1]:
1898
                            obj = getattr(obj, bit)
1899
                        setting = bits[-1]
1900
                    else:
1901
                        obj = self._memobj.settings
1902
                        setting = element.get_name()
1903

    
1904
                    if element.has_apply_callback():
1905
                        LOG.debug("Using apply callback")
1906
                        element.run_apply_callback()
1907
                    else:
1908
                        LOG.debug("Setting %s = %s" % (setting, element.value))
1909
                        if self._is_freq(element):
1910
                            setattr(obj, setting, int(element.value)/10)
1911
                        else:
1912
                            setattr(obj, setting, element.value)
1913
                except Exception, e:
1914
                    LOG.debug(element.get_name())
1915
                    raise
1916

    
1917
    def _is_freq(self, element):
1918
        return "rxfreq" in element.get_name() or "txoffset" in element.get_name() or "rx_start" in element.get_name() or "rx_stop" in element.get_name() or "tx_start" in element.get_name() or "tx_stop" in element.get_name()
(5-5/18)