Project

General

Profile

New Model #1035 » th9000-003.patch

David Fannin, 05/14/2014 03:03 PM

View differences:

/dev/null Thu Jan 01 00:00:00 1970 +0000 → chirp/th9000vhf.py Mon May 12 10:04:50 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

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

  
46

  
47
#
48
# Global Parameters 
49
#
50
MMAPSIZE = 16128
51
TONES = [62.5] + list(chirp_common.TONES)
52
TMODES =  ['','Tone','DTCS'] 
53
DUPLEXES = ['','err','-','+'] # index 2 not used
54
MODES = ['WFM','FM','NFM']  #  25k, 20k,15k bw 
55
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
56
POWER_LEVELS=[chirp_common.PowerLevel("High", watts=65),
57
              chirp_common.PowerLevel("Mid", watts=25),
58
              chirp_common.PowerLevel("Low", watts=10)]
59

  
60
CROSS_MODES = chirp_common.CROSS_MODES
61
VALID_MODEL = ['TH-9000']
62

  
63

  
64
#
65
#
66
#
67

  
68
MEM_FORMAT = """
69
#seekto 0x0100;
70
struct {
71
   bit c[8];
72
} csetflag[24];
73

  
74
struct {
75
   u8 unknown0100[7];
76
} ropt0100;
77

  
78
#seekto 0x0120;
79
struct {
80
   bit c[8];
81
} cskipflag[24];
82

  
83
struct {
84
   u8 unknown0120[7];
85
} ropt0120;
86
"""
87

  
88
MEM_FORMAT = MEM_FORMAT + """
89
#seekto 0x0200;
90
struct {
91
    bbcd txrangelow[4];
92
    bbcd txrangehi[4];
93
    bbcd rxrangelow[4];
94
    bbcd rxrangehi[4];
95
} ropt0200;
96
"""
97

  
98
MEM_FORMAT = MEM_FORMAT + """
99
#seekto 0x0210;
100
struct {
101
   u8 bootup_passwd[6];
102
   u8 unknown2010[10];
103
} ropt0210;
104
"""
105

  
106
MEM_FORMAT = MEM_FORMAT + """
107
#seekto 0x0220;
108
struct {
109
   u8 display_mode; 
110
   u8 vfo_mr; 
111
   u8 unknown0220A; 
112
   u8 squelch; 
113
   u8 unknown0220B[2]; 
114
   u8 channel_lock; 
115
   u8 unknown0220C; 
116
   u8 bg_brightness; 
117
   u8 unknown0220D; 
118
   u8 bg_color;
119
   u8 tbst_freq;
120
   u8 timeout_timer;
121
   u8 unknown0220E;
122
   u8 auto_power_off;
123
   u8 voice_prompt; 
124
} ropt0220;
125
"""
126

  
127
MEM_FORMAT = MEM_FORMAT + """
128
#seekto 0x0230;
129
struct {
130
   u8 unknown0230A:6,
131
      elim_sql_tail:1,
132
      sql_key_function:1;
133
   u8 unknown0230B[2];
134
   u8 unknown0230C:4, 
135
      inhibit_init_ops:1,
136
      unknown0230D:1,
137
      inhibit_setup_bg_chk:1,
138
      unknown0230E:1;
139
   u8 tail_elim_type;
140
   u8 choose_tx_power;
141
   u8 unknown0230F[2];
142
   u8 bootup_passwd_flag;
143
   u8 unknown0230G[7];
144
}ropt0230;
145
"""
146

  
147

  
148

  
149
MEM_FORMAT = MEM_FORMAT + """
150
#seekto 0x2000;
151
struct {
152
  bbcd freq[4];
153
  bbcd offset[4];
154
  u8 unknown2000A:4,
155
     tune_step:4;
156
  u8 unknown2000B:4,
157
     channel_width:2,
158
     reverse:1,
159
     txoff:1;
160
  u8 talkaround:1,
161
     compander:1,
162
     unknown2000C:2,
163
     power:2,
164
     duplex:2;
165
  u8 unknown2000D:4,
166
     rxtmode:2,
167
     txtmode:2;
168
  u8 unknown2000E:2,
169
     txtone:6;
170
  u8 unknown2000F:2,
171
     rxtone:6;
172
  u8 txcode;
173
  u8 rxcode;
174
  u8 unknown2000G[3];
175
  char name[7];
176
  u8 unknown2000H:6,
177
     busychannellockout:2;
178
  u8 unknown2000I[4];
179
  u8 unknown2000J:7,
180
     scrambler:1; 
181
} memory[200] ;
182
"""
183

  
184

  
185
def _debug(string):
186
    if "CHIRP_DEBUG" in os.environ or True:
