Project

General

Profile

New Model #1035 » tytth9000-004.patch

David Fannin, 06/07/2014 02:53 PM

View differences:

/dev/null Thu Jan 01 00:00:00 1970 +0000 → chirp/th9000vhf.py Sat Jun 07 14:45:29 2014 -0700
1
# Copyright 2012 Dan Smith <dsmith@danplanet.com>
2
#
3
# This program is free software: you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation, either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15

  
16
import os
17
import struct
18
import time
19

  
20
from chirp import chirp_common
21
from chirp import directory
22
from chirp import memmap
23
from chirp import bitwise
24
from chirp import errors
25
from chirp import util
26
from chirp.settings import RadioSetting, RadioSettingGroup, \
27
        RadioSettingValueInteger, RadioSettingValueList, \
28
        RadioSettingValueBoolean, RadioSettingValueString, \
29
        RadioSettingValueFloat, InvalidValueError
30

  
31
#
32
#  Chirp Driver for TYT TH-9000 VHF (2 meter) Model
33
#  by David Fannin <dfannin@sushisoft.com>, KK6DF
34
#
35
#  Version 0.4 (Experimental - Known Bugs and Issues)
36
#  Use for development purposes only!  
37
#  Features working:
38
#         - Download from Radio
39
#         - Display Memories (only None, Tone, TSQL signalling supported)
40
#         - Save image file
41
#         - memory map decoded (about 90%)
42
#         - Upload to radio
43
#         - Modification of memories
44
#         - feature settings
45
#         - added Startup ID label
46
#
47
#  Features not working:
48
#         - DCS , Cross Signaling
49
#         - Skip channels
50

  
51

  
52
#
53
# Global Parameters 
54
#
55
MMAPSIZE = 16128
56
TONES = [62.5] + list(chirp_common.TONES)
57
TMODES =  ['','Tone','DTCS'] 
58
DUPLEXES = ['','err','-','+'] # index 2 not used
59
MODES = ['WFM','FM','NFM']  #  25k, 20k,15k bw 
60
TUNING_STEPS=[ 5.0, 6.25, 8.33, 10.0, 12.5, 15.0, 20.0, 25.0, 30.0, 50.0 ] # index 0-9
61
POWER_LEVELS=[chirp_common.PowerLevel("High", watts=65),
62
              chirp_common.PowerLevel("Mid", watts=25),
63
              chirp_common.PowerLevel("Low", watts=10)]
