1
|
# Copyright 2011 Dan Smith <dsmith@danplanet.com>
|
2
|
# Copyright 2013 Jens Jensen AF5MI <kd4tjx@yahoo.com>
|
3
|
#
|
4
|
# This program is free software: you can redistribute it and/or modify
|
5
|
# it under the terms of the GNU General Public License as published by
|
6
|
# the Free Software Foundation, either version 3 of the License, or
|
7
|
# (at your option) any later version.
|
8
|
#
|
9
|
# This program is distributed in the hope that it will be useful,
|
10
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
# GNU General Public License for more details.
|
13
|
#
|
14
|
# You should have received a copy of the GNU General Public License
|
15
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
|
17
|
from chirp import chirp_common, bitwise, memmap, directory, errors, util, yaesu_clone
|
18
|
from chirp.settings import RadioSetting, RadioSettingGroup, \
|
19
|
RadioSettingValueInteger, RadioSettingValueList, \
|
20
|
RadioSettingValueBoolean, RadioSettingValueString
|
21
|
import time, os, traceback, string, re
|
22
|
from textwrap import dedent
|
23
|
|
24
|
if os.getenv("CHIRP_DEBUG"):
|
25
|
CHIRP_DEBUG = True
|
26
|
else:
|
27
|
CHIRP_DEBUG=False
|
28
|
|
29
|
CMD_ACK = chr(0x06)
|
30
|
|
31
|
FT90_STEPS = [5.0, 10.0, 12.5, 15.0, 20.0, 25.0, 50.0]
|
32
|
FT90_MODES = ["AM", "FM", "Auto"]
|
33
|
FT90_TMODES = ["", "Tone", "TSQL", "", "DTCS"] # idx 3 (Bell) not supported yet
|
34
|
FT90_TONES = list(chirp_common.TONES)
|
35
|
for tone in [ 165.5, 171.3, 177.3 ]:
|
36
|
FT90_TONES.remove(tone)
|
37
|
FT90_POWER_LEVELS_VHF = [chirp_common.PowerLevel("Hi", watts=50),
|
38
|
chirp_common.PowerLevel("Mid1", watts=20),
|
39
|
chirp_common.PowerLevel("Mid2", watts=10),
|
40
|
chirp_common.PowerLevel("Low", watts=5)]
|
41
|
|
42
|
FT90_POWER_LEVELS_UHF = [chirp_common.PowerLevel("Hi", watts=35),
|
43
|
chirp_common.PowerLevel("Mid1", watts=20),
|
44
|
chirp_common.PowerLevel("Mid2", watts=10),
|
45
|
chirp_common.PowerLevel("Low", watts=5)]
|
46
|
|
47
|
FT90_DUPLEX = ["", "-", "+", "split"]
|
48
|
FT90_CWID_CHARS = list(string.digits) + list(string.uppercase) + list(" ")
|
49
|
FT90_DTMF_CHARS = list("0123456789ABCD*#")
|
50
|
FT90_SPECIAL = [ "vfo_vhf", "home_vhf", "vfo_uhf", "home_uhf", \
|
51
|
"pms_1L", "pms_1U", "pms_2L", "pms_2U"]
|
52
|
|
53
|
@directory.register
|
54
|
class FT90Radio(yaesu_clone.YaesuCloneModeRadio):
|
55
|
VENDOR = "Yaesu"
|
56
|
MODEL = "FT-90"
|
57
|
ID = "\x8E\xF6"
|
58
|
|
59
|
_memsize = 4063
|
60
|
# block 03 (200 Bytes long) repeats 18 times; channel memories
|
61
|
_block_lengths = [ 2, 232, 24 ] + ([200] * 18 ) + [205]
|
62
|
|
63
|
mem_format = """
|
64
|
u16 id;
|
65
|
#seekto 0x22;
|
66
|
struct {
|
67
|
u8 dtmf_active;
|
68
|
u8 dtmf1_len;
|
69
|
u8 dtmf2_len;
|
70
|
u8 dtmf3_len;
|
71
|
u8 dtmf4_len;
|
72
|
u8 dtmf5_len;
|
73
|
u8 dtmf6_len;
|
74
|
u8 dtmf7_len;
|
75
|
u8 dtmf8_len;
|
76
|
u8 dtmf1[8];
|
77
|
u8 dtmf2[8];
|
78
|
u8 dtmf3[8];
|
79
|
u8 dtmf4[8];
|
80
|
u8 dtmf5[8];
|
81
|
u8 dtmf6[8];
|
82
|
u8 dtmf7[8];
|
83
|
u8 dtmf8[8];
|
84
|
char cwid[7];
|
85
|
u8 unk1;
|
86
|
u8 scan1:2,
|
87
|
beep:1,
|
88
|
unk3:3,
|
89
|
rfsqlvl:2;
|
90
|
u8 unk4:2,
|
91
|
scan2:1,
|
92
|
cwid_en:1,
|
93
|
txnarrow:1,
|
94
|
dtmfspeed:1,
|
95
|
pttlock:2;
|
96
|
u8 dtmftxdelay:3,
|
97
|
fancontrol:2,
|
98
|
unk5:3;
|
99
|
u8 dimmer:3,
|
100
|
unk6:1,
|
101
|
lcdcontrast:4;
|
102
|
u8 dcsmode:2,
|
103
|
unk16:2,
|
104
|
tot:4;
|
105
|
u8 unk14;
|
106
|
u8 unk8:1,
|
107
|
ars:1,
|
108
|
lock:1,
|
109
|
txpwrsave:1,
|
110
|
apo:4;
|
111
|
u8 unk15;
|
112
|
u8 unk9:4,
|
113
|
key_lt:4;
|
114
|
u8 unk10:4,
|
115
|
key_rt:4;
|
116
|
u8 unk11:4,
|
117
|
key_p1:4;
|
118
|
u8 unk12:4,
|
119
|
key_p2:4;
|
120
|
u8 unk13:4,
|
121
|
key_acc:4;
|
122
|
|
123
|
} settings;
|
124
|
|
125
|
struct mem_struct {
|
126
|
u8 mode:2,
|
127
|
isUhf1:1,
|
128
|
unknown1:2,
|
129
|
step:3;
|
130
|
u8 artsmode:2,
|
131
|
unknown2:1,
|
132
|
isUhf2:1
|
133
|
power:2,
|
134
|
shift:2;
|
135
|
u8 skip:1,
|
136
|
showname:1,
|
137
|
unknown3:1,
|
138
|
isUhfHi:1,
|
139
|
unknown4:1,
|
140
|
tmode:3;
|
141
|
u32 rxfreq;
|
142
|
u32 txfreqoffset;
|
143
|
u8 UseDefaultName:1,
|
144
|
ars:1,
|
145
|
tone:6;
|
146
|
u8 packetmode:1,
|
147
|
unknown5:1,
|
148
|
dcstone:6;
|
149
|
char name[7];
|
150
|
};
|
151
|
|
152
|
#seekto 0x86;
|
153
|
struct mem_struct vfo_vhf;
|
154
|
struct mem_struct home_vhf;
|
155
|
struct mem_struct vfo_uhf;
|
156
|
struct mem_struct home_uhf;
|
157
|
|
158
|
#seekto 0xEB;
|
159
|
u8 chan_enable[23];
|
160
|
|
161
|
#seekto 0x101;
|
162
|
struct {
|
163
|
u8 pms_2U_enable:1,
|
164
|
pms_2L_enable:1,
|
165
|
pms_1U_enable:1,
|
166
|
pms_1L_enable:1,
|
167
|
unknown6:4;
|
168
|
} special_enables;
|
169
|
|
170
|
#seekto 0x102;
|
171
|
struct mem_struct memory[180];
|
172
|
|
173
|
#seekto 0xf12;
|
174
|
struct mem_struct pms_1L;
|
175
|
struct mem_struct pms_1U;
|
176
|
struct mem_struct pms_2L;
|
177
|
struct mem_struct pms_2U;
|
178
|
|
179
|
#seekto 0x0F7B;
|
180
|
struct {
|
181
|
char demomsg1[50];
|
182
|
char demomsg2[50];
|
183
|
} demomsg;
|
184
|
|
185
|
"""
|
186
|
@classmethod
|
187
|
def get_prompts(cls):
|
188
|
rp = chirp_common.RadioPrompts()
|
189
|
rp.pre_download = _(dedent("""\
|
190
|
1. Turn radio off.
|
191
|
2. Connect mic and hold [ACC] on mic while powering on.
|
192
|
("CLONE" will appear on the display)
|
193
|
3. Replace mic with PC programming cable.
|
194
|
4. <b>After clicking OK</b>, press the [SET] key to send image."""))
|
195
|
rp.pre_upload = _(dedent("""\
|
196
|
1. Turn radio off.
|
197
|
2. Connect mic and hold [ACC] on mic while powering on.
|
198
|
("CLONE" will appear on the display)
|
199
|
3. Replace mic with PC programming cable.
|
200
|
4. Press the [DISP/SS] key
|
201
|
("R" will appear on the lower left of LCD)."""))
|
202
|
return rp
|
203
|
|
204
|
@classmethod
|
205
|
def match_model(cls, filedata, filename):
|
206
|
return len(filedata) == cls._memsize
|
207
|
|
208
|
def get_features(self):
|
209
|
rf = chirp_common.RadioFeatures()
|
210
|
rf.has_settings = True
|
211
|
rf.has_ctone = False
|
212
|
rf.has_bank = False
|
213
|
rf.has_dtcs_polarity = False
|
214
|
rf.has_dtcs = True
|
215
|
rf.valid_modes = FT90_MODES
|
216
|
rf.valid_tmodes = FT90_TMODES
|
217
|
rf.valid_duplexes = FT90_DUPLEX
|
218
|
rf.valid_tuning_steps = FT90_STEPS
|
219
|
rf.valid_power_levels = FT90_POWER_LEVELS_VHF
|
220
|
rf.valid_name_length = 7
|
221
|
rf.valid_characters = chirp_common.CHARSET_ASCII
|
222
|
rf.valid_skips = ["", "S"]
|
223
|
rf.valid_special_chans = FT90_SPECIAL
|
224
|
rf.memory_bounds = (1, 180)
|
225
|
rf.valid_bands = [(100000000, 230000000),
|
226
|
(300000000, 530000000), (810000000, 999975000)]
|
227
|
|
228
|
return rf
|
229
|
|
230
|
def _read(self, blocksize, blocknum):
|
231
|
data = self.pipe.read(blocksize+2)
|
232
|
|
233
|
# chew echo'd ack
|
234
|
self.pipe.write(CMD_ACK)
|
235
|
time.sleep(0.02)
|
236
|
self.pipe.read(1) # chew echoed ACK from 1-wire serial
|
237
|
|
238
|
if len(data) == blocksize+2 and data[0] == chr(blocknum):
|
239
|
checksum = yaesu_clone.YaesuChecksum(1, blocksize)
|
240
|
if checksum.get_existing(data) != checksum.get_calculated(data):
|
241
|
raise Exception("Checksum Failed [%02X<>%02X] block %02X, data len: %i" %
|
242
|
(checksum.get_existing(data),
|
243
|
checksum.get_calculated(data), blocknum, len(data) ))
|
244
|
data = data[1:blocksize+1] # Chew blocknum and checksum
|
245
|
|
246
|
else:
|
247
|
raise Exception("Unable to read blocknum %02X expected blocksize %i got %i." %
|
248
|
(blocknum, blocksize+2, len(data)))
|
249
|
|
250
|
return data
|
251
|
|
252
|
def _clone_in(self):
|
253
|
# Be very patient with the radio
|
254
|
self.pipe.setTimeout(4)
|
255
|
start = time.time()
|
256
|
|
257
|
data = ""
|
258
|
blocknum = 0
|
259
|
status = chirp_common.Status()
|
260
|
status.msg = "Cloning..."
|
261
|
self.status_fn(status)
|
262
|
status.max = len(self._block_lengths)
|
263
|
for blocksize in self._block_lengths:
|
264
|
data += self._read(blocksize, blocknum)
|
265
|
blocknum += 1
|
266
|
status.cur = blocknum
|
267
|
self.status_fn(status)
|
268
|
|
269
|
print "Clone completed in %i seconds, blocks read: %i" % (time.time() - start, blocknum)
|
270
|
|
271
|
return memmap.MemoryMap(data)
|
272
|
|
273
|
def _clone_out(self):
|
274
|
looppredelay = 0.3
|
275
|
looppostdelay = 1.8
|
276
|
start = time.time()
|
277
|
|
278
|
blocknum = 0
|
279
|
pos = 0
|
280
|
status = chirp_common.Status()
|
281
|
status.msg = "Cloning to radio..."
|
282
|
self.status_fn(status)
|
283
|
status.max = len(self._block_lengths)
|
284
|
|
285
|
for blocksize in self._block_lengths:
|
286
|
checksum = yaesu_clone.YaesuChecksum(pos, pos+blocksize-1)
|
287
|
blocknumbyte = chr(blocknum)
|
288
|
payloadbytes = self.get_mmap()[pos:pos+blocksize]
|
289
|
checksumbyte = chr(checksum.get_calculated(self.get_mmap()))
|
290
|
if CHIRP_DEBUG:
|
291
|
print "Block %i - will send from %i to %i byte " % \
|
292
|
(blocknum, pos, pos + blocksize)
|
293
|
print util.hexprint(blocknumbyte)
|
294
|
print util.hexprint(payloadbytes)
|
295
|
print util.hexprint(checksumbyte)
|
296
|
# send wrapped bytes
|
297
|
time.sleep(looppredelay)
|
298
|
self.pipe.write(blocknumbyte)
|
299
|
self.pipe.write(payloadbytes)
|
300
|
self.pipe.write(checksumbyte)
|
301
|
tmp = self.pipe.read(blocksize+2) #chew echo
|
302
|
if CHIRP_DEBUG:
|
303
|
print "bytes echoed: "
|
304
|
print util.hexprint(tmp)
|
305
|
# radio is slow to write/ack:
|
306
|
time.sleep(looppostdelay)
|
307
|
buf = self.pipe.read(1)
|
308
|
if CHIRP_DEBUG:
|
309
|
print "ack recd:"
|
310
|
print util.hexprint(buf)
|
311
|
if buf != CMD_ACK:
|
312
|
raise Exception("Radio did not ack block %i" % blocknum)
|
313
|
pos += blocksize
|
314
|
blocknum += 1
|
315
|
status.cur = blocknum
|
316
|
self.status_fn(status)
|
317
|
|
318
|
print "Clone completed in %i seconds" % (time.time() - start)
|
319
|
|
320
|
def sync_in(self):
|
321
|
try:
|
322
|
self._mmap = self._clone_in()
|
323
|
except errors.RadioError:
|
324
|
raise
|
325
|
except Exception, e:
|
326
|
trace = traceback.format_exc()
|
327
|
raise errors.RadioError("Failed to communicate with radio: %s" % trace)
|
328
|
self.process_mmap()
|
329
|
|
330
|
def sync_out(self):
|
331
|
try:
|
332
|
self._clone_out()
|
333
|
except errors.RadioError:
|
334
|
raise
|
335
|
except Exception, e:
|
336
|
trace = traceback.format_exc()
|
337
|
raise errors.RadioError("Failed to communicate with radio: %s" % trace)
|
338
|
|
339
|
def process_mmap(self):
|
340
|
self._memobj = bitwise.parse(self.mem_format, self._mmap)
|
341
|
|
342
|
def _get_chan_enable(self, number):
|
343
|
number = number - 1
|
344
|
bytepos = number // 8
|
345
|
bitpos = number % 8
|
346
|
chan_enable = self._memobj.chan_enable[bytepos]
|
347
|
if chan_enable & ( 1 << bitpos ):
|
348
|
return True
|
349
|
else:
|
350
|
return False
|
351
|
|
352
|
def _set_chan_enable(self, number, enable):
|
353
|
number = number - 1
|
354
|
bytepos = number // 8
|
355
|
bitpos = number % 8
|
356
|
chan_enable = self._memobj.chan_enable[bytepos]
|
357
|
if enable:
|
358
|
chan_enable = chan_enable | ( 1 << bitpos ) # enable
|
359
|
else:
|
360
|
chan_enable = chan_enable & ~ ( 1 << bitpos ) # disable
|
361
|
self._memobj.chan_enable[bytepos] = chan_enable
|
362
|
|
363
|
def get_memory(self, number):
|
364
|
mem = chirp_common.Memory()
|
365
|
if isinstance(number, str):
|
366
|
# special channel
|
367
|
_mem = getattr(self._memobj, number)
|
368
|
mem.number = - len(FT90_SPECIAL) + FT90_SPECIAL.index(number)
|
369
|
mem.extd_number = number
|
370
|
if re.match('^pms', mem.extd_number):
|
371
|
# enable pms_XY channel flag
|
372
|
_special_enables = self._memobj.special_enables
|
373
|
mem.empty = not getattr(_special_enables, mem.extd_number + "_enable")
|
374
|
else:
|
375
|
# regular memory
|
376
|
_mem = self._memobj.memory[number-1]
|
377
|
mem.number = number
|
378
|
mem.empty = not self._get_chan_enable(number)
|
379
|
if mem.empty:
|
380
|
return mem # bail out, do not parse junk
|
381
|
mem.freq = _mem.rxfreq * 10
|
382
|
mem.offset = _mem.txfreqoffset * 10
|
383
|
if not _mem.tmode < len(FT90_TMODES):
|
384
|
_mem.tmode = 0
|
385
|
mem.tmode = FT90_TMODES[_mem.tmode]
|
386
|
mem.rtone = FT90_TONES[_mem.tone]
|
387
|
mem.dtcs = chirp_common.DTCS_CODES[_mem.dcstone]
|
388
|
mem.mode = FT90_MODES[_mem.mode]
|
389
|
mem.duplex = FT90_DUPLEX[_mem.shift]
|
390
|
if mem.freq / 1000000 > 300:
|
391
|
mem.power = FT90_POWER_LEVELS_UHF[_mem.power]
|
392
|
else:
|
393
|
mem.power = FT90_POWER_LEVELS_VHF[_mem.power]
|
394
|
|
395
|
# radio has a known bug with 5khz step and squelch
|
396
|
if _mem.step == 0 or _mem.step > len(FT90_STEPS)-1:
|
397
|
_mem.step = 2
|
398
|
mem.tuning_step = FT90_STEPS[_mem.step]
|
399
|
mem.skip = _mem.skip and "S" or ""
|
400
|
if not all(char in chirp_common.CHARSET_ASCII for char in str(_mem.name)):
|
401
|
# dont display blank/junk name
|
402
|
mem.name = ""
|
403
|
else:
|
404
|
mem.name = str(_mem.name)
|
405
|
return mem
|
406
|
|
407
|
def get_raw_memory(self, number):
|
408
|
return repr(self._memobj.memory[number-1])
|
409
|
|
410
|
def set_memory(self, mem):
|
411
|
if mem.number < 0: # special channels
|
412
|
_mem = getattr(self._memobj, mem.extd_number)
|
413
|
if re.match('^pms', mem.extd_number):
|
414
|
# enable pms_XY channel flag
|
415
|
_special_enables = self._memobj.special_enables
|
416
|
setattr(_special_enables, mem.extd_number + "_enable", True)
|
417
|
else:
|
418
|
_mem = self._memobj.memory[mem.number - 1]
|
419
|
self._set_chan_enable( mem.number, not mem.empty )
|
420
|
_mem.skip = mem.skip == "S"
|
421
|
# radio has a known bug with 5khz step and dead squelch
|
422
|
if not mem.tuning_step or mem.tuning_step == FT90_STEPS[0]:
|
423
|
_mem.step = 2
|
424
|
else:
|
425
|
_mem.step = FT90_STEPS.index(mem.tuning_step)
|
426
|
_mem.rxfreq = mem.freq / 10
|
427
|
# vfo will unlock if not in right band?
|
428
|
if mem.freq > 300000000:
|
429
|
# uhf
|
430
|
_mem.isUhf1 = 1
|
431
|
_mem.isUhf2 = 1
|
432
|
if mem.freq > 810000000:
|
433
|
# uhf hiband
|
434
|
_mem.isUhfHi = 1
|
435
|
else:
|
436
|
_mem.isUhfHi = 0
|
437
|
else:
|
438
|
# vhf
|
439
|
_mem.isUhf1 = 0
|
440
|
_mem.isUhf2 = 0
|
441
|
_mem.isUhfHi = 0
|
442
|
_mem.txfreqoffset = mem.offset / 10
|
443
|
_mem.tone = FT90_TONES.index(mem.rtone)
|
444
|
_mem.tmode = FT90_TMODES.index(mem.tmode)
|
445
|
_mem.mode = FT90_MODES.index(mem.mode)
|
446
|
_mem.shift = FT90_DUPLEX.index(mem.duplex)
|
447
|
_mem.dcstone = chirp_common.DTCS_CODES.index(mem.dtcs)
|
448
|
_mem.step = FT90_STEPS.index(mem.tuning_step)
|
449
|
_mem.shift = FT90_DUPLEX.index(mem.duplex)
|
450
|
if mem.power:
|
451
|
_mem.power = FT90_POWER_LEVELS_VHF.index(mem.power)
|
452
|
else:
|
453
|
_mem.power = 3 # default to low power
|
454
|
if (len(mem.name) == 0):
|
455
|
_mem.name = bytearray.fromhex("80ffffffffffff")
|
456
|
_mem.showname = 0
|
457
|
else:
|
458
|
_mem.name = str(mem.name).ljust(7)
|
459
|
_mem.showname = 1
|
460
|
_mem.UseDefaultName = 0
|
461
|
|
462
|
def _decode_cwid(self, cwidarr):
|
463
|
cwid = ""
|
464
|
if CHIRP_DEBUG:
|
465
|
print "@ +_decode_cwid:"
|
466
|
for byte in cwidarr.get_value():
|
467
|
char = int(byte)
|
468
|
if CHIRP_DEBUG:
|
469
|
print char
|
470
|
# bitwise wraps in quotes! get rid of those
|
471
|
if char < len(FT90_CWID_CHARS):
|
472
|
cwid += FT90_CWID_CHARS[char]
|
473
|
return cwid
|
474
|
|
475
|
def _encode_cwid(self, cwidarr):
|
476
|
cwid = ""
|
477
|
if CHIRP_DEBUG:
|
478
|
print "@ _encode_cwid:"
|
479
|
for char in cwidarr.get_value():
|
480
|
cwid += chr(FT90_CWID_CHARS.index(char))
|
481
|
if CHIRP_DEBUG:
|
482
|
print cwid
|
483
|
return cwid
|
484
|
|
485
|
def _bbcd2dtmf(self, bcdarr, strlen = 16):
|
486
|
# doing bbcd, but with support for ABCD*#
|
487
|
if CHIRP_DEBUG:
|
488
|
print bcdarr.get_value()
|
489
|
string = ''.join("%02X" % b for b in bcdarr)
|
490
|
if CHIRP_DEBUG:
|
491
|
print "@_bbcd2dtmf, received: %s" % string
|
492
|
string = string.replace('E','*').replace('F','#')
|
493
|
if strlen <= 16:
|
494
|
string = string[:strlen]
|
495
|
return string
|
496
|
|
497
|
def _dtmf2bbcd(self, dtmf):
|
498
|
dtmfstr = dtmf.get_value()
|
499
|
dtmfstr = dtmfstr.replace('*', 'E').replace('#', 'F')
|
500
|
dtmfstr = str.ljust(dtmfstr.strip(), 16, "0" )
|
501
|
bcdarr = list(bytearray.fromhex(dtmfstr))
|
502
|
if CHIRP_DEBUG:
|
503
|
print "@_dtmf2bbcd, sending: %s" % bcdarr
|
504
|
return bcdarr
|
505
|
|
506
|
def get_settings(self):
|
507
|
_settings = self._memobj.settings
|
508
|
basic = RadioSettingGroup("basic", "Basic")
|
509
|
autodial = RadioSettingGroup("autodial", "AutoDial")
|
510
|
keymaps = RadioSettingGroup("keymaps", "KeyMaps")
|
511
|
top = RadioSettingGroup("top", "All Settings", basic, keymaps, autodial)
|
512
|
|
513
|
rs = RadioSetting("beep", "Beep",
|
514
|
RadioSettingValueBoolean(_settings.beep))
|
515
|
basic.append(rs)
|
516
|
rs = RadioSetting("lock", "Lock",
|
517
|
RadioSettingValueBoolean(_settings.lock))
|
518
|
basic.append(rs)
|
519
|
rs = RadioSetting("ars", "Auto Repeater Shift",
|
520
|
RadioSettingValueBoolean(_settings.ars))
|
521
|
basic.append(rs)
|
522
|
rs = RadioSetting("txpwrsave", "TX Power Save",
|
523
|
RadioSettingValueBoolean(_settings.txpwrsave))
|
524
|
basic.append(rs)
|
525
|
rs = RadioSetting("txnarrow", "TX Narrow",
|
526
|
RadioSettingValueBoolean(_settings.txnarrow))
|
527
|
basic.append(rs)
|
528
|
options = ["Off", "S-3", "S-5", "S-Full"]
|
529
|
rs = RadioSetting("rfsqlvl", "RF Squelch Level",
|
530
|
RadioSettingValueList(options,
|
531
|
options[_settings.rfsqlvl]))
|
532
|
basic.append(rs)
|
533
|
options = ["Off", "Band A", "Band B", "Both"]
|
534
|
rs = RadioSetting("pttlock", "PTT Lock",
|
535
|
RadioSettingValueList(options,
|
536
|
options[_settings.pttlock]))
|
537
|
basic.append(rs)
|
538
|
|
539
|
rs = RadioSetting("cwid_en", "CWID Enable",
|
540
|
RadioSettingValueBoolean(_settings.cwid_en))
|
541
|
basic.append(rs)
|
542
|
|
543
|
cwid = RadioSettingValueString(0, 7, self._decode_cwid(_settings.cwid))
|
544
|
cwid.set_charset(FT90_CWID_CHARS)
|
545
|
rs = RadioSetting("cwid", "CWID", cwid)
|
546
|
basic.append(rs)
|
547
|
|
548
|
options = ["OFF"] + map(str, range(1, 12+1))
|
549
|
rs = RadioSetting("apo", "APO time (hrs)",
|
550
|
RadioSettingValueList(options,
|
551
|
options[_settings.apo]))
|
552
|
basic.append(rs)
|
553
|
|
554
|
options = ["Off"] + map(str, range(1, 60+1))
|
555
|
rs = RadioSetting("tot", "Time Out Timer (mins)",
|
556
|
RadioSettingValueList(options,options[_settings.tot]))
|
557
|
basic.append(rs)
|
558
|
|
559
|
options = ["off", "Auto/TX", "Auto", "TX"]
|
560
|
rs = RadioSetting("fancontrol", "Fan Control",
|
561
|
RadioSettingValueList(options,options[_settings.fancontrol]))
|
562
|
basic.append(rs)
|
563
|
|
564
|
keyopts = ["Scan Up", "Scan Down", "Repeater", "Reverse", "Tone Burst",
|
565
|
"Tx Power", "Home Ch", "VFO/MR", "Tone", "Priority"]
|
566
|
rs = RadioSetting("key_lt", "Left Key",
|
567
|
RadioSettingValueList(keyopts,keyopts[_settings.key_lt]))
|
568
|
keymaps.append(rs)
|
569
|
rs = RadioSetting("key_rt", "Right Key",
|
570
|
RadioSettingValueList(keyopts,keyopts[_settings.key_rt]))
|
571
|
keymaps.append(rs)
|
572
|
rs = RadioSetting("key_p1", "P1 Key",
|
573
|
RadioSettingValueList(keyopts,keyopts[_settings.key_p1]))
|
574
|
keymaps.append(rs)
|
575
|
rs = RadioSetting("key_p2", "P2 Key",
|
576
|
RadioSettingValueList(keyopts,keyopts[_settings.key_p2]))
|
577
|
keymaps.append(rs)
|
578
|
rs = RadioSetting("key_acc", "ACC Key",
|
579
|
RadioSettingValueList(keyopts,keyopts[_settings.key_acc]))
|
580
|
keymaps.append(rs)
|
581
|
|
582
|
options = map(str, range(0,12+1))
|
583
|
rs = RadioSetting("lcdcontrast", "LCD Contrast",
|
584
|
RadioSettingValueList(options,options[_settings.lcdcontrast]))
|
585
|
basic.append(rs)
|
586
|
|
587
|
options = ["off", "d4", "d3", "d2", "d1"]
|
588
|
rs = RadioSetting("dimmer", "Dimmer",
|
589
|
RadioSettingValueList(options,options[_settings.dimmer]))
|
590
|
basic.append(rs)
|
591
|
|
592
|
options = ["TRX Normal", "RX Reverse", "TX Reverse", "TRX Reverse"]
|
593
|
rs = RadioSetting("dcsmode", "DCS Mode",
|
594
|
RadioSettingValueList(options,options[_settings.dcsmode]))
|
595
|
basic.append(rs)
|
596
|
|
597
|
options = ["50 ms", "100 ms"]
|
598
|
rs = RadioSetting("dtmfspeed", "DTMF Speed",
|
599
|
RadioSettingValueList(options,options[_settings.dtmfspeed]))
|
600
|
autodial.append(rs)
|
601
|
|
602
|
options = ["50 ms", "250 ms", "450 ms", "750 ms", "1 sec"]
|
603
|
rs = RadioSetting("dtmftxdelay", "DTMF TX Delay",
|
604
|
RadioSettingValueList(options,options[_settings.dtmftxdelay]))
|
605
|
autodial.append(rs)
|
606
|
|
607
|
options = map(str,range(1,8+1))
|
608
|
rs = RadioSetting("dtmf_active", "DTMF Active",
|
609
|
RadioSettingValueList(options,options[_settings.dtmf_active]))
|
610
|
autodial.append(rs)
|
611
|
|
612
|
# setup 8 dtmf autodial entries
|
613
|
for i in map(str, range(1,9)):
|
614
|
objname = "dtmf" + i
|
615
|
dtmfsetting = getattr(_settings, objname)
|
616
|
dtmflen = getattr(_settings, objname + "_len")
|
617
|
dtmfstr = self._bbcd2dtmf(dtmfsetting, dtmflen)
|
618
|
dtmf = RadioSettingValueString(0, 16, dtmfstr)
|
619
|
dtmf.set_charset(FT90_DTMF_CHARS + list(" "))
|
620
|
rs = RadioSetting(objname, objname.upper(), dtmf)
|
621
|
autodial.append(rs)
|
622
|
|
623
|
return top
|
624
|
|
625
|
def set_settings(self, uisettings):
|
626
|
_settings = self._memobj.settings
|
627
|
for element in uisettings:
|
628
|
if not isinstance(element, RadioSetting):
|
629
|
self.set_settings(element)
|
630
|
continue
|
631
|
if not element.changed():
|
632
|
continue
|
633
|
try:
|
634
|
setting = element.get_name()
|
635
|
oldval = getattr(_settings, setting)
|
636
|
newval = element.value
|
637
|
if setting == "cwid":
|
638
|
newval = self._encode_cwid(newval)
|
639
|
if re.match('dtmf\d', setting):
|
640
|
# set dtmf length field and then get bcd dtmf
|
641
|
dtmfstrlen = len(str(newval).strip())
|
642
|
setattr(_settings, setting + "_len", dtmfstrlen)
|
643
|
newval = self._dtmf2bbcd(newval)
|
644
|
if CHIRP_DEBUG:
|
645
|
print "Setting %s(%s) <= %s" % (setting,
|
646
|
oldval, newval)
|
647
|
setattr(_settings, setting, newval)
|
648
|
except Exception, e:
|
649
|
print element.get_name()
|
650
|
raise
|
651
|
|