187
        print string
188

  
189
def _echo_write(radio, data):
190
    try:
191
        radio.pipe.write(data)
192
        radio.pipe.read(len(data))
193
    except Exception, e:
194
        print "Error writing to radio: %s" % e
195
        raise errors.RadioError("Unable to write to radio")
196

  
197

  
198
def _checksum(data):
199
    cs = 0
200
    for byte in data:
201
        cs += ord(byte)
202
    return cs % 256
203

  
204
def _read(radio, length):
205
    try:
206
        data = radio.pipe.read(length)
207
    except Exception, e:
208
        print "Error reading from radio: %s" % e
209
        raise errors.RadioError("Unable to read from radio")
210

  
211
    if len(data) != length:
212
        print "Short read from radio (%i, expected %i)" % (len(data),
213
                                                           length)
214
        print util.hexprint(data)
215
        raise errors.RadioError("Short read from radio")
216
    return data
217

  
218

  
219

  
220
def _ident(radio):
221
    radio.pipe.setTimeout(1)
222
    _echo_write(radio,"PROGRAM")
223
    response = radio.pipe.read(3)
224
    if response != "QX\06":
225
        print "Response was :\n%s" % util.hexprint(response)
226
        raise errors.RadioError("Unsupported model")
227
    _echo_write(radio, "\x02")
228
    response = radio.pipe.read(16)
229
    _debug(util.hexprint(response))
230
    if response[1:8] != "TH-9000":
231
        print "Looking  for:\n%s" % util.hexprint("TH-9000")
232
        print "Response was:\n%s" % util.hexprint(response)
233
        raise errors.RadioError("Unsupported model")
234

  
235
def _send(radio, cmd, addr, length, data=None):
236
    frame = struct.pack(">cHb", cmd, addr, length)
237
    if data:
238
        frame += data
239
        frame += chr(_checksum(frame[1:]))
240
        frame += "\x06"
241
    _echo_write(radio, frame)
242
    _debug("Sent:\n%s" % util.hexprint(frame))
243
    if data:
244
        result = radio.pipe.read(1)
245
        if result != "\x06":
246
            print "Ack was: %s" % repr(result)
247
            raise errors.RadioError("Radio did not accept block at %04x" % addr)
248
        return
249
    result = _read(radio, length + 6)
250
    _debug("Got:\n%s" % util.hexprint(result))
251
    header = result[0:4]
252
    data = result[4:-2]
253
    ack = result[-1]
254
    if ack != "\x06":
255
        print "Ack was: %s" % repr(ack)
256
        raise errors.RadioError("Radio NAK'd block at %04x" % addr)
257
    _cmd, _addr, _length = struct.unpack(">cHb", header)
258
    if _addr != addr or _length != _length:
259
        print "Expected/Received:"
260
        print " Length: %02x/%02x" % (length, _length)
261
        print " Addr: %04x/%04x" % (addr, _addr)
262
        raise errors.RadioError("Radio send unexpected block")
263
    cs = _checksum(result[1:-2])
264
    if cs != ord(result[-2]):
265
        print "Calculated: %02x" % cs
266
        print "Actual:     %02x" % ord(result[-2])
267
        raise errors.RadioError("Block at 0x%04x failed checksum" % addr)
268
    return data
269

  
270

  
271
def _finish(radio):
272
    endframe = "\x45\x4E\x44"
273
    _echo_write(radio, endframe)
274
    result = radio.pipe.read(1)
275
    if result != "\x06":
276
        print "Got:\n%s" % util.hexprint(result)
277
        raise errors.RadioError("Radio did not finish cleanly")
278

  
279
def do_download(radio):
280

  
281
    print "download"
282

  
283
    _ident(radio)
284

  
285
    _memobj = None
286
    data = ""
287

  
288
    for start,end in radio._ranges: 