64

  
65
CROSS_MODES = chirp_common.CROSS_MODES
66
VALID_MODEL = ['TH-9000']
67

  
68
APO_LIST = [ "Off","30 min","1 hr","2 hrs" ] 
69
BGCOLOR_LIST = ["Blue","Orange","Purple"]
70
BGBRIGHT_LIST = ["%s" % x for x in range(1,32)]
71
SQUELCH_LIST = ["Off"] + ["Level %s" % x for x in range(1,20)] 
72
TIMEOUT_LIST = ["Off"] + ["%s min" % x for x in range(1,30)]
73
TXPWR_LIST = ["60W","25W"]  # maximum power for Hi setting
74
TBSTFREQ_LIST = ["1750Hz","2100Hz","1000Hz","1450Hz"]
75
BEEP_LIST = ["Off","On"]
76

  
77
SETTING_LISTS = {
78
        "auto_power_off": APO_LIST,
79
        "bg_color"      : BGCOLOR_LIST,
80
        "bg_brightness" : BGBRIGHT_LIST,
81
        "squelch"       : SQUELCH_LIST,
82
        "timeout_timer" : TIMEOUT_LIST,
83
        "choose_tx_power": TXPWR_LIST,
84
        "tbst_freq"     : TBSTFREQ_LIST,
85
        "voice_prompt"  : BEEP_LIST
86
}
87

  
88

  
89
#
90
#
91
#
92
"""
93
Overall Memory Map:
94

  
95
    Memory Map (Range 0x0100-3FF0, step 0x10):
96

  
97
        Field                   Start  End  Size   
98
                                (hex)  (hex) (hex)  
99
        
100
        1 Channel Set Flag        0100  011F   20 
101
        2 Channel Skip Flag       0120  013F   20 
102
        3 Blank/Unknown           0140  01EF   B0 
103
        4 Unknown                 01F0  01FF   10
104
        5 TX/RX Range             0200  020F   10    
105
        6 Bootup Passwd           0210  021F   10 
106
        7 Options, Radio          0220  023F   20
107
        8 Unknown                 0240  019F   
108
            8B Startup Label      03E0  03E7   07
109
        9 Channel Bank            2000  38FF 1900  
110
             Channel 000          2000  201F   20  
111
             Channel 001          2020  202F   20  
112
             ... 
113
             Channel 199          38E0  38FF   20 
114
        10 Blank/Unknown          3900  3FFF  6FF  14592  16383    1792   
115
            Total Map Size           16128 (2^8 = 16384)
116

  
117

  
118
"""
119

  
120
"""
121
  TH9000/VHF  memory map 
122
  section: 1 and 2:  Channel Set/Skip Flags
123

  
124
    Channel Set (starts 0x100) : Channel Set  bit is value 0 if a memory location in the channel bank is active.
125
    Channel Skip (starts 0x120): Channel Skip bit is value 0 if a memory location in the channel bank is active.
126

  
127
    Both flag maps are a total 24 bytes in length, aligned on 32 byte records.
128
    bit = 0 channel set/no skip,  1 is channel not set/skip
129

  
130
    to index a channel:
131
        cbyte = channel / 8 ;
132
        cbit  = channel % 8 ;
133
        setflag  = csetflag[cbyte].c[cbit] ;
134
        skipflag = cskipflag[cbyte].c[cbit] ;
135

  
136
    channel range is 0-199, range is 32 bytes (last 7 unknown)
137
"""
138

  
139

  
140
MEM_FORMAT = """
141
#seekto 0x0100;
142
struct {
143
   bit c[8];
144
} csetflag[32];
145

  
146
struct {
147
   u8 unknown0100[7];
148
} ropt0100;
149

  
150
#seekto 0x0120;
151
struct {
152
   bit c[8];
153
} cskipflag[32];
154

  
155
struct {
156
   u8 unknown0120[7];
157
} ropt0120;
158
"""
159

  
160
"""
161
  TH9000/VHF  memory map 
162
  section: 5  TX/RX Range
163
     used to set the TX/RX range of the radio (e.g.  144-148Mhz for 2 meter)
164
     possible to set range to 136-172Mhz for tx/rx 
165

  
166
"""
167

  
168

  
169
MEM_FORMAT = MEM_FORMAT + """
170
#seekto 0x0200;
171
struct {
172
    bbcd txrangelow[4];
173
    bbcd txrangehi[4];
174
    bbcd rxrangelow[4];
175
    bbcd rxrangehi[4];
176
} freqrange;
177
"""
178

  
179
"""
180
  TH9000/VHF  memory map 
181
  section: 6  bootup_passwd
182
     used to set bootup passwd (see boot_passwd checkbox option)
183

  
184
  options - bootup password
185

  
186
  bytes:bit   type                 description
187
  ---------------------------------------------------------------------------
188
  6         u8 bootup_passwd[6]     bootup passwd, 6 chars, numberic chars 30-39 , see boot_passwd checkbox to set
189
  10        u8 unknown;  
190

  
191
"""
192

  
193
MEM_FORMAT = MEM_FORMAT + """
194
#seekto 0x0210;
195
struct {
196
   u8 bootup_passwd[6];
197
   u8 unknown2010[10];
198
} ropt0210;
199
"""
200

  
201
"""
202
  TH9000/VHF  memory map 
203
  section: 7  Radio Options  
204
        used to set a number of radio options 
205

  
206
  bytes:bit   type                 description
207
  ---------------------------------------------------------------------------
208
  1         u8 display_mode     display mode, range 0-2, 0=freq,1=channel,2=name (selecting name affects vfo_mr)
209
  1         u8 vfo_mr;          vfo_mr , 0=vfo, mr=1 
210
  1         u8 unknown;  
211
  1         u8 squelch;         squelch level, range 0-19, hex for menu
212
  1         u8 unknown[2]; 
213
  1         u8 channel_lock;    if display_mode[channel] selected, then lock=1,no lock =0
214
  1         u8 unknown; 
215
  1         u8 bg_brightness ;  background brightness, range 0-21, hex, menu index 
216
  1         u8 unknown;     
217
  1         u8 bg_color ;       bg color, menu index,  blue 0 , orange 1, purple 2
218
  1         u8 tbst_freq ;      tbst freq , menu 0 = 1750Hz, 1=2100 , 2=1000 , 3=1450hz 
219
  1         u8 timeout_timer;   timeout timer, hex, value = minutes, 0= no timeout
220
  1         u8 unknown; 
221
  1         u8 auto_power_off;   auto power off, range 0-3, off,30min, 1hr, 2hr, hex menu index
222
  1         u8 voice_prompt;     voice prompt, value 0,1 , Beep ON = 1, Beep Off = 2
223

  
224
 description of function setup options, starting at 0x0230
225

  
226
  bytes:bit   type                 description
227
  ---------------------------------------------------------------------------
228
  1         u8  // 0
229
   :4       unknown:6
230
   :1       elim_sql_tail:1   eliminate squelsh tail when no ctcss checkbox (1=checked)
231
   :1       sql_key_function  "squelch off" 1 , "squelch momentary off" 0 , menu index
232
  2         u8 unknown[2] /1-2  
233
  1         u8 // 3
234
   :4       unknown:4
235
   :1       inhibit_init_ops:1 //bit 5
236
   :1       unknownD:1
237
   :1       inhibit_setup_bg_chk:1 //bit 7
238
   :1       unknown:1
239
  1         u8 tail_elim_type    menu , (off=0,120=1,180=2),  // 4
240
  1         u8 choose_tx_power    menu , (60w=0,25w=1) // 5
241
  2         u8 unknown[2]; // 6-7 
242
  1         u8 bootup_passwd_flag  checkbox 1=on, 0=off // 8
243
  7         u8 unknown[7]; // 9-F 
244

  
245
"""
246

  
247
MEM_FORMAT = MEM_FORMAT + """
248
#seekto 0x0220;
249
struct {
250
   u8 display_mode; 
251
   u8 vfo_mr; 
252
   u8 unknown0220A; 
253
   u8 squelch; 
254
   u8 unknown0220B[2]; 
255
   u8 channel_lock; 
256
   u8 unknown0220C; 
257
   u8 bg_brightness; 
258
   u8 unknown0220D; 
259
   u8 bg_color;
260
   u8 tbst_freq;
261
   u8 timeout_timer;
262
   u8 unknown0220E;
263
   u8 auto_power_off;
264
   u8 voice_prompt; 
265
   u8 unknown0230A:6,
266
      elim_sql_tail:1,
267
      sql_key_function:1;
268
   u8 unknown0230B[2];
269
   u8 unknown0230C:4, 
270
      inhibit_init_ops:1,
271
      unknown0230D:1,
272
      inhibit_setup_bg_chk:1,
273
      unknown0230E:1;
274
   u8 tail_elim_type;
275
   u8 choose_tx_power;
276
   u8 unknown0230F[2];
277
   u8 bootup_passwd_flag;
278
   u8 unknown0230G[7];
279
} settings;
280
"""
281

  
282
"""
283
  TH9000/VHF  memory map 
284
  section: 8B  Startup Label  
285

  
286
  bytes:bit   type                 description
287
  ---------------------------------------------------------------------------
288
  7     char start_label[7]    label displayed at startup (usually your call sign)
289
"""
290
MEM_FORMAT = MEM_FORMAT + """
291
#seekto 0x03E0;
292
struct {
293
    char startname[7];
294
} slabel;
295
"""
296

  
297
"""
298
  TH9000/VHF  memory map 
299
  section: 9  Channel Bank
300
         description of channel bank (200 channels , range 0-199)
301
         Each 32 Byte (0x20 hex)  record:
302
  bytes:bit   type                 description
303
  ---------------------------------------------------------------------------
304
  4         bbcd freq[4]        receive frequency in packed binary coded decimal  
305
  4         bbcd offset[4]      transmit offset in packed binary coded decimal (note: plus/minus direction set by 'duplex' field)
306
  1         u8
307
   :4       unknown:4
308
   :4       tuning_step:4         tuning step, menu index value from 0-9
309
            5,6.25,8.33,10,12.5,15,20,25,30,50
310
  1         u8
311
   :4       unknown:4          not yet decoded, used for DCS coding?
312
   :2       channel_width:2     channel spacing, menu index value from 0-3
313
            25,20,12.5
314
   :1       reverse:1           reverse flag, 0=off, 1=on (reverses tx and rx freqs)
315
   :1       txoff:1             transmitt off flag, 0=transmit , 1=do not transmit 
316
  1         u8
317
   :1       talkaround:1        talkaround flag, 0=off, 1=on (bypasses repeater) 
318
   :1       compander:1         compander flag, 0=off, 1=on (turns on/off voice compander option)  
319
   :2       unknown:2          
320
   :2       power:2             tx power setting, value range 0-2, 0=hi,1=med,2=lo 
321
   :2       duplex:2            duplex settings, 0=simplex,2= minus(-) offset, 3= plus (+) offset (see offset field) 
322
            
323
  1         u8 
324
   :4       unknown:4
325
   :2       rxtmode:2           rx tone mode, value range 0-2, 0=none, 1=CTCSS, 2=DCS  (ctcss tone in field rxtone)
326
   :2       txtmode:2           tx tone mode, value range 0-2, 0=none, 1=CTCSS, 3=DCS  (ctcss tone in field txtone)
327
  1         u8 
328
   :2       unknown:2
329
   :6       txtone:6            tx ctcss tone, menu index
330
  1         u8 
331
   :2       unknown:2 
332
   :6       rxtone:6            rx ctcss tone, menu index
333
  1         u8 txcode           ?, not used for ctcss
334
  1         u8 rxcode           ?, not used for ctcss
335
  3         u8 unknown[3]
336
  7         char name[7]        7 byte char string for channel name
337
  1         u8 
338
   :6       unknown:6,
339
   :2       busychannellockout:2 busy channel lockout option , 0=off, 1=repeater, 2=busy  (lock out tx if channel busy)
340
  4         u8 unknownI[4];
341
  1         u8 
342
   :7       unknown:7 
343
   :1       scrambler:1         scrambler flag, 0=off, 1=on (turns on tyt scrambler option)
344
"""
345

  
346

  
347

  
348
MEM_FORMAT = MEM_FORMAT + """
349
#seekto 0x2000;
350
struct {
351
  bbcd freq[4];
352
  bbcd offset[4];
353
  u8 unknown2000A:4,
354
     tuning_step:4;
355
  u8 unknown2000B:4,
356
     channel_width:2,
357
     reverse:1,
358
     txoff:1;
359
  u8 talkaround:1,
360
     compander:1,
361
     unknown2000C:2,
362
     power:2,
363
     duplex:2;
364
  u8 unknown2000D:4,
365
     rxtmode:2,
366
     txtmode:2;
367
  u8 unknown2000E:2,
368
     txtone:6;
369
  u8 unknown2000F:2,
370
     rxtone:6;
371
  u8 txcode;
372
  u8 rxcode;
373
  u8 unknown2000G[3];
374
  char name[7];
375
  u8 unknown2000H:6,
376
     busychannellockout:2;
377
  u8 unknown2000I[4];
378
  u8 unknown2000J:7,
379
     scrambler:1; 
380
} memory[200] ;
381
"""
382

  
383

  
384
def _debug(string):
385
    if "CHIRP_DEBUG" in os.environ or True:
386
        print string
387

  
388
def _echo_write(radio, data):
389
    try:
390
        radio.pipe.write(data)
391
        radio.pipe.read(len(data))
392
    except Exception, e:
393
        print "Error writing to radio: %s" % e
394
        raise errors.RadioError("Unable to write to radio")
395

  
396

  
397
def _checksum(data):
398
    cs = 0
399
    for byte in data:
400
        cs += ord(byte)
401
    return cs % 256
402

  
403
def _read(radio, length):
404
    try:
405
        data = radio.pipe.read(length)
406
    except Exception, e:
407
        print "Error reading from radio: %s" % e
408
        raise errors.RadioError("Unable to read from radio")
409

  
410
    if len(data) != length:
411
        print "Short read from radio (%i, expected %i)" % (len(data),
412
                                                           length)
413
        print util.hexprint(data)
414
        raise errors.RadioError("Short read from radio")
415
    return data
416

  
417

  
418

  
419
def _ident(radio):
420
    radio.pipe.setTimeout(1)
421
    _echo_write(radio,"PROGRAM")
422
    response = radio.pipe.read(3)
423
    if response != "QX\06":
424
        print "Response was :\n%s" % util.hexprint(response)
425
        raise errors.RadioError("Unsupported model")
426
    _echo_write(radio, "\x02")