289
        for addr in range(start,end,0x10):
290
            block = _send(radio,'R',addr,0x10) 
291
            data += block
292
            status = chirp_common.Status()
293
            status.cur = len(data)
294
            status.max = end
295
            status.msg = "Cloning from radio"
296
            radio.status_fn(status)
297

  
298
    _finish(radio)
299

  
300
    return memmap.MemoryMap(data)
301

  
302
def do_upload(radio):
303
    """This is your upload function"""
304
    raise Exception("Upload not yet working.")
305
    return
306

  
307
    # Get the serial port connection
308
    serial = radio.pipe
309

  
310
    # Our fake radio is just a simple upload of 1000 bytes
311
    # to the serial port. Do that one byte at a time, reading
312
    # from our memory map
313
    for i in range(0, MMAPSIZE):
314
        serial.write(radio.get_mmap()[i])
315

  
316
@directory.register
317
class Th9000VHFRadio(chirp_common.CloneModeRadio):
318
    """TYT TH-9000 VHF"""
319
    VENDOR = "TYT"    
320
    MODEL = "TH9000" 
321
    BAUD_RATE = 9600 
322
    _file_ident = "TH-9000"
323

  
324
    _memsize = MMAPSIZE
325
    _ranges = [(0x0000,0x4000)]
326

  
327
    @classmethod
328
    def get_prompts(cls):
329
        rp = chirp_common.RadioPrompts()
330
        rp.experimental = ("The TYT TH-9000 driver is experimental."
331
                            "Proceed with Caution and backup your data")
332
        return rp
333

  
334
    def get_features(self):
335
        rf = chirp_common.RadioFeatures()
336
        rf.has_settings = False
337
        rf.has_bank = False
338
        rf.has_cross = True
339
        rf.has_tuning_step = True
340
        rf.has_rx_dtcs = True
341
        rf.valid_skips = ["","S","P"]
342
        rf.memory_bounds = (0, 199) 
343
        rf.valid_bands = [(136000000, 172000000)]
344
        rf.valid_name_length = 7
345
        rf.valid_characters = chirp_common.CHARSET_UPPER_NUMERIC + "-"
346
        rf.valid_modes = MODES
347
        rf.valid_tmodes = chirp_common.TONE_MODES
348
        rf.valid_cross_modes = CROSS_MODES
349
        rf.valid_power_levels = POWER_LEVELS
350
        rf.valid_dtcs_codes = chirp_common.ALL_DTCS_CODES
351
        return rf
352

  
353
    # Do a download of the radio from the serial port
354
    def sync_in(self):
355
        self._mmap = do_download(self)
356
        self.process_mmap()
357

  
358
    # Do an upload of the radio to the serial port
359
    def sync_out(self):
360
        do_upload(self)
361

  
362
    def process_mmap(self):
363
        self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
364

  
365

  
366
    # Return a raw representation of the memory object, which 
367
    # is very helpful for development
368
    def get_raw_memory(self, number):
369
        return repr(self._memobj.memory[number])
370

  
371

  
372
    # not working
373
    def _get_dcs_index(self, _mem,which):
374
        base = getattr(_mem, '%scode' % which)
375
        extra = getattr(_mem, '%sdcsextra' % which)
376
        return (int(extra) << 8) | int(base)
377

  
378
    def _set_dcs_index(self, _mem, which, index):
379
        base = getattr(_mem, '%scode' % which)
380
        extra = getattr(_mem, '%sdcsextra' % which)
381
        base.set_value(index & 0xFF)
382
        extra.set_value(index >> 8)
383

  
384

  
385

  
386
    # Extract a high-level memory object from the low-level memory map
387
    # This is called to populate a memory in the UI
388
    def get_memory(self, number):
389
        # Get a low-level memory object mapped to the image
390
        _mem = self._memobj.memory[number]
391

  
392
        # Create a high-level memory object to return to the UI
393
        mem = chirp_common.Memory()
394

  
395
        mem.number = number  # Set the memory number
396

  
397
        mem.freq = int(_mem.freq) * 100    
398
        mem.offset = int(_mem.offset) * 100
399
        mem.name = str(_mem.name).rstrip() # Set the alpha tag
400
        mem.duplex = DUPLEXES[_mem.duplex]