427
    response = radio.pipe.read(16)
428
    _debug(util.hexprint(response))
429
    if response[1:8] != "TH-9000":
430
        print "Looking  for:\n%s" % util.hexprint("TH-9000")
431
        print "Response was:\n%s" % util.hexprint(response)
432
        raise errors.RadioError("Unsupported model")
433

  
434
def _send(radio, cmd, addr, length, data=None):
435
    frame = struct.pack(">cHb", cmd, addr, length)
436
    if data:
437
        frame += data
438
        frame += chr(_checksum(frame[1:]))
439
        frame += "\x06"
440
    _echo_write(radio, frame)
441
    _debug("Sent:\n%s" % util.hexprint(frame))
442
    if data:
443
        result = radio.pipe.read(1)
444
        if result != "\x06":
445
            print "Ack was: %s" % repr(result)
446
            raise errors.RadioError("Radio did not accept block at %04x" % addr)
447
        return
448
    result = _read(radio, length + 6)
449
    _debug("Got:\n%s" % util.hexprint(result))
450
    header = result[0:4]
451
    data = result[4:-2]
452
    ack = result[-1]
453
    if ack != "\x06":
454
        print "Ack was: %s" % repr(ack)
455
        raise errors.RadioError("Radio NAK'd block at %04x" % addr)
456
    _cmd, _addr, _length = struct.unpack(">cHb", header)
457
    if _addr != addr or _length != _length:
458
        print "Expected/Received:"
459
        print " Length: %02x/%02x" % (length, _length)
460
        print " Addr: %04x/%04x" % (addr, _addr)
461
        raise errors.RadioError("Radio send unexpected block")
462
    cs = _checksum(result[1:-2])
463
    if cs != ord(result[-2]):
464
        print "Calculated: %02x" % cs
465
        print "Actual:     %02x" % ord(result[-2])
466
        raise errors.RadioError("Block at 0x%04x failed checksum" % addr)
467
    return data
468

  
469

  
470
def _finish(radio):
471
    endframe = "\x45\x4E\x44"
472
    _echo_write(radio, endframe)
473
    result = radio.pipe.read(1)
474
    if result != "\x06":
475
        print "Got:\n%s" % util.hexprint(result)
476
        raise errors.RadioError("Radio did not finish cleanly")
477

  
478
def do_download(radio):
479

  
480
    _ident(radio)
481

  
482
    _memobj = None
483
    data = ""
484

  
485
    for start,end in radio._ranges: 
486
        for addr in range(start,end,0x10):
487
            block = _send(radio,'R',addr,0x10) 
488
            data += block
489
            status = chirp_common.Status()
490
            status.cur = len(data)
491
            status.max = end
492
            status.msg = "Downloading from radio"
493
            radio.status_fn(status)
494

  
495
    _finish(radio)
496

  
497
    return memmap.MemoryMap(data)
498

  
499
def do_upload(radio):
500

  
501
    _ident(radio)
502

  
503
    for start,end in radio._ranges:
504
        for addr in range(start,end,0x10):
505
            if addr < 0x0100:
506
                continue
507
            block = radio._mmap[addr:addr+0x10]
508
            _send(radio,'W',addr,len(block),block)
509
            status = chirp_common.Status()
510
            status.cur = addr
511
            status.max = end
512
            status.msg = "Uploading to Radio"
513
            radio.status_fn(status)
514

  
515
    _finish(radio)
516
            
517

  
518

  
519
@directory.register
520
class Th9000VHFRadio(chirp_common.CloneModeRadio):
521
    """TYT TH-9000 VHF"""
522
    VENDOR = "TYT"    
523
    MODEL = "TH9000" 