401
        mem.mode = MODES[_mem.channel_width]
402
        mem.power = POWER_LEVELS[_mem.power]
403

  
404
        rxtone = txtone = None
405

  
406

  
407
        rxmode = TMODES[_mem.rxtmode]
408
        txmode = TMODES[_mem.txtmode]
409

  
410

  
411
        # doesn't work
412
        if rxmode == "Tone":
413
            rxtone = TONES[_mem.rxtone]
414
        elif rxmode == "DTCS":
415
            rxtone = chirp_common.ALL_DTCS_CODES[self._get_dcs_index(_mem,'rx')]
416

  
417
        if txmode == "Tone":
418
            txtone = TONES[_mem.txtone]
419
        elif txmode == "DTCS":
420
            txtone = chirp_common.ALL_DTCS_CODES[self._get_dcs_index(_mem,'tx')]
421

  
422
        rxpol = ""
423
        txpol = ""
424

  
425
        chirp_common.split_tone_decode(mem,
426
                                       (txmode, txtone, txpol),
427
                                       (rxmode, rxtone, rxpol))
428
        mem.skip = ""
429

  
430

  
431
        # We'll consider any blank (i.e. 0MHz frequency) to be empty
432
        if mem.freq == 0:
433
            mem.empty = True
434

  
435
        return mem
436

  
437
    # Store details about a high-level memory to the memory map
438
    # This is called when a user edits a memory in the UI
439
    def set_memory(self, mem):
440
        # Get a low-level memory object mapped to the image
441
        _mem = self._memobj.memory[mem.number]
442

  
443
        _mem.freq = mem.freq / 100         # Convert to low-level frequency
444
        _mem.offset = mem.offset / 100         # Convert to low-level frequency
445

  
446
        _mem.name = mem.name.ljust(7)[:7]  # Store the alpha tag
447

  
448
@classmethod
449
def match_model(cls,filedata,filename):
450
    return cls._file_ident in filedata[0x00:0x30]
chirp/th9000vhf.py Mon May 12 10:04:50 2014 -0700 → chirp/th9000vhf.py Wed May 14 14:52:17 2014 -0700
23 23
from chirp import bitwise
24 24
from chirp import errors
25 25
from chirp import util
26
from chirp.settings import RadioSetting, RadioSettingGroup, \
27
        RadioSettingValueInteger, RadioSettingValueList, \
28
        RadioSettingValueBoolean, RadioSettingValueString, \
29
        RadioSettingValueFloat, InvalidValueError
26 30

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

  
......
60 64
CROSS_MODES = chirp_common.CROSS_MODES
61 65
VALID_MODEL = ['TH-9000']
62 66

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

  
76

  
77

  
78

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

  
63 90

  
64 91
#
65 92
#
......
69 96
#seekto 0x0100;
70 97
struct {
71 98
   bit c[8];
72
} csetflag[24];
99
} csetflag[32];
73 100

  
74 101
struct {
75 102
   u8 unknown0100[7];
......
78 105
#seekto 0x0120;
79 106
struct {
80 107
   bit c[8];
81
} cskipflag[24];
108
} cskipflag[32];
82 109

  
83 110
struct {
84 111
   u8 unknown0120[7];
......
92 119
    bbcd txrangehi[4];
93 120
    bbcd rxrangelow[4];
94 121
    bbcd rxrangehi[4];
95
} ropt0200;
122
} freqrange;
96 123
"""
97 124

  
98 125
MEM_FORMAT = MEM_FORMAT + """
......
121 148
   u8 unknown0220E;
122 149
   u8 auto_power_off;
123 150
   u8 voice_prompt; 