524
    BAUD_RATE = 9600 
525
    _file_ident = "TH-9000"
526

  
527
    _memsize = MMAPSIZE
528
    _ranges = [(0x0000,0x4000)]
529

  
530
    @classmethod
531
    def get_prompts(cls):
532
        rp = chirp_common.RadioPrompts()
533
        rp.experimental = ("The TYT TH-9000 driver is an alpha version."
534
                           "Use only for testing and development"
535
                           "Proceed with Caution and backup your data"
536
                           "as you may lose it using this driver!")
537
        return rp
538

  
539
    def get_features(self):
540
        rf = chirp_common.RadioFeatures()
541
        rf.has_settings = True
542
        rf.has_bank = False
543
        rf.has_cross = True
544
        rf.has_tuning_step = False
545
        rf.has_rx_dtcs = True
546
        rf.valid_skips = ["","S"]
547
        rf.memory_bounds = (0, 199) 
548
        rf.valid_name_length = 7
549
        rf.valid_characters = chirp_common.CHARSET_UPPER_NUMERIC + "-"
550
        rf.valid_modes = MODES
551
        rf.valid_tmodes = chirp_common.TONE_MODES
552
        rf.valid_cross_modes = CROSS_MODES
553
        rf.valid_power_levels = POWER_LEVELS
554
        rf.valid_dtcs_codes = chirp_common.ALL_DTCS_CODES
555
        rf.valid_bands = [(136000000, 174000000)]
556
        return rf
557

  
558
    # Do a download of the radio from the serial port
559
    def sync_in(self):
560
        self._mmap = do_download(self)
561
        self.process_mmap()
562

  
563
    # Do an upload of the radio to the serial port
564
    def sync_out(self):
565
        do_upload(self)
566

  
567
    def process_mmap(self):
568
        self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
569

  
570

  
571
    # Return a raw representation of the memory object, which 
572
    # is very helpful for development
573
    def get_raw_memory(self, number):
574
        return repr(self._memobj.memory[number])
575

  
576

  
577
    # not working
578
    def _get_dcs_index(self, _mem,which):
579
        base = getattr(_mem, '%scode' % which)
580
        extra = getattr(_mem, '%sdcsextra' % which)
581
        return (int(extra) << 8) | int(base)
582

  
583
    def _set_dcs_index(self, _mem, which, index):
584
        base = getattr(_mem, '%scode' % which)
585
        extra = getattr(_mem, '%sdcsextra' % which)
586
        base.set_value(index & 0xFF)
587
        extra.set_value(index >> 8)
588

  
589

  
590
    # Extract a high-level memory object from the low-level memory map
591
    # This is called to populate a memory in the UI
592
    def get_memory(self, number):
593
        # Get a low-level memory object mapped to the image
594
        _mem = self._memobj.memory[number]
595

  
596
        # get flag info
597
        cbyte = number / 8 ;
598
        cbit =  7 - (number % 8) ;
599
        setflag = self._memobj.csetflag[cbyte].c[cbit]; 
600
        skipflag = self._memobj.cskipflag[cbyte].c[cbit]; 
601

  
602
        mem = chirp_common.Memory()
603

  
604
        mem.number = number  # Set the memory number
605

  
606
        if setflag == 1:
607
            mem.empty = True
608
            return mem
609

  
610
        mem.freq = int(_mem.freq) * 100    
611
        mem.offset = int(_mem.offset) * 100
612
        mem.name = str(_mem.name).rstrip() # Set the alpha tag
613
        mem.duplex = DUPLEXES[_mem.duplex]
614
        mem.mode = MODES[_mem.channel_width]
615
        mem.power = POWER_LEVELS[_mem.power]
616

  
617
        rxtone = txtone = None
618

  
619

  
620
        rxmode = TMODES[_mem.rxtmode]
621
        txmode = TMODES[_mem.txtmode]
622

  
623

  
624
        rxpol = txpol =  ""
625

  
626
        # doesn't work
627
        if rxmode == "Tone":
628
            rxpol = ""
629
            rxtone = TONES[_mem.rxtone]
630
        elif rxmode == "DTCS":
631
            rxpol = "N"
632
            rxtone = chirp_common.ALL_DTCS_CODES[self._get_dcs_index(_mem,'rx')]