124
} ropt0220;
125
"""
126

  
127
MEM_FORMAT = MEM_FORMAT + """
128
#seekto 0x0230;
129
struct {
130 151
   u8 unknown0230A:6,
131 152
      elim_sql_tail:1,
132 153
      sql_key_function:1;
......
141 162
   u8 unknown0230F[2];
142 163
   u8 bootup_passwd_flag;
143 164
   u8 unknown0230G[7];
144
}ropt0230;
165
} settings;
145 166
"""
146 167

  
147 168

  
......
278 299

  
279 300
def do_download(radio):
280 301

  
281
    print "download"
282

  
283 302
    _ident(radio)
284 303

  
285 304
    _memobj = None
......
292 311
            status = chirp_common.Status()
293 312
            status.cur = len(data)
294 313
            status.max = end
295
            status.msg = "Cloning from radio"
314
            status.msg = "Downloading from radio"
296 315
            radio.status_fn(status)
297 316

  
298 317
    _finish(radio)
......
300 319
    return memmap.MemoryMap(data)
301 320

  
302 321
def do_upload(radio):
303
    """This is your upload function"""
304
    raise Exception("Upload not yet working.")
305
    return
306 322

  
307
    # Get the serial port connection
308
    serial = radio.pipe
323
    _ident(radio)
309 324

  
310
    # Our fake radio is just a simple upload of 1000 bytes
311
    # to the serial port. Do that one byte at a time, reading
312
    # from our memory map
313
    for i in range(0, MMAPSIZE):
314
        serial.write(radio.get_mmap()[i])
325
    for start,end in radio._ranges:
326
        for addr in range(start,end,0x10):
327
            if addr < 0x0100:
328
                continue
329
            block = radio._mmap[addr:addr+0x10]
330
            _send(radio,'W',addr,len(block),block)
331
            status = chirp_common.Status()
332
            status.cur = addr
333
            status.max = end
334
            status.msg = "Uploading to Radio"
335
            radio.status_fn(status)
336

  
337
    _finish(radio)
338
            
339

  
315 340

  
316 341
@directory.register
317 342
class Th9000VHFRadio(chirp_common.CloneModeRadio):
......
327 352
    @classmethod
328 353
    def get_prompts(cls):
329 354
        rp = chirp_common.RadioPrompts()
330
        rp.experimental = ("The TYT TH-9000 driver is experimental."
331
                            "Proceed with Caution and backup your data")
355
        rp.experimental = ("The TYT TH-9000 driver is an alpha version."
356
                           "Use only for testing and development"
357
                           "Proceed with Caution and backup your data"
358
                           "as you may lose it using this driver!")
332 359
        return rp
333 360

  
334 361
    def get_features(self):
335 362
        rf = chirp_common.RadioFeatures()
336
        rf.has_settings = False
363
        rf.has_settings = True
337 364
        rf.has_bank = False
338 365
        rf.has_cross = True
339 366
        rf.has_tuning_step = True
340 367
        rf.has_rx_dtcs = True
341
        rf.valid_skips = ["","S","P"]
368
        rf.valid_skips = ["","S"]
342 369
        rf.memory_bounds = (0, 199) 
343
        rf.valid_bands = [(136000000, 172000000)]
344 370
        rf.valid_name_length = 7
345 371
        rf.valid_characters = chirp_common.CHARSET_UPPER_NUMERIC + "-"
346 372
        rf.valid_modes = MODES
......
348 374
        rf.valid_cross_modes = CROSS_MODES
349 375
        rf.valid_power_levels = POWER_LEVELS
350 376
        rf.valid_dtcs_codes = chirp_common.ALL_DTCS_CODES
377
        rf.valid_bands = [(136000000, 174000000)]
351 378
        return rf
352 379

  
353 380
    # Do a download of the radio from the serial port
......
382 409
        extra.set_value(index >> 8)
383 410

  
384 411

  
385

  
386 412
    # Extract a high-level memory object from the low-level memory map
387 413
    # This is called to populate a memory in the UI
388 414
    def get_memory(self, number):
389 415
        # Get a low-level memory object mapped to the image
390 416
        _mem = self._memobj.memory[number]
391 417

  
392
        # Create a high-level memory object to return to the UI
418
        # get flag info
419
        cbyte = number / 8 ;
420
        cbit =  7 - (number % 8) ;
421
        setflag = self._memobj.csetflag[cbyte].c[cbit]; 
422
        skipflag = self._memobj.cskipflag[cbyte].c[cbit]; 
423

  
393 424
        mem = chirp_common.Memory()
394 425

  
395 426
        mem.number = number  # Set the memory number
396 427

  
428
        if setflag == 1:
429
            mem.empty = True
430
            return mem
431

  
397 432
        mem.freq = int(_mem.freq) * 100    
398 433
        mem.offset = int(_mem.offset) * 100
399 434
        mem.name = str(_mem.name).rstrip() # Set the alpha tag
......
408 443
        txmode = TMODES[_mem.txtmode]
409 444

  
410 445

  
446
        rxpol = txpol =  ""
447

  
411 448
        # doesn't work
412 449
        if rxmode == "Tone":
450
            rxpol = ""
413 451
            rxtone = TONES[_mem.rxtone]
414 452
        elif rxmode == "DTCS":
453
            rxpol = "N"
415 454
            rxtone = chirp_common.ALL_DTCS_CODES[self._get_dcs_index(_mem,'rx')]
416 455

  
417 456
        if txmode == "Tone":
457
            txpol = ""
418 458
            txtone = TONES[_mem.txtone]
419 459
        elif txmode == "DTCS":
460
            txpol = "N"
420 461
            txtone = chirp_common.ALL_DTCS_CODES[self._get_dcs_index(_mem,'tx')]
421 462

  
422
        rxpol = ""
423
        txpol = ""
424 463

  
425 464
        chirp_common.split_tone_decode(mem,
426 465
                                       (txmode, txtone, txpol),
427 466
                                       (rxmode, rxtone, rxpol))
428
        mem.skip = ""
467

  
468
        mem.skip = "S" if skipflag == 1 else ""
429 469

  
430 470

  
431 471
        # We'll consider any blank (i.e. 0MHz frequency) to be empty
......
438 478
    # This is called when a user edits a memory in the UI
439 479
    def set_memory(self, mem):
440 480
        # Get a low-level memory object mapped to the image
481

  
441 482
        _mem = self._memobj.memory[mem.number]
442 483

  
484
        cbyte = mem.number / 8 
485
        cbit =  7 - (mem.number % 8) 
486

  
487
        if mem.empty:
488
            self._memobj.csetflag[cbyte].c[cbit] = 1
489
            self._memobj.cskipflag[cbyte].c[cbit] = 1
490
            return
491

  
492
        self._memobj.csetflag[cbyte].c[cbit] =  0 
493
        self._memobj.cskipflag[cbyte].c[cbit]  =  1 if (mem.skip == "S") else 0
494

  
495
        _mem.set_raw("\x00" * 32)
496

  
443 497
        _mem.freq = mem.freq / 100         # Convert to low-level frequency
444 498
        _mem.offset = mem.offset / 100         # Convert to low-level frequency
445 499

  
446 500
        _mem.name = mem.name.ljust(7)[:7]  # Store the alpha tag
501
        _mem.duplex = DUPLEXES.index(mem.duplex)
447 502

  
448
@classmethod
449
def match_model(cls,filedata,filename):
450
    return cls._file_ident in filedata[0x00:0x30]
503

  
504
        try:
505
            _mem.channel_width = MODES.index(mem.mode)
506
        except ValueError:
507
            _mem.channel_width = 0
508

  
509
        ((txmode, txtone, txpol),
510
         (rxmode, rxtone, rxpol)) = chirp_common.split_tone_encode(mem)
511

  
512
        _mem.txtmode = TMODES.index(txmode)
513
        _mem.rxtmode = TMODES.index(rxmode)
514

  
515
        if txmode == "Tone":
516
            _mem.txtone = TONES.index(txtone)
517
        elif txmode == "DTCS":
518
            self._set_dcs_index(_mem,'tx',chirp_common.ALL_DTCS_CODES.index(txtone))
519

  
520
        if rxmode == "Tone":
521
            _mem.rxtone = TONES.index(rxtone)
522
        elif rxmode == "DTCS":
523
            self._set_dcs_index(_mem, 'rx', chirp_common.ALL_DTCS_CODES.index(rxtone))
524

  
525
        #_mem.txinv = txpol == "N"
526
        #_mem.rxinv = rxpol == "N"
527

  
528
       
529
        if mem.power:
530
            _mem.power = POWER_LEVELS.index(mem.power)
531
        else:
532
            _mem.power = 0
533

  
534
    def _get_settings(self):
535
        _settings = self._memobj.settings
536
        _freqrange = self._memobj.freqrange
537

  
538
        basic = RadioSettingGroup("basic","Global Settings")
539
        freqrange = RadioSettingGroup("freqrange","Frequency Ranges")
540
        top = RadioSettingGroup("top","All Settings",basic,freqrange)
541

  
542

  
543
        rs = RadioSetting("bg_color","Background Color",
544
                           RadioSettingValueList(BGCOLOR_LIST, BGCOLOR_LIST[_settings.bg_color]))
545
        basic.append(rs)
546

  
547
        rs = RadioSetting("bg_brightness","Background Brightness",
548
                           RadioSettingValueList(BGBRIGHT_LIST, BGBRIGHT_LIST[_settings.bg_brightness]))
549
        basic.append(rs)
550

  
551
        rs = RadioSetting("squelch","Squelch Level",
552
                           RadioSettingValueList(SQUELCH_LIST, SQUELCH_LIST[_settings.squelch]))
553
        basic.append(rs)
554

  
555
        rs = RadioSetting("timeout_timer","Timeout Timer",
556
                           RadioSettingValueList(TIMEOUT_LIST, TIMEOUT_LIST[_settings.timeout_timer]))
557
        basic.append(rs)
558

  
559
        rs = RadioSetting("auto_power_off","Auto Power Off",
560
                           RadioSettingValueList(APO_LIST, APO_LIST[_settings.auto_power_off]))
561
        basic.append(rs)
562

  
563
        rs = RadioSetting("voice_prompt","Beep Prompt",
564
                           RadioSettingValueList(BEEP_LIST, BEEP_LIST[_settings.voice_prompt]))
565
        basic.append(rs)
566

  
567
        rs = RadioSetting("tbst_freq","Tone Burst Frequency",
568
                           RadioSettingValueList(TBSTFREQ_LIST, TBSTFREQ_LIST[_settings.tbst_freq]))
569
        basic.append(rs)
570

  
571
        rs = RadioSetting("choose_tx_power","Max Level of TX Power",
572
                           RadioSettingValueList(TXPWR_LIST, TXPWR_LIST[_settings.choose_tx_power]))
573
        basic.append(rs)
574

  
575
        rs = RadioSetting("txrangelow","TX Freq, Lower Limit (khz)", RadioSettingValueInteger(136000,144000, int(_freqrange.txrangelow)/10))
576
        freqrange.append(rs)
577

  
578
        rs = RadioSetting("txrangehi","TX Freq, Upper Limit (khz)", RadioSettingValueInteger(148000,174000,int(_freqrange.txrangehi)/10))
579
        freqrange.append(rs)
580

  
581
        rs = RadioSetting("rxrangelow","RX Freq, Lower Limit (khz)", RadioSettingValueInteger(136000,144000, int(_freqrange.rxrangelow)/10))
582
        freqrange.append(rs)
583

  
584
        rs = RadioSetting("rxrangehi","RX Freq, Upper Limit (khz)", RadioSettingValueInteger(148000,174000,int(_freqrange.rxrangehi)/10))
585
        freqrange.append(rs)
586

  
587
        return top
588

  
589
    def get_settings(self):
590
        try:
591
            return self._get_settings()
592
        except:
593
            import traceback
594
            print "failed to parse settings"
595
            traceback.print_exc()
596
            return None
597

  
598
    def set_settings(self,settings):
599
        _settings = self._memobj.settings
600
        for element in settings:
601
            if not isinstance(element,RadioSetting):
602
                self.set_settings(element)
603
                continue
604
            else:
605
                try:
606
                    name = element.get_name()
607

  
608
                    if  name in ["txrangelow","txrangehi","rxrangelow","rxrangehi"]:
609
                        print "setting %s = %s" % (name,int(element.value)*10)
610
                        setattr(self._memobj.freqrange,name,int(element.value)*10)
611
                        continue
612

  
613
                    obj = _settings
614
                    setting = element.get_name()
615

  
616
                    if element.has_apply_callback():
617
                        print "using apply callback"
618
                        element.run_apply_callback()
619
                    else:
620
                        print "Setting %s = %s" % (setting, element.value)
621
                        setattr(obj, setting, element.value)
622
                except Exception, e:
623
                    print element.get_name()
624
                    raise
625

  
626
    @classmethod
627
    def match_model(cls, filedata, filename):
628
        return cls._file_ident in filedata[0x10:0x20]
(4-4/14)