633

  
634
        if txmode == "Tone":
635
            txpol = ""
636
            txtone = TONES[_mem.txtone]
637
        elif txmode == "DTCS":
638
            txpol = "N"
639
            txtone = chirp_common.ALL_DTCS_CODES[self._get_dcs_index(_mem,'tx')]
640

  
641

  
642
        chirp_common.split_tone_decode(mem,
643
                                       (txmode, txtone, txpol),
644
                                       (rxmode, rxtone, rxpol))
645

  
646
        mem.skip = "S" if skipflag == 1 else ""
647

  
648

  
649
        # We'll consider any blank (i.e. 0MHz frequency) to be empty
650
        if mem.freq == 0:
651
            mem.empty = True
652

  
653
        return mem
654

  
655
    # Store details about a high-level memory to the memory map
656
    # This is called when a user edits a memory in the UI
657
    def set_memory(self, mem):
658
        # Get a low-level memory object mapped to the image
659

  
660
        _mem = self._memobj.memory[mem.number]
661

  
662
        cbyte = mem.number / 8 
663
        cbit =  7 - (mem.number % 8) 
664

  
665
        if mem.empty:
666
            self._memobj.csetflag[cbyte].c[cbit] = 1
667
            self._memobj.cskipflag[cbyte].c[cbit] = 1
668
            return
669

  
670
        self._memobj.csetflag[cbyte].c[cbit] =  0 
671
        self._memobj.cskipflag[cbyte].c[cbit]  =  1 if (mem.skip == "S") else 0
672

  
673
        _mem.set_raw("\x00" * 32)
674

  
675
        _mem.freq = mem.freq / 100         # Convert to low-level frequency
676
        _mem.offset = mem.offset / 100         # Convert to low-level frequency
677

  
678
        _mem.name = mem.name.ljust(7)[:7]  # Store the alpha tag
679
        _mem.duplex = DUPLEXES.index(mem.duplex)
680

  
681

  
682
        try:
683
            _mem.channel_width = MODES.index(mem.mode)
684
        except ValueError:
685
            _mem.channel_width = 0
686

  
687
        ((txmode, txtone, txpol),
688
         (rxmode, rxtone, rxpol)) = chirp_common.split_tone_encode(mem)
689

  
690
        _mem.txtmode = TMODES.index(txmode)
691
        _mem.rxtmode = TMODES.index(rxmode)
692

  
693
        if txmode == "Tone":
694
            _mem.txtone = TONES.index(txtone)
695
        elif txmode == "DTCS":
696
            self._set_dcs_index(_mem,'tx',chirp_common.ALL_DTCS_CODES.index(txtone))
697

  
698
        if rxmode == "Tone":
699
            _mem.rxtone = TONES.index(rxtone)
700
        elif rxmode == "DTCS":
701
            self._set_dcs_index(_mem, 'rx', chirp_common.ALL_DTCS_CODES.index(rxtone))
702

  
703
        #_mem.txinv = txpol == "N"
704
        #_mem.rxinv = rxpol == "N"
705

  
706
       
707
        if mem.power:
708
            _mem.power = POWER_LEVELS.index(mem.power)
709
        else:
710
            _mem.power = 0
711

  
712
    def _get_settings(self):
713
        _settings = self._memobj.settings
714
        _freqrange = self._memobj.freqrange
715
        _slabel = self._memobj.slabel
716

  
717
        basic = RadioSettingGroup("basic","Global Settings")
718
        freqrange = RadioSettingGroup("freqrange","Frequency Ranges")
719
        top = RadioSettingGroup("top","All Settings",basic,freqrange)
720

  
721
        def _filter(name):
722
            filtered = ""
723
            for char in str(name):
724
                if char in chirp_common.CHARSET_ASCII:
725
                    filtered += char
726
                else:
727
                    filtered += ""
728
            return filtered
729
                   
730
        val = RadioSettingValueString(0,7,_filter(_slabel.startname))
731
        rs = RadioSetting("startname","Startup Label",val)
732
        basic.append(rs)
733

  
734
        rs = RadioSetting("bg_color","LCD Color",
735
                           RadioSettingValueList(BGCOLOR_LIST, BGCOLOR_LIST[_settings.bg_color]))
736
        basic.append(rs)
737

  
738
        rs = RadioSetting("bg_brightness","LCD Brightness",
739
                           RadioSettingValueList(BGBRIGHT_LIST, BGBRIGHT_LIST[_settings.bg_brightness]))
740
        basic.append(rs)
741

  
742
        rs = RadioSetting("squelch","Squelch Level",
743
                           RadioSettingValueList(SQUELCH_LIST, SQUELCH_LIST[_settings.squelch]))
744
        basic.append(rs)
745

  
746
        rs = RadioSetting("timeout_timer","Timeout Timer (TOT)",
747
                           RadioSettingValueList(TIMEOUT_LIST, TIMEOUT_LIST[_settings.timeout_timer]))
748
        basic.append(rs)
749

  
750
        rs = RadioSetting("auto_power_off","Auto Power Off (APO)",
751
                           RadioSettingValueList(APO_LIST, APO_LIST[_settings.auto_power_off]))
752
        basic.append(rs)
753

  
754
        rs = RadioSetting("voice_prompt","Beep Prompt",
755
                           RadioSettingValueList(BEEP_LIST, BEEP_LIST[_settings.voice_prompt]))
756
        basic.append(rs)
757

  
758
        rs = RadioSetting("tbst_freq","Tone Burst Frequency",
759
                           RadioSettingValueList(TBSTFREQ_LIST, TBSTFREQ_LIST[_settings.tbst_freq]))
760
        basic.append(rs)
761

  
762
        rs = RadioSetting("choose_tx_power","Max Level of TX Power",
763
                           RadioSettingValueList(TXPWR_LIST, TXPWR_LIST[_settings.choose_tx_power]))
764
        basic.append(rs)
765

  
766
        rs = RadioSetting("txrangelow","TX Freq, Lower Limit (khz)", RadioSettingValueInteger(136000,144000, int(_freqrange.txrangelow)/10))
767
        freqrange.append(rs)
768

  
769
        rs = RadioSetting("txrangehi","TX Freq, Upper Limit (khz)", RadioSettingValueInteger(148000,174000,int(_freqrange.txrangehi)/10))
770
        freqrange.append(rs)
771

  
772
        rs = RadioSetting("rxrangelow","RX Freq, Lower Limit (khz)", RadioSettingValueInteger(136000,144000, int(_freqrange.rxrangelow)/10))
773
        freqrange.append(rs)
774

  
775
        rs = RadioSetting("rxrangehi","RX Freq, Upper Limit (khz)", RadioSettingValueInteger(148000,174000,int(_freqrange.rxrangehi)/10))
776
        freqrange.append(rs)
777

  
778
        return top
779

  
780
    def get_settings(self):
781
        try:
782
            return self._get_settings()
783
        except:
784
            import traceback
785
            print "failed to parse settings"
786
            traceback.print_exc()
787
            return None
788

  
789
    def set_settings(self,settings):
790
        _settings = self._memobj.settings
791
        for element in settings:
792
            if not isinstance(element,RadioSetting):
793
                self.set_settings(element)
794
                continue
795
            else:
796
                try:
797
                    name = element.get_name()
798

  
799
                    if  name in ["txrangelow","txrangehi","rxrangelow","rxrangehi"]:
800
                        print "setting %s = %s" % (name,int(element.value)*10)
801
                        setattr(self._memobj.freqrange,name,int(element.value)*10)
802
                        continue
803

  
804
                    if name in ["startname"]:
805
                        print "setting %s = %s" % (name, element.value)
806
                        setattr(self._memobj.slabel,name,element.value)
807
                        continue
808

  
809
                    obj = _settings
810
                    setting = element.get_name()
811

  
812
                    if element.has_apply_callback():
813
                        print "using apply callback"
814
                        element.run_apply_callback()
815
                    else:
816
                        print "Setting %s = %s" % (setting, element.value)
817
                        setattr(obj, setting, element.value)
818
                except Exception, e:
819
                    print element.get_name()
820
                    raise
821

  
822
    @classmethod
823
    def match_model(cls, filedata, filename):
824
        return cls._file_ident in filedata[0x10:0x20]
(5-5/14)