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 struct
|
17
|
import logging
|
18
|
|
19
|
|
20
|
from chirp import chirp_common, errors, util, directory, memmap
|
21
|
from chirp import bitwise
|
22
|
from chirp.settings import InvalidValueError, RadioSetting, \
|
23
|
RadioSettingGroup, RadioSettingValueFloat, \
|
24
|
RadioSettingValueList, RadioSettingValueBoolean, \
|
25
|
RadioSettingValueString, RadioSettings
|
26
|
from textwrap import dedent
|
27
|
from chirp import bandplan_na
|
28
|
|
29
|
LOG = logging.getLogger(__name__)
|
30
|
|
31
|
AIRBAND = (108000000, 135999999)
|
32
|
MEM_FORMAT = """
|
33
|
#seekto 0x0008;
|
34
|
struct {
|
35
|
lbcd rxfreq[4];
|
36
|
lbcd txfreq[4];
|
37
|
lbcd rxtone[2];
|
38
|
lbcd txtone[2];
|
39
|
u8 unused1;
|
40
|
u8 pttid:2,
|
41
|
freqhop:1,
|
42
|
unused3:1,
|
43
|
unused4:1,
|
44
|
bcl:1,
|
45
|
unused5:1,
|
46
|
unused2:1;
|
47
|
u8 unused6:1,
|
48
|
unused7:1,
|
49
|
lowpower:2,
|
50
|
wide:1,
|
51
|
unused8:1,
|
52
|
offset:2;
|
53
|
u8 unused10;
|
54
|
} memory[200];
|
55
|
|
56
|
#seekto 0x0CA8;
|
57
|
struct {
|
58
|
u8 txled:1,
|
59
|
rxled:1,
|
60
|
unused11:1,
|
61
|
ham:1,
|
62
|
gmrs:1,
|
63
|
unused14:1,
|
64
|
unused15:1,
|
65
|
pritx:1;
|
66
|
u8 scanmode:2,
|
67
|
unused16:1,
|
68
|
keyautolock:1,
|
69
|
unused17:1,
|
70
|
btnvoice:1,
|
71
|
unknown18:1,
|
72
|
voiceprompt:1;
|
73
|
u8 fmworkmode:1,
|
74
|
sync:1,
|
75
|
tonevoice:2,
|
76
|
fmrec:1,
|
77
|
mdfa:1,
|
78
|
aworkmode:2;
|
79
|
u8 ponmsg:2,
|
80
|
unused19:1,
|
81
|
mdfb:1,
|
82
|
unused20:1,
|
83
|
dbrx:1,
|
84
|
bworkmode:2;
|
85
|
u8 ablock;
|
86
|
u8 bblock;
|
87
|
u8 fmroad;
|
88
|
u8 unused21:1,
|
89
|
tailclean:1,
|
90
|
rogerprompt:1,
|
91
|
unused23:1,
|
92
|
unused24:1,
|
93
|
voxgain:3;
|
94
|
u8 astep:4,
|
95
|
bstep:4;
|
96
|
u8 squelch;
|
97
|
u8 tot;
|
98
|
u8 lang;
|
99
|
u8 save;
|
100
|
u8 ligcon;
|
101
|
u8 voxdelay;
|
102
|
u8 onlychmode:1,
|
103
|
unused:6,
|
104
|
alarm:1;
|
105
|
} settings;
|
106
|
|
107
|
//#seekto 0x0CB8;
|
108
|
struct {
|
109
|
u8 ofseta[4];
|
110
|
} aoffset;
|
111
|
|
112
|
//#seekto 0x0CBC;
|
113
|
struct {
|
114
|
u8 ofsetb[4];
|
115
|
} boffset;
|
116
|
|
117
|
#seekto 0x0CD8;
|
118
|
struct{
|
119
|
lbcd fmblock[4];
|
120
|
}fmmode[25];
|
121
|
|
122
|
#seekto 0x0D48;
|
123
|
struct {
|
124
|
char name[8];
|
125
|
u8 unknown2[8];
|
126
|
} names[200];
|
127
|
|
128
|
#seekto 0x1A08;
|
129
|
lbit usedflags[200];
|
130
|
|
131
|
#seekto 0x1a28;
|
132
|
lbit scanadd[200];
|
133
|
|
134
|
#seekto 0x1B38;
|
135
|
lbcd fmvfo[4];
|
136
|
|
137
|
#seekto 0x1B58;
|
138
|
struct {
|
139
|
lbcd rxfreqa[4];
|
140
|
lbcd txfreq[4];
|
141
|
u8 rxtone[2];
|
142
|
u8 txtone[2];
|
143
|
u8 unused1;
|
144
|
u8 pttid:2,
|
145
|
specialqta:1,
|
146
|
unused3:1,
|
147
|
unused4:1,
|
148
|
bcl:1,
|
149
|
unused5:1,
|
150
|
unused2:1;
|
151
|
u8 unused6:1,
|
152
|
unused7:1,
|
153
|
lowpower:2,
|
154
|
wide:1,
|
155
|
unused8:1,
|
156
|
offset:2;
|
157
|
u8 unused10;
|
158
|
} vfoa;
|
159
|
|
160
|
//#seekto 0x1B68;
|
161
|
struct {
|
162
|
lbcd rxfreqb[4];
|
163
|
lbcd txfreq[4];
|
164
|
u8 rxtoneb[2];
|
165
|
u8 txtone[2];
|
166
|
u8 unused1;
|
167
|
u8 pttid:2,
|
168
|
specialqtb:1,
|
169
|
unused3:1,
|
170
|
unused4:1,
|
171
|
bclb:1,
|
172
|
unused5:1,
|
173
|
unused2:1;
|
174
|
u8 unused6:1,
|
175
|
unused7:1,
|
176
|
lowpowerb:2,
|
177
|
wideb:1,
|
178
|
unused8:1,
|
179
|
offsetb:2;
|
180
|
u8 unused10;
|
181
|
} vfob;
|
182
|
|
183
|
//#seekto 0x1B78;
|
184
|
lbit fmusedflags[32];
|
185
|
|
186
|
#seekto 0x1c08;
|
187
|
struct {
|
188
|
char msg1[16];
|
189
|
char msg2[16];
|
190
|
char msg3[16];
|
191
|
} poweron_msg;
|
192
|
|
193
|
|
194
|
#seekto 0x1CC8;
|
195
|
struct{
|
196
|
u8 stopkey1;
|
197
|
u8 ssidekey1;
|
198
|
u8 ssidekey2;
|
199
|
u8 ltopkey2;
|
200
|
u8 lsidekey3;
|
201
|
u8 lsidekey4;
|
202
|
u8 unused25[10];
|
203
|
} press;
|
204
|
|
205
|
#seekto 0x1E28;
|
206
|
struct{
|
207
|
u8 idcode[3];
|
208
|
}icode;
|
209
|
|
210
|
#seekto 0x1E31;
|
211
|
struct{
|
212
|
u8 gcode;
|
213
|
}groupcode;
|
214
|
|
215
|
#seekto 0x1E38;
|
216
|
struct{
|
217
|
u8 group1[7];
|
218
|
}group1;
|
219
|
|
220
|
#seekto 0x1E48;
|
221
|
struct{
|
222
|
u8 group2[7];
|
223
|
}group2;
|
224
|
|
225
|
#seekto 0x1E58;
|
226
|
struct{
|
227
|
u8 group3[7];
|
228
|
}group3;
|
229
|
|
230
|
#seekto 0x1E68;
|
231
|
struct{
|
232
|
u8 group4[7];
|
233
|
}group4;
|
234
|
|
235
|
#seekto 0x1E78;
|
236
|
struct{
|
237
|
u8 group5[7];
|
238
|
}group5;
|
239
|
|
240
|
#seekto 0x1E88;
|
241
|
struct{
|
242
|
u8 group6[7];
|
243
|
}group6;
|
244
|
|
245
|
#seekto 0x1E98;
|
246
|
struct{
|
247
|
u8 group7[7];
|
248
|
}group7;
|
249
|
|
250
|
#seekto 0x1EA8;
|
251
|
struct{
|
252
|
u8 group8[7];
|
253
|
}group8;
|
254
|
|
255
|
#seekto 0x1EC8;
|
256
|
struct{
|
257
|
u8 scode[7];
|
258
|
}startcode;
|
259
|
|
260
|
#seekto 0x1ED8;
|
261
|
struct{
|
262
|
u8 ecode[7];
|
263
|
}endcode;
|
264
|
"""
|
265
|
|
266
|
MEM_FORMAT_H3 = """
|
267
|
#seekto 0x0008;
|
268
|
struct {
|
269
|
lbcd rxfreq[4];
|
270
|
lbcd txfreq[4];
|
271
|
lbcd rxtone[2];
|
272
|
lbcd txtone[2];
|
273
|
u8 unused1;
|
274
|
u8 pttid:2,
|
275
|
freqhop:1,
|
276
|
unused3:1,
|
277
|
unused4:1,
|
278
|
bcl:1,
|
279
|
unused5:1,
|
280
|
unused2:1;
|
281
|
u8 unused6:1,
|
282
|
scramble:1,
|
283
|
lowpower:2,
|
284
|
wide:1,
|
285
|
unused8:1,
|
286
|
offset:2;
|
287
|
u8 unused10;
|
288
|
} memory[200];
|
289
|
|
290
|
#seekto 0x0C98;
|
291
|
struct{
|
292
|
u8 stopkey1;
|
293
|
u8 ssidekey1;
|
294
|
u8 ssidekey2;
|
295
|
u8 ltopkey2;
|
296
|
u8 lsidekey3;
|
297
|
u8 lsidekey4;
|
298
|
} press;
|
299
|
|
300
|
#seekto 0x0CA8;
|
301
|
struct {
|
302
|
u8 txled:1,
|
303
|
rxled:1,
|
304
|
unused11:1,
|
305
|
ham:1,
|
306
|
gmrs:1,
|
307
|
unused14:1,
|
308
|
unused15:1,
|
309
|
pritx:1;
|
310
|
u8 scanmode:2,
|
311
|
unused16:1,
|
312
|
keyautolock:1,
|
313
|
unused17:1,
|
314
|
btnvoice:1,
|
315
|
unknown18:1,
|
316
|
voiceprompt:1;
|
317
|
u8 fmworkmode:1,
|
318
|
sync:1,
|
319
|
tonevoice:2,
|
320
|
fmrec:1,
|
321
|
mdfa:1,
|
322
|
aworkmode:2;
|
323
|
u8 ponmsg:2,
|
324
|
unused19:1,
|
325
|
mdfb:1,
|
326
|
unused20:1,
|
327
|
dbrx:1,
|
328
|
bworkmode:2;
|
329
|
u8 ablock;
|
330
|
u8 bblock;
|
331
|
u8 fmroad;
|
332
|
u8 unused21:1,
|
333
|
tailclean:1,
|
334
|
rogerprompt_:1,
|
335
|
kill:1,
|
336
|
stun:1,
|
337
|
voxgain:3;
|
338
|
u8 astep:4,
|
339
|
bstep:4;
|
340
|
u8 squelch;
|
341
|
u8 tot;
|
342
|
u8 rogerprompt:2,
|
343
|
unused11_4:4,
|
344
|
lang:1,
|
345
|
unused11_1:1;
|
346
|
u8 save;
|
347
|
u8 ligcon;
|
348
|
u8 voxdelay;
|
349
|
u8 onlychmode:1,
|
350
|
breathled:3,
|
351
|
unused:3,
|
352
|
alarm:1;
|
353
|
} settings;
|
354
|
|
355
|
//#seekto 0x0CB8;
|
356
|
struct {
|
357
|
u8 ofseta[4];
|
358
|
} aoffset;
|
359
|
|
360
|
//#seekto 0x0CBC;
|
361
|
struct {
|
362
|
u8 ofsetb[4];
|
363
|
} boffset;
|
364
|
|
365
|
#seekto 0x0CD8;
|
366
|
struct{
|
367
|
lbcd fmblock[4];
|
368
|
}fmmode[25];
|
369
|
|
370
|
#seekto 0x0D48;
|
371
|
struct {
|
372
|
char name[8];
|
373
|
} names[200];
|
374
|
|
375
|
#seekto 0x1808;
|
376
|
struct{
|
377
|
u8 stuncode[16];
|
378
|
u8 killcode[16];
|
379
|
}skcode;
|
380
|
|
381
|
//#seekto 0x1828;
|
382
|
struct{
|
383
|
u8 idcode[3];
|
384
|
}icode;
|
385
|
|
386
|
#seekto 0x1837;
|
387
|
struct{
|
388
|
u8 gcode;
|
389
|
}groupcode;
|
390
|
|
391
|
//#seekto 0x1838;
|
392
|
struct{
|
393
|
u8 group1[7];
|
394
|
}group1;
|
395
|
|
396
|
#seekto 0x1848;
|
397
|
struct{
|
398
|
u8 group2[7];
|
399
|
}group2;
|
400
|
|
401
|
#seekto 0x1858;
|
402
|
struct{
|
403
|
u8 group3[7];
|
404
|
}group3;
|
405
|
|
406
|
#seekto 0x1868;
|
407
|
struct{
|
408
|
u8 group4[7];
|
409
|
}group4;
|
410
|
|
411
|
#seekto 0x1878;
|
412
|
struct{
|
413
|
u8 group5[7];
|
414
|
}group5;
|
415
|
|
416
|
#seekto 0x1888;
|
417
|
struct{
|
418
|
u8 group6[7];
|
419
|
}group6;
|
420
|
|
421
|
#seekto 0x1898;
|
422
|
struct{
|
423
|
u8 group7[7];
|
424
|
}group7;
|
425
|
|
426
|
#seekto 0x18A8;
|
427
|
struct{
|
428
|
u8 group8[7];
|
429
|
}group8;
|
430
|
|
431
|
#seekto 0x18C8;
|
432
|
struct{
|
433
|
u8 scode[7];
|
434
|
}startcode;
|
435
|
|
436
|
#seekto 0x18D8;
|
437
|
struct{
|
438
|
u8 ecode[7];
|
439
|
}endcode;
|
440
|
|
441
|
#seekto 0x1908;
|
442
|
lbit usedflags[200];
|
443
|
|
444
|
#seekto 0x1928;
|
445
|
lbit scanadd[200];
|
446
|
|
447
|
#seekto 0x1948;
|
448
|
lbit fmusedflags[32];
|
449
|
|
450
|
#seekto 0x1958;
|
451
|
struct {
|
452
|
lbcd rxfreqa[4];
|
453
|
lbcd txfreq[4];
|
454
|
u8 rxtone[2];
|
455
|
u8 txtone[2];
|
456
|
u8 unused1;
|
457
|
u8 pttid:2,
|
458
|
specialqta:1,
|
459
|
unused3:1,
|
460
|
unused4:1,
|
461
|
bcl:1,
|
462
|
unused5:1,
|
463
|
unused2:1;
|
464
|
u8 unused6:1,
|
465
|
unused7:1,
|
466
|
lowpower:2,
|
467
|
wide:1,
|
468
|
unused8:1,
|
469
|
offset:2;
|
470
|
u8 unused10;
|
471
|
} vfoa;
|
472
|
|
473
|
//#seekto 0x1968;
|
474
|
struct {
|
475
|
lbcd rxfreqb[4];
|
476
|
lbcd txfreq[4];
|
477
|
u8 rxtoneb[2];
|
478
|
u8 txtone[2];
|
479
|
u8 unused1;
|
480
|
u8 pttid:2,
|
481
|
specialqtb:1,
|
482
|
unused3:1,
|
483
|
unused4:1,
|
484
|
bclb:1,
|
485
|
unused5:1,
|
486
|
unused2:1;
|
487
|
u8 unused6:1,
|
488
|
unused7:1,
|
489
|
lowpowerb:2,
|
490
|
wideb:1,
|
491
|
unused8:1,
|
492
|
offsetb:2;
|
493
|
u8 unused10;
|
494
|
} vfob;
|
495
|
|
496
|
//#seekto 0x1978;
|
497
|
lbcd fmvfo[4];
|
498
|
|
499
|
#seekto 0x1c08;
|
500
|
struct {
|
501
|
char msg1[16];
|
502
|
char msg2[16];
|
503
|
char msg3[16];
|
504
|
} poweron_msg;
|
505
|
|
506
|
#seekto 0x1f28;
|
507
|
struct{
|
508
|
u8 micgain;
|
509
|
} mic;
|
510
|
|
511
|
"""
|
512
|
|
513
|
MEM_FORMAT_RT730 = """
|
514
|
#seekto 0x0008;
|
515
|
struct {
|
516
|
lbcd rxfreq[4];
|
517
|
lbcd txfreq[4];
|
518
|
lbcd rxtone[2];
|
519
|
lbcd txtone[2];
|
520
|
u8 unused1;
|
521
|
u8 unused2:4,
|
522
|
spec:1,
|
523
|
bcl:1,
|
524
|
unused3:2;
|
525
|
u8 scramble:1,
|
526
|
freqhop:1,
|
527
|
lowpower:2,
|
528
|
wide:1,
|
529
|
unused4:3;
|
530
|
u8 unused5;
|
531
|
} memory[200];
|
532
|
|
533
|
#seekto 0x0C98;
|
534
|
struct{
|
535
|
u8 ssidekey1;
|
536
|
u8 lsidekey1;
|
537
|
u8 ssidekey2;
|
538
|
u8 lsidekey2;
|
539
|
u8 unused1:6,
|
540
|
rogerprompt:2;
|
541
|
} press;
|
542
|
|
543
|
#seekto 0x0CA8;
|
544
|
struct {
|
545
|
u8 txled:1,
|
546
|
rxled:1,
|
547
|
unused1:6;
|
548
|
u8 scanmode:2,
|
549
|
unused2:1,
|
550
|
keyautolock:1,
|
551
|
save:1,
|
552
|
btnvoice:1,
|
553
|
unused3:1,
|
554
|
voiceprompt:1;
|
555
|
u8 fmworkmode:1,
|
556
|
ligcon:2,
|
557
|
unused4:1,
|
558
|
fmrec:1,
|
559
|
mdfa:1,
|
560
|
aworkmode:2;
|
561
|
u8 unused5:5,
|
562
|
dbrx:1,
|
563
|
bworkmode:2;
|
564
|
u8 unused6;
|
565
|
u8 unused7;
|
566
|
u8 fmroad;
|
567
|
u8 unused8:1,
|
568
|
tailclean:1,
|
569
|
unused9:3,
|
570
|
voxgain:3;
|
571
|
u8 astep:4,
|
572
|
bstep:4;
|
573
|
u8 squelch;
|
574
|
u8 tot;
|
575
|
u8 unused10:6,
|
576
|
lang:1,
|
577
|
unused11:1;
|
578
|
u8 unused12;
|
579
|
u8 unused13;
|
580
|
u8 voxdelay;
|
581
|
u8 unused14:6,
|
582
|
hoptype:2;
|
583
|
} settings;
|
584
|
|
585
|
//#seekto 0x0CB8;
|
586
|
struct {
|
587
|
u8 ofseta[4];
|
588
|
} aoffset;
|
589
|
|
590
|
//#seekto 0x0CBC;
|
591
|
struct {
|
592
|
u8 ofsetb[4];
|
593
|
} boffset;
|
594
|
|
595
|
#seekto 0x0CD8;
|
596
|
struct{
|
597
|
lbcd fmblock[4];
|
598
|
}fmmode[25];
|
599
|
|
600
|
#seekto 0x0D48;
|
601
|
struct {
|
602
|
char name[8];
|
603
|
} names[200];
|
604
|
|
605
|
#seekto 0x1398;
|
606
|
struct {
|
607
|
char msg1[16];
|
608
|
char msg2[16];
|
609
|
char msg3[16];
|
610
|
char msg4[16];
|
611
|
} poweron_msg;
|
612
|
|
613
|
#seekto 0x1A28;
|
614
|
lbit scanadd[200];
|
615
|
|
616
|
#seekto 0x1B08;
|
617
|
lbit usedflags[200];
|
618
|
|
619
|
#seekto 0x1B38;
|
620
|
lbcd fmvfo[4];
|
621
|
|
622
|
#seekto 0x1B58;
|
623
|
struct {
|
624
|
lbcd rxfreqa[4];
|
625
|
lbcd txfreq[4];
|
626
|
u8 rxtone[2];
|
627
|
u8 txtone[2];
|
628
|
u8 unused1;
|
629
|
u8 pttid:2,
|
630
|
specialqta:1,
|
631
|
unused2:1,
|
632
|
unused3:1,
|
633
|
bcl:1,
|
634
|
unused4:1,
|
635
|
unused5:1;
|
636
|
u8 unused6:1,
|
637
|
unused7:1,
|
638
|
lowpower:2,
|
639
|
wide:1,
|
640
|
unused8:1,
|
641
|
offset:2;
|
642
|
u8 unused9;
|
643
|
} vfoa;
|
644
|
|
645
|
//#seekto 0x1B68;
|
646
|
struct {
|
647
|
lbcd rxfreqb[4];
|
648
|
lbcd txfreq[4];
|
649
|
u8 rxtoneb[2];
|
650
|
u8 txtone[2];
|
651
|
u8 unused1;
|
652
|
u8 pttid:2,
|
653
|
specialqtb:1,
|
654
|
unused2:1,
|
655
|
unused3:1,
|
656
|
bclb:1,
|
657
|
unused4:1,
|
658
|
unused5:1;
|
659
|
u8 unused6:1,
|
660
|
unused7:1,
|
661
|
lowpowerb:2,
|
662
|
wideb:1,
|
663
|
unused8:1,
|
664
|
offsetb:2;
|
665
|
u8 unused9;
|
666
|
} vfob;
|
667
|
|
668
|
//#seekto 0x1B78;
|
669
|
lbit fmusedflags[32];
|
670
|
|
671
|
#seekto 0x1f28;
|
672
|
struct{
|
673
|
u8 micgain;
|
674
|
} mic;
|
675
|
|
676
|
"""
|
677
|
|
678
|
# basic settings
|
679
|
SQUELCH = ['%s' % x for x in range(0, 10)]
|
680
|
LIGHT_LIST = ["CONT", "5s", "10s", "15s", "30s"]
|
681
|
LIGHT730_LIST = ["CONT", "10s", "20s", "30s"]
|
682
|
VOICE_PRMPT_LIST = ["OFF", "ON"]
|
683
|
AUTOLOCK_LIST = ["OFF", "ON"]
|
684
|
TIME_OUT_LIST = ["OFF", "60s", "120s", "180s"]
|
685
|
MDFA_LIST = ["Frequency", "Name"]
|
686
|
MDFB_LIST = ["Frequency", "Name"]
|
687
|
HOP_LIST = ["A", "B", "C", "D"]
|
688
|
SYNC_LIST = ["ON", "OFF"]
|
689
|
LANG_LIST = ["Chinese", "English"]
|
690
|
BTV_SAVER_LIST = ["OFF", "1:1", "1:2", "1:3", "1:4"]
|
691
|
DBRX_LIST = ["OFF", "ON"]
|
692
|
OFFON_LIST = ["OFF", "ON"]
|
693
|
ASTEP_LIST = ["2.50K", "5.00K", "6.25K",
|
694
|
"10.00K", "12.00K", "25.00K", "50.00K"]
|
695
|
BSTEP_LIST = ["2.50K", "5.00K", "6.25K",
|
696
|
"10.00K", "12.00K", "25.00K", "50.00K"]
|
697
|
SCAN_MODE_LIST = ["TO", "CO", "SE"]
|
698
|
PRIO_LIST = ["Edit", "Busy"]
|
699
|
SHORT_KEY_LIST = ["None", "FM Radio", "Lamp", "Monitor",
|
700
|
"TONE", "Alarm", "Weather"]
|
701
|
LONG_KEY_LIST = ["None", "FM Radio", "Lamp",
|
702
|
"Monitor", "TONE", "Alarm", "Weather"]
|
703
|
SHORT_KEY730_LIST = ["None", "Scan", "FM", "Warn", "TONE", "Weather",
|
704
|
"Copy CH"]
|
705
|
LONG_KEY730_LIST = SHORT_KEY730_LIST + ["Monitor"]
|
706
|
BUSYLOCK_LIST = ["Off", "On"]
|
707
|
PRESS_NAME = ["stopkey1", "ssidekey1", "ssidekey2",
|
708
|
"ltopkey2", "lsidekey3", "lsidekey4"]
|
709
|
|
710
|
VFOA_NAME = ["rxfreqa",
|
711
|
"txfreq",
|
712
|
"rxtone",
|
713
|
"txtone",
|
714
|
"pttid",
|
715
|
"specialqta",
|
716
|
"bcl",
|
717
|
"lowpower",
|
718
|
"wide",
|
719
|
"offset"]
|
720
|
|
721
|
VFOB_NAME = ["rxfreqb",
|
722
|
"txfreq",
|
723
|
"rxtoneb",
|
724
|
"txtone",
|
725
|
"pttid",
|
726
|
"specialqtb",
|
727
|
"bclb",
|
728
|
"lowpowerb",
|
729
|
"wideb",
|
730
|
"offsetb"]
|
731
|
|
732
|
# KEY
|
733
|
VOX_GAIN = ["OFF", "1", "2", "3", "4", "5"]
|
734
|
VOX_DELAY = ["1.05s", "2.0s", "3.0s"]
|
735
|
VOX_GAIN730 = ["OFF", "1", "2", "3"]
|
736
|
VOX_DELAY730 = ["0.5s", "1.0s", "2.0s", "3.0s"]
|
737
|
PTTID_VALUES = ["Off", "BOT", "EOT", "BOTH"]
|
738
|
BCLOCK_VALUES = ["Off", "On"]
|
739
|
FREQHOP_VALUES = ["Off", "On"]
|
740
|
SCAN_VALUES = ["Del", "Add"]
|
741
|
|
742
|
# AB CHANNEL
|
743
|
A_OFFSET = ["Off", "-", "+"]
|
744
|
A_TX_POWER = ["Low", "Mid", "High"]
|
745
|
A_BAND = ["Wide", "Narrow"]
|
746
|
A_BUSYLOCK = ["Off", "On"]
|
747
|
A_SPEC_QTDQT = ["Off", "On"]
|
748
|
A_WORKMODE = ["VFO", "VFO+CH", "CH Mode"]
|
749
|
|
750
|
B_OFFSET = ["Off", "-", "+"]
|
751
|
B_TX_POWER = ["Low", "Mid", "High"]
|
752
|
B_BAND = ["Wide", "Narrow"]
|
753
|
B_BUSYLOCK = ["Off", "On"]
|
754
|
B_SPEC_QTDQT = ["Off", "On"]
|
755
|
B_WORKMODE = ["VFO", "VFO+CH", "CH Mode"]
|
756
|
|
757
|
# FM
|
758
|
FM_WORKMODE = ["CH", "VFO"]
|
759
|
FM_CHANNEL = ['%s' % x for x in range(0, 26)]
|
760
|
|
761
|
# DTMF
|
762
|
GROUPCODE = ["", "Off", "*", "#", "A", "B", "C", "D"]
|
763
|
|
764
|
AB_LIST = ["A", "B"]
|
765
|
ALMOD_LIST = ["Site", "Tone", "Code"]
|
766
|
BANDWIDTH_LIST = ["Wide", "Narrow"]
|
767
|
COLOR_LIST = ["Off", "Blue", "Orange", "Purple"]
|
768
|
DTMFSPEED_LIST = ["%s ms" % x for x in range(50, 2010, 10)]
|
769
|
DTMFST_LIST = ["OFF", "DT-ST", "ANI-ST", "DT+ANI"]
|
770
|
MODE_LIST = ["Channel", "Name", "Frequency"]
|
771
|
PONMSG_LIST = ["Full", "Message", "Icon"]
|
772
|
PTTID_LIST = ["Off", "BOT", "EOT", "Both"]
|
773
|
PTTIDCODE_LIST = ["%s" % x for x in range(1, 16)]
|
774
|
RTONE_LIST = ["1000 Hz", "1450 Hz", "1750 Hz", "2100 Hz"]
|
775
|
RESUME_LIST = ["TO", "CO", "SE"]
|
776
|
ROGERRX_LIST = ["Off"] + AB_LIST
|
777
|
RPSTE_LIST = ["OFF"] + ["%s" % x for x in range(1, 11)]
|
778
|
SAVE_LIST = ["Off", "1:1", "1:2", "1:3", "1:4"]
|
779
|
SCODE_LIST = ["%s" % x for x in range(1, 16)]
|
780
|
SHIFTD_LIST = ["Off", "+", "-"]
|
781
|
STEDELAY_LIST = ["OFF"] + ["%s ms" % x for x in range(100, 1100, 100)]
|
782
|
STEPS = [2.5, 5.0, 6.25, 10.0, 12.5, 25.0]
|
783
|
STEP_LIST = [str(x) for x in STEPS]
|
784
|
STEPS = [2.5, 5.0, 6.25, 10.0, 12.5, 20.0, 25.0, 50.0]
|
785
|
STEP291_LIST = [str(x) for x in STEPS]
|
786
|
TDRAB_LIST = ["Off"] + AB_LIST
|
787
|
TDRCH_LIST = ["CH%s" % x for x in range(1, 129)]
|
788
|
TIMEOUT_LIST = ["%s sec" % x for x in range(15, 615, 15)] + \
|
789
|
["Off (if supported by radio)"]
|
790
|
TIMEOUT730_LIST = ["Off"] + ["%s sec" % x for x in range(30, 240, 30)]
|
791
|
VOICE_LIST = ["Off", "English", "Chinese"]
|
792
|
VOX_LIST = ["OFF"] + ["%s" % x for x in range(1, 11)]
|
793
|
WORKMODE_LIST = ["Frequency", "Channel"]
|
794
|
# mic
|
795
|
MIC_GAIN_LIST = ['%s' % x for x in range(0, 10)]
|
796
|
MIC_GAIN_LIST_H8 = ['%s' % x for x in range(0, 33)]
|
797
|
H8_LIST = ["TD-H8", "TD-H8-HAM", "TD-H8-GMRS"]
|
798
|
|
799
|
GMRS_FREQS = bandplan_na.GMRS_HIRPT
|
800
|
|
801
|
NOAA_FREQS = [162550000, 162400000, 162475000, 162425000, 162450000,
|
802
|
162500000, 162525000, 161650000, 161775000, 161750000,
|
803
|
162000000]
|
804
|
|
805
|
HAM_GMRS_NAME = ["NOAA 1", "NOAA 2", "NOAA 3", "NOAA 4", "NOAA 5", "NOAA 6",
|
806
|
"NOAA 7", "NOAA 8", "NOAA 9", "NOAA 10", "NOAA 11"]
|
807
|
|
808
|
ALL_MODEL = ["TD-H8", "TD-H8-HAM", "TD-H8-GMRS", "TD-H3",
|
809
|
"TD-H3-HAM", "TD-H3-GMRS", "RT-730"]
|
810
|
|
811
|
TD_H8 = b"\x50\x56\x4F\x4A\x48\x1C\x14"
|
812
|
TD_H3 = b"\x50\x56\x4F\x4A\x48\x5C\x14"
|
813
|
RT_730 = b"\x50\x47\x4F\x4A\x48\xC3\x44"
|
814
|
|
815
|
|
816
|
def in_range(freq, ranges):
|
817
|
for lo, hi in ranges:
|
818
|
if lo <= freq <= hi:
|
819
|
return True
|
820
|
return False
|
821
|
|
822
|
|
823
|
def _do_status(radio, block):
|
824
|
status = chirp_common.Status()
|
825
|
status.msg = "Cloning"
|
826
|
status.cur = block
|
827
|
status.max = radio._memsize
|
828
|
radio.status_fn(status)
|
829
|
|
830
|
|
831
|
def _upper_band_from_data(data):
|
832
|
return data[0x03:0x04]
|
833
|
|
834
|
|
835
|
def _upper_band_from_image(radio):
|
836
|
return _upper_band_from_data(radio.get_mmap())
|
837
|
|
838
|
|
839
|
def _firmware_version_from_data(data, version_start, version_stop):
|
840
|
version_tag = data[version_start:version_stop]
|
841
|
return version_tag
|
842
|
|
843
|
|
844
|
def _firmware_version_from_image(radio):
|
845
|
version = _firmware_version_from_data(radio.get_mmap(),
|
846
|
radio._fw_ver_file_start,
|
847
|
radio._fw_ver_file_stop)
|
848
|
# LOG.debug("_firmware_version_from_image: " + util.hexprint(version))
|
849
|
return version
|
850
|
|
851
|
|
852
|
def _do_ident(serial, magic, secondack=True):
|
853
|
serial.timeout = 1
|
854
|
|
855
|
LOG.info("Sending Magic: %s" % util.hexprint(magic))
|
856
|
serial.write(magic)
|
857
|
ack = serial.read(1)
|
858
|
|
859
|
if ack != b"\x06":
|
860
|
if ack:
|
861
|
# LOG.debug(repr(ack))
|
862
|
pass
|
863
|
raise errors.RadioError("Radio did not respond")
|
864
|
|
865
|
serial.write(b"\x02")
|
866
|
|
867
|
response = b""
|
868
|
for i in range(1, 9):
|
869
|
byte = serial.read(1)
|
870
|
response += byte
|
871
|
if byte == b"\xDD":
|
872
|
break
|
873
|
|
874
|
if len(response) in [8, 12]:
|
875
|
# DEBUG
|
876
|
LOG.info("Valid response, got this:")
|
877
|
LOG.info(util.hexprint(response))
|
878
|
if len(response) == 12:
|
879
|
ident = response[0] + response[3] + response[5] + response[7:]
|
880
|
else:
|
881
|
ident = response
|
882
|
else:
|
883
|
# bad response
|
884
|
msg = "Unexpected response, got this:"
|
885
|
msg += util.hexprint(response)
|
886
|
LOG.debug(msg)
|
887
|
raise errors.RadioError("Unexpected response from radio.")
|
888
|
|
889
|
if secondack:
|
890
|
serial.write(b"\x06")
|
891
|
ack = serial.read(1)
|
892
|
if ack != b"\x06":
|
893
|
raise errors.RadioError("Radio refused clone")
|
894
|
|
895
|
return ident
|
896
|
|
897
|
|
898
|
def response_mode(mode):
|
899
|
data = mode
|
900
|
return data
|
901
|
|
902
|
|
903
|
def _read_block(radio, start, size):
|
904
|
serial = radio.pipe
|
905
|
|
906
|
cmd = struct.pack(">cHb", b'R', start, size)
|
907
|
expectedresponse = b"W" + cmd[1:]
|
908
|
|
909
|
try:
|
910
|
serial.write(cmd)
|
911
|
response = serial.read(5 + size)
|
912
|
if response[:4] != expectedresponse:
|
913
|
raise errors.RadioError("Error reading block %04x." % (start))
|
914
|
block_data = response[4:-1]
|
915
|
|
916
|
except Exception:
|
917
|
raise errors.RadioError("Failed to read block at %04x" % start)
|
918
|
|
919
|
return block_data
|
920
|
|
921
|
|
922
|
def _get_radio_firmware_version(radio):
|
923
|
if radio.MODEL in ALL_MODEL:
|
924
|
block = _read_block(radio, 0x1B40, 0x20)
|
925
|
version = block[0:6]
|
926
|
return version
|
927
|
|
928
|
|
929
|
IDENT_BLACKLIST = {
|
930
|
b"\x50\x56\x4F\x4A\x48\x1C\x14": "Radio identifies as TIDRADIO TD-H8",
|
931
|
}
|
932
|
|
933
|
|
934
|
def _do_download(radio):
|
935
|
# Radio must have already been ident'd by detect_from_serial()
|
936
|
data = radio.ident_mode
|
937
|
# Main block
|
938
|
LOG.info("Downloading...")
|
939
|
|
940
|
for i in range(0, radio._memsize, 0x20):
|
941
|
block = _read_block(radio, i, 0x20)
|
942
|
data += block
|
943
|
_do_status(radio, i)
|
944
|
_do_status(radio, radio._memsize)
|
945
|
LOG.info("done.")
|
946
|
|
947
|
return memmap.MemoryMapBytes(data)
|
948
|
|
949
|
|
950
|
def _exit_write_block(radio):
|
951
|
serial = radio.pipe
|
952
|
try:
|
953
|
serial.write(b"E")
|
954
|
|
955
|
except Exception:
|
956
|
raise errors.RadioError("Radio refused to exit programming mode")
|
957
|
|
958
|
|
959
|
def _write_block(radio, addr, data):
|
960
|
serial = radio.pipe
|
961
|
cmd = struct.pack(">cHb", b'W', addr, 0x20)
|
962
|
data = radio.get_mmap()[addr + 8: addr + 40]
|
963
|
# The checksum needs to be in the last
|
964
|
check_sum = bytes([sum(data) & 0xFF])
|
965
|
data += check_sum
|
966
|
used_data = cmd + data
|
967
|
serial.write(used_data)
|
968
|
|
969
|
ack = radio.pipe.read(1)
|
970
|
if ack != b"\x06":
|
971
|
raise errors.RadioError("Radio refused to accept block 0x%04x" % addr)
|
972
|
|
973
|
|
974
|
def _do_upload(radio):
|
975
|
data = _do_ident(radio.pipe, radio._idents[0])
|
976
|
radio_version = _get_radio_firmware_version(radio)
|
977
|
LOG.info("Radio Version is %s" % repr(radio_version))
|
978
|
|
979
|
if radio.ident_mode == data:
|
980
|
LOG.info("Successful match.")
|
981
|
else:
|
982
|
msg = ("Model mismatch!")
|
983
|
raise errors.RadioError(msg)
|
984
|
|
985
|
# Main block
|
986
|
LOG.debug("Uploading...")
|
987
|
|
988
|
for start_addr, end_addr in radio._ranges_main:
|
989
|
for addr in range(start_addr, end_addr, 0x20):
|
990
|
_write_block(radio, addr, 0x20)
|
991
|
_do_status(radio, addr)
|
992
|
_exit_write_block(radio)
|
993
|
LOG.debug("Upload all done.")
|
994
|
|
995
|
|
996
|
TDH8_CHARSET = chirp_common.CHARSET_ALPHANUMERIC + \
|
997
|
"!@#$%^&*()+-=[]:\";'<>?,./"
|
998
|
|
999
|
|
1000
|
@directory.register
|
1001
|
class TDH8(chirp_common.CloneModeRadio):
|
1002
|
"""TIDRADIO TD-H8"""
|
1003
|
VENDOR = "TIDRADIO"
|
1004
|
MODEL = "TD-H8"
|
1005
|
ident_mode = b'P31183\xff\xff'
|
1006
|
BAUD_RATE = 38400
|
1007
|
NEEDS_COMPAT_SERIAL = False
|
1008
|
_memsize = 0x1eef
|
1009
|
_ranges_main = [(0x0000, 0x1eef)]
|
1010
|
_idents = [TD_H8]
|
1011
|
_txbands = [(136000000, 175000000), (400000000, 521000000)]
|
1012
|
_rxbands = []
|
1013
|
_aux_block = True
|
1014
|
_tri_power = True
|
1015
|
_gmrs = False
|
1016
|
_ham = False
|
1017
|
_mem_params = (0x1F2F)
|
1018
|
|
1019
|
# offset of fw version in image file
|
1020
|
_fw_ver_file_start = 0x1838
|
1021
|
_fw_ver_file_stop = 0x1846
|
1022
|
_valid_chars = TDH8_CHARSET
|
1023
|
_tx_power = [chirp_common.PowerLevel("Low", watts=1.00),
|
1024
|
chirp_common.PowerLevel("Mid", watts=4.00),
|
1025
|
chirp_common.PowerLevel("High", watts=8.00)]
|
1026
|
|
1027
|
@classmethod
|
1028
|
def detect_from_serial(cls, pipe):
|
1029
|
ident = _do_ident(pipe, cls._idents[0])
|
1030
|
for rclass in [cls] + cls.detected_models():
|
1031
|
if (rclass.ident_mode == ident and
|
1032
|
rclass.MODEL.startswith(cls.MODEL)):
|
1033
|
return rclass
|
1034
|
LOG.error('No model match found for %r', ident)
|
1035
|
raise errors.RadioError('Unsupported model')
|
1036
|
|
1037
|
@classmethod
|
1038
|
def get_prompts(cls):
|
1039
|
rp = chirp_common.RadioPrompts()
|
1040
|
rp.pre_download = (dedent("""\
|
1041
|
1. Turn radio off.
|
1042
|
2. Connect cable to mic/spkr connector.
|
1043
|
3. Make sure connector is firmly connected.
|
1044
|
4. Turn radio on (volume may need to be set at 100%).
|
1045
|
5. Ensure that the radio is tuned to channel with no activity.
|
1046
|
6. Click OK to download image from device."""))
|
1047
|
rp.pre_upload = (dedent("""\
|
1048
|
1. Turn radio off.
|
1049
|
2. Connect cable to mic/spkr connector.
|
1050
|
3. Make sure connector is firmly connected.
|
1051
|
4. Turn radio on (volume may need to be set at 100%).
|
1052
|
5. Ensure that the radio is tuned to channel with no activity.
|
1053
|
6. Click OK to upload image to device."""))
|
1054
|
return rp
|
1055
|
|
1056
|
def get_features(self):
|
1057
|
rf = chirp_common.RadioFeatures()
|
1058
|
rf.has_settings = True
|
1059
|
rf.has_bank = False
|
1060
|
rf.has_cross = True
|
1061
|
rf.has_ctone = True
|
1062
|
rf.has_rx_dtcs = True
|
1063
|
rf.has_tuning_step = False
|
1064
|
rf.has_ctone = True
|
1065
|
rf.can_odd_split = True
|
1066
|
rf.valid_name_length = 8
|
1067
|
rf.valid_characters = self._valid_chars
|
1068
|
rf.valid_skips = ["", "S"]
|
1069
|
rf.valid_tmodes = ["", "Tone", "TSQL", "DTCS", "Cross"]
|
1070
|
rf.valid_cross_modes = [
|
1071
|
"Tone->Tone",
|
1072
|
"DTCS->",
|
1073
|
"->DTCS",
|
1074
|
"Tone->DTCS",
|
1075
|
"DTCS->Tone",
|
1076
|
"->Tone",
|
1077
|
"DTCS->DTCS"]
|
1078
|
rf.valid_power_levels = [x for x in self._tx_power if x]
|
1079
|
rf.valid_duplexes = ["", "-", "+", "split", "off"]
|
1080
|
rf.valid_modes = ["FM", "NFM"]
|
1081
|
rf.valid_tuning_steps = STEPS
|
1082
|
|
1083
|
rf.valid_bands = self._txbands + self._rxbands
|
1084
|
rf.valid_bands.sort()
|
1085
|
rf.memory_bounds = (1, 199)
|
1086
|
return rf
|
1087
|
|
1088
|
def process_mmap(self):
|
1089
|
self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
|
1090
|
|
1091
|
def sync_in(self):
|
1092
|
try:
|
1093
|
self._mmap = _do_download(self)
|
1094
|
self.process_mmap()
|
1095
|
except Exception as e:
|
1096
|
raise errors.RadioError("Failed to communicate with radio: %s" % e)
|
1097
|
|
1098
|
def sync_out(self):
|
1099
|
try:
|
1100
|
_do_upload(self)
|
1101
|
except errors.RadioError:
|
1102
|
raise
|
1103
|
except Exception as e:
|
1104
|
raise errors.RadioError("Failed to communicate with radio: %s" % e)
|
1105
|
|
1106
|
def get_raw_memory(self, number):
|
1107
|
return repr(self._memobj.memory[number])
|
1108
|
|
1109
|
# Encoding processing
|
1110
|
def _decode_tone(self, val):
|
1111
|
if val == 16665 or val == 0:
|
1112
|
return '', None, None
|
1113
|
elif val >= 12000:
|
1114
|
return 'DTCS', val - 12000, 'R'
|
1115
|
elif val >= 8000:
|
1116
|
return 'DTCS', val - 8000, 'N'
|
1117
|
else:
|
1118
|
return 'Tone', val / 10.0, None
|
1119
|
|
1120
|
# Decoding processing
|
1121
|
def _encode_tone(self, memval, mode, value, pol):
|
1122
|
if mode == "":
|
1123
|
memval[0].set_raw(0xFF)
|
1124
|
memval[1].set_raw(0xFF)
|
1125
|
elif mode == 'Tone':
|
1126
|
memval.set_value(int(value * 10))
|
1127
|
|
1128
|
elif mode == 'DTCS':
|
1129
|
flag = 0x80 if pol == 'N' else 0xC0
|
1130
|
memval.set_value(value)
|
1131
|
memval[1].set_bits(flag)
|
1132
|
else:
|
1133
|
raise Exception("Internal error: invalid mode `%s'" % mode)
|
1134
|
|
1135
|
def _get_mem(self, number):
|
1136
|
return self._memobj.memory[number]
|
1137
|
|
1138
|
def _get_nam(self, number):
|
1139
|
return self._memobj.names[number - 1]
|
1140
|
|
1141
|
def _get_fm(self, number):
|
1142
|
return self._memobj.fmmode[number]
|
1143
|
|
1144
|
def _get_get_scanvfo(self, number):
|
1145
|
return self._memobj.fmvfo[number]
|
1146
|
|
1147
|
def get_memory(self, number):
|
1148
|
_mem = self._get_mem(number)
|
1149
|
_nam = self._get_nam(number)
|
1150
|
mem = chirp_common.Memory()
|
1151
|
mem.number = number
|
1152
|
|
1153
|
if _mem.get_raw()[0] == 0xff:
|
1154
|
mem.empty = True
|
1155
|
return mem
|
1156
|
|
1157
|
# narrow and wide
|
1158
|
mem.mode = _mem.wide and "NFM" or "FM"
|
1159
|
|
1160
|
# power
|
1161
|
try:
|
1162
|
mem.power = self._tx_power[_mem.lowpower]
|
1163
|
if mem.power is None:
|
1164
|
# Gaps are basically missing power levels
|
1165
|
raise IndexError()
|
1166
|
except IndexError:
|
1167
|
LOG.error("Radio reported invalid power level %s (in %s)" %
|
1168
|
(_mem.lowpower, self._tx_power))
|
1169
|
mem.power = self._tx_power[0]
|
1170
|
|
1171
|
# Channel name
|
1172
|
for char in _nam.name:
|
1173
|
if "\x00" in str(char) or "\xFF" in str(char):
|
1174
|
char = ""
|
1175
|
mem.name += str(char)
|
1176
|
|
1177
|
mem.name = mem.name.rstrip()
|
1178
|
if self.ident_mode != b'P31183\xff\xff' and \
|
1179
|
(mem.number >= 189 and mem.number <= 199):
|
1180
|
mem.name = HAM_GMRS_NAME[mem.number - 200]
|
1181
|
|
1182
|
# tmode
|
1183
|
lin2 = int(_mem.rxtone)
|
1184
|
rxtone = self._decode_tone(lin2)
|
1185
|
|
1186
|
lin = int(_mem.txtone)
|
1187
|
txtone = self._decode_tone(lin)
|
1188
|
|
1189
|
if txtone[0] == "Tone" and not rxtone[0]:
|
1190
|
mem.tmode = "Tone"
|
1191
|
elif txtone[0] == rxtone[0] and txtone[0] == "Tone" \
|
1192
|
and mem.rtone == mem.ctone:
|
1193
|
mem.tmode = "TSQL"
|
1194
|
elif txtone[0] == rxtone[0] and txtone[0] == "DTCS" \
|
1195
|
and mem.dtcs == mem.rx_dtcs:
|
1196
|
mem.tmode = "DTCS"
|
1197
|
elif rxtone[0] or txtone[0]:
|
1198
|
mem.tmode = "Cross"
|
1199
|
mem.cross_mode = "%s->%s" % (txtone[0], rxtone[0])
|
1200
|
|
1201
|
chirp_common.split_tone_decode(mem, txtone, rxtone)
|
1202
|
|
1203
|
mem.skip = '' if self._memobj.scanadd[mem.number - 1] else 'S'
|
1204
|
|
1205
|
mem.freq = int(_mem.rxfreq) * 10
|
1206
|
if _mem.txfreq.get_raw() == b'\xff\xff\xff\xff':
|
1207
|
mem.offset = 0
|
1208
|
mem.duplex = 'off'
|
1209
|
else:
|
1210
|
chirp_common.split_to_offset(mem,
|
1211
|
int(_mem.rxfreq) * 10,
|
1212
|
int(_mem.txfreq) * 10)
|
1213
|
|
1214
|
if self._gmrs:
|
1215
|
# mem.duplex = ""
|
1216
|
# mem.offset = 0
|
1217
|
if mem.number >= 1 and mem.number <= 30:
|
1218
|
mem.immutable.append('freq')
|
1219
|
if mem.number >= 8 and mem.number <= 14:
|
1220
|
mem.mode = 'NFM'
|
1221
|
mem.power = self._tx_power[0]
|
1222
|
mem.immutable = ['freq', 'mode', 'power',
|
1223
|
'duplex', 'offset']
|
1224
|
elif mem.number >= 31 and mem.number <= 54:
|
1225
|
# mem.immutable = ['duplex', 'offset']
|
1226
|
mem.duplex = '+'
|
1227
|
mem.offset = 5000000
|
1228
|
elif mem.number >= 189 and mem.number <= 199:
|
1229
|
ham_freqs = NOAA_FREQS[mem.number - 189]
|
1230
|
mem.freq = ham_freqs
|
1231
|
mem.immutable = ['name', 'power', 'duplex', 'freq',
|
1232
|
'rx_dtcs', 'vfo', 'tmode', 'empty',
|
1233
|
'offset', 'rtone', 'ctone', 'dtcs',
|
1234
|
'dtcs_polarity', 'cross_mode']
|
1235
|
elif self._ham:
|
1236
|
if mem.number >= 189 and mem.number <= 199:
|
1237
|
ham_freqs = NOAA_FREQS[mem.number - 189]
|
1238
|
mem.freq = ham_freqs
|
1239
|
mem.immutable = ['name', 'power', 'freq', 'rx_dtcs', 'vfo',
|
1240
|
'tmode', 'empty', 'offset', 'rtone', 'ctone',
|
1241
|
'dtcs', 'dtcs_polarity', 'cross_mode']
|
1242
|
|
1243
|
# other function
|
1244
|
# pttid
|
1245
|
mem.extra = RadioSettingGroup("Extra", "extra")
|
1246
|
|
1247
|
if self.MODEL != "RT-730":
|
1248
|
rs = RadioSetting("pttid", "PTT ID",
|
1249
|
RadioSettingValueList(PTTID_VALUES,
|
1250
|
PTTID_VALUES[_mem.pttid]))
|
1251
|
mem.extra.append(rs)
|
1252
|
|
1253
|
# Busylock
|
1254
|
rs = RadioSetting("bcl", "Busy Lock",
|
1255
|
RadioSettingValueList(BCLOCK_VALUES,
|
1256
|
BCLOCK_VALUES[_mem.bcl]))
|
1257
|
mem.extra.append(rs)
|
1258
|
|
1259
|
if self.MODEL != "RT-730":
|
1260
|
rs = RadioSetting(
|
1261
|
"freqhop", "Frequency Hop", RadioSettingValueList(
|
1262
|
FREQHOP_VALUES, FREQHOP_VALUES[_mem.freqhop]))
|
1263
|
mem.extra.append(rs)
|
1264
|
|
1265
|
if in_range(mem.freq, self._rxbands):
|
1266
|
mem.duplex = 'off'
|
1267
|
mem.immutable.append('duplex')
|
1268
|
if in_range(mem.freq, [AIRBAND]):
|
1269
|
mem.mode = 'AM'
|
1270
|
mem.immutable.append('mode')
|
1271
|
|
1272
|
return mem
|
1273
|
|
1274
|
def _set_mem(self, number):
|
1275
|
return self._memobj.memory[number]
|
1276
|
|
1277
|
def _set_nam(self, number):
|
1278
|
return self._memobj.names[number - 1]
|
1279
|
|
1280
|
def _get_scan_list(self, scan_data):
|
1281
|
# scan_val_list - Get all scans Add data 1-200 digits
|
1282
|
scan_val_list = []
|
1283
|
for x in range(25):
|
1284
|
a = self._get_scan(x)
|
1285
|
for i in range(0, 8):
|
1286
|
scan_val = (getattr(a, 'scan%i' % (i+1)))
|
1287
|
used_scan_val = str(scan_val)[3]
|
1288
|
scan_val_list.append(used_scan_val)
|
1289
|
|
1290
|
# used_scan_list - 25 structures, split the scan added
|
1291
|
# data into 25 groups of 8 bits each
|
1292
|
used_scan_list = []
|
1293
|
count_num = 1
|
1294
|
for i in range(0, len(scan_val_list), 8):
|
1295
|
used_scan_list.append(scan_val_list[i:i + 8])
|
1296
|
count_num += 1
|
1297
|
# Determine whether it is a standard number that can be divisible
|
1298
|
# Which group is the scan addition located in the modified channel
|
1299
|
if scan_data % 8 != 0:
|
1300
|
x_list = scan_data / 8
|
1301
|
y_list = scan_data % 8
|
1302
|
|
1303
|
else:
|
1304
|
x_list = (scan_data / 8) - 1
|
1305
|
y_list = 8
|
1306
|
|
1307
|
return ([x_list, y_list])
|
1308
|
|
1309
|
def set_memory(self, mem):
|
1310
|
_mem = self._get_mem(mem.number)
|
1311
|
_nam = self._get_nam(mem.number)
|
1312
|
|
1313
|
# When the channel is empty, you need to set "usedflags" to 0,
|
1314
|
# When the channel is used , you need to set "usedflags" to 1.
|
1315
|
self._memobj.usedflags[mem.number - 1] = int(not mem.empty)
|
1316
|
|
1317
|
if mem.empty:
|
1318
|
_mem.fill_raw(b'\xFF')
|
1319
|
return
|
1320
|
|
1321
|
_mem.fill_raw(b'\x00')
|
1322
|
|
1323
|
if mem.duplex == "":
|
1324
|
_mem.rxfreq = _mem.txfreq = mem.freq / 10
|
1325
|
elif mem.duplex == "split":
|
1326
|
_mem.txfreq = mem.offset / 10
|
1327
|
elif mem.duplex == "+":
|
1328
|
_mem.txfreq = (mem.freq + mem.offset) / 10
|
1329
|
elif mem.duplex == "-":
|
1330
|
_mem.txfreq = (mem.freq - mem.offset) / 10
|
1331
|
elif mem.duplex == 'off':
|
1332
|
_mem.txfreq.fill_raw(b'\xFF')
|
1333
|
else:
|
1334
|
_mem.txfreq = mem.freq / 10
|
1335
|
|
1336
|
if in_range(mem.freq, self._rxbands):
|
1337
|
_mem.txfreq.fill_raw(b'\xFF')
|
1338
|
|
1339
|
_mem.rxfreq = mem.freq / 10
|
1340
|
_namelength = self.get_features().valid_name_length
|
1341
|
|
1342
|
for i in range(_namelength):
|
1343
|
try:
|
1344
|
_nam.name[i] = mem.name[i]
|
1345
|
except IndexError:
|
1346
|
_nam.name[i] = "\xFF"
|
1347
|
|
1348
|
txtone, rxtone = chirp_common.split_tone_encode(mem)
|
1349
|
|
1350
|
self._encode_tone(_mem.txtone, *txtone)
|
1351
|
self._encode_tone(_mem.rxtone, *rxtone)
|
1352
|
|
1353
|
if mem.mode == "FM":
|
1354
|
_mem.wide = 0
|
1355
|
else:
|
1356
|
_mem.wide = 1
|
1357
|
|
1358
|
try:
|
1359
|
_mem.lowpower = self._tx_power.index(mem.power or
|
1360
|
self._tx_power[-1])
|
1361
|
except ValueError:
|
1362
|
_mem.lowpower = 0
|
1363
|
LOG.warning('Unsupported power %r', mem.power)
|
1364
|
|
1365
|
# Skip/Scanadd Setting
|
1366
|
self._memobj.scanadd[mem.number - 1] = mem.skip != 'S'
|
1367
|
|
1368
|
for setting in mem.extra:
|
1369
|
if (self.ident_mode == b'P31185\xff\xff' or
|
1370
|
self.ident_mode == b'P31184\xff\xff') and \
|
1371
|
mem.number >= 189 and mem.number <= 199:
|
1372
|
if setting.get_name() == 'pttid':
|
1373
|
setting.value = 'Off'
|
1374
|
setattr(_mem, setting.get_name(), setting.value)
|
1375
|
elif setting.get_name() == 'bcl':
|
1376
|
setting.value = 'Off'
|
1377
|
setattr(_mem, setting.get_name(), setting.value)
|
1378
|
elif setting.get_name() == 'freqhop':
|
1379
|
setting.value = 'Off'
|
1380
|
setattr(_mem, setting.get_name(), setting.value)
|
1381
|
else:
|
1382
|
setattr(_mem, setting.get_name(), setting.value)
|
1383
|
|
1384
|
def _is_orig(self):
|
1385
|
version_tag = _firmware_version_from_image(self)
|
1386
|
try:
|
1387
|
if b'BFB' in version_tag:
|
1388
|
idx = version_tag.index(b"BFB") + 3
|
1389
|
version = int(version_tag[idx:idx + 3])
|
1390
|
return version < 291
|
1391
|
return False
|
1392
|
except Exception:
|
1393
|
pass
|
1394
|
raise errors.RadioError("Unable to parse version string %s" %
|
1395
|
version_tag)
|
1396
|
|
1397
|
def _my_upper_band(self):
|
1398
|
band_tag = _upper_band_from_image(self)
|
1399
|
return band_tag
|
1400
|
|
1401
|
def _get_settings(self):
|
1402
|
_settings = self._memobj.settings
|
1403
|
_press = self._memobj.press
|
1404
|
_aoffset = self._memobj.aoffset
|
1405
|
_boffset = self._memobj.boffset
|
1406
|
_vfoa = self._memobj.vfoa
|
1407
|
_vfob = self._memobj.vfob
|
1408
|
if self.MODEL != "RT-730":
|
1409
|
_gcode = self._memobj.groupcode
|
1410
|
_msg = self._memobj.poweron_msg
|
1411
|
basic = RadioSettingGroup("basic", "Basic Settings")
|
1412
|
abblock = RadioSettingGroup("abblock", "A/B Channel")
|
1413
|
fmmode = RadioSettingGroup("fmmode", "FM")
|
1414
|
dtmf = RadioSettingGroup("dtmf", "DTMF")
|
1415
|
|
1416
|
# group = RadioSettings(fmmode, dtmf)
|
1417
|
group = RadioSettings(basic)
|
1418
|
|
1419
|
rs = RadioSetting("squelch", "Squelch Level",
|
1420
|
RadioSettingValueList(
|
1421
|
SQUELCH, SQUELCH[_settings.squelch]))
|
1422
|
basic.append(rs)
|
1423
|
|
1424
|
if self.MODEL != "RT-730":
|
1425
|
rs = RadioSetting("ligcon", "Light Control",
|
1426
|
RadioSettingValueList(
|
1427
|
LIGHT_LIST, LIGHT_LIST[_settings.ligcon]))
|
1428
|
basic.append(rs)
|
1429
|
|
1430
|
rs = RadioSetting("voiceprompt", "Voice Prompt",
|
1431
|
RadioSettingValueList(
|
1432
|
VOICE_PRMPT_LIST, VOICE_PRMPT_LIST[
|
1433
|
_settings.voiceprompt]))
|
1434
|
basic.append(rs)
|
1435
|
|
1436
|
rs = RadioSetting("keyautolock", "Auto Lock",
|
1437
|
RadioSettingValueList(
|
1438
|
AUTOLOCK_LIST, AUTOLOCK_LIST[
|
1439
|
_settings.keyautolock]))
|
1440
|
basic.append(rs)
|
1441
|
|
1442
|
if self.MODEL != "RT-730":
|
1443
|
rs = RadioSetting("mdfa", "MDF-A",
|
1444
|
RadioSettingValueList(
|
1445
|
MDFA_LIST, MDFA_LIST[_settings.mdfa]))
|
1446
|
basic.append(rs)
|
1447
|
|
1448
|
rs = RadioSetting("mdfb", "MDF-B",
|
1449
|
RadioSettingValueList(
|
1450
|
MDFB_LIST, MDFB_LIST[_settings.mdfb]))
|
1451
|
basic.append(rs)
|
1452
|
|
1453
|
rs = RadioSetting("sync", "SYNC",
|
1454
|
RadioSettingValueList(
|
1455
|
SYNC_LIST, SYNC_LIST[_settings.sync]))
|
1456
|
basic.append(rs)
|
1457
|
|
1458
|
rs = RadioSetting("save", "Battery Save",
|
1459
|
RadioSettingValueList(
|
1460
|
BTV_SAVER_LIST,
|
1461
|
BTV_SAVER_LIST[_settings.save]))
|
1462
|
basic.append(rs)
|
1463
|
|
1464
|
rs = RadioSetting("dbrx", "Double Rx",
|
1465
|
RadioSettingValueList(
|
1466
|
DBRX_LIST, DBRX_LIST[_settings.dbrx]))
|
1467
|
basic.append(rs)
|
1468
|
|
1469
|
if self.MODEL != "RT-730":
|
1470
|
rs = RadioSetting("astep", "A Step",
|
1471
|
RadioSettingValueList(
|
1472
|
ASTEP_LIST, ASTEP_LIST[_settings.astep]))
|
1473
|
basic.append(rs)
|
1474
|
|
1475
|
rs = RadioSetting("bstep", "B Step",
|
1476
|
RadioSettingValueList(
|
1477
|
BSTEP_LIST, BSTEP_LIST[_settings.bstep]))
|
1478
|
basic.append(rs)
|
1479
|
|
1480
|
rs = RadioSetting("scanmode", "Scan Mode",
|
1481
|
RadioSettingValueList(
|
1482
|
SCAN_MODE_LIST, SCAN_MODE_LIST[
|
1483
|
_settings.scanmode]))
|
1484
|
basic.append(rs)
|
1485
|
|
1486
|
if self.MODEL != "RT-730":
|
1487
|
rs = RadioSetting("pritx", "Priority TX",
|
1488
|
RadioSettingValueList(
|
1489
|
PRIO_LIST, PRIO_LIST[_settings.pritx]))
|
1490
|
basic.append(rs)
|
1491
|
|
1492
|
rs = RadioSetting("btnvoice", "Beep",
|
1493
|
RadioSettingValueBoolean(_settings.btnvoice))
|
1494
|
basic.append(rs)
|
1495
|
|
1496
|
if self.MODEL != "RT-730":
|
1497
|
rs = RadioSetting("rogerprompt", "Roger",
|
1498
|
RadioSettingValueBoolean(_settings.rogerprompt))
|
1499
|
basic.append(rs)
|
1500
|
|
1501
|
rs = RadioSetting("txled", "Disp Lcd(TX)",
|
1502
|
|
1503
|
RadioSettingValueBoolean(_settings.txled))
|
1504
|
basic.append(rs)
|
1505
|
|
1506
|
rs = RadioSetting("rxled", "Disp Lcd(RX)",
|
1507
|
RadioSettingValueBoolean(_settings.rxled))
|
1508
|
basic.append(rs)
|
1509
|
|
1510
|
if self.MODEL != "RT-730":
|
1511
|
rs = RadioSetting("onlychmode", "Only CH Mode",
|
1512
|
RadioSettingValueBoolean(_settings.onlychmode))
|
1513
|
basic.append(rs)
|
1514
|
rs = RadioSetting("ssidekey1", "SHORT_KEY_PF1",
|
1515
|
RadioSettingValueList(
|
1516
|
SHORT_KEY_LIST, SHORT_KEY_LIST[
|
1517
|
_press.ssidekey1]))
|
1518
|
basic.append(rs)
|
1519
|
rs = RadioSetting("lsidekey3", "LONG_KEY_PF1",
|
1520
|
RadioSettingValueList(
|
1521
|
LONG_KEY_LIST,
|
1522
|
LONG_KEY_LIST[_press.lsidekey3]))
|
1523
|
basic.append(rs)
|
1524
|
|
1525
|
if self.MODEL in H8_LIST:
|
1526
|
rs = RadioSetting("stopkey1", "SHORT_KEY_TOP",
|
1527
|
RadioSettingValueList(SHORT_KEY_LIST,
|
1528
|
SHORT_KEY_LIST[0]))
|
1529
|
basic.append(rs)
|
1530
|
|
1531
|
rs = RadioSetting("ltopkey2", "LONG_KEY_TOP",
|
1532
|
RadioSettingValueList(
|
1533
|
LONG_KEY_LIST,
|
1534
|
LONG_KEY_LIST[_press.ltopkey2]))
|
1535
|
basic.append(rs)
|
1536
|
|
1537
|
rs = RadioSetting("ssidekey2", "SHORT_KEY_PF2",
|
1538
|
RadioSettingValueList(
|
1539
|
SHORT_KEY_LIST,
|
1540
|
SHORT_KEY_LIST[_press.ssidekey2]))
|
1541
|
basic.append(rs)
|
1542
|
|
1543
|
rs = RadioSetting("lsidekey4", "LONG_KEY_PF2",
|
1544
|
RadioSettingValueList(
|
1545
|
LONG_KEY_LIST,
|
1546
|
LONG_KEY_LIST[_press.lsidekey4]))
|
1547
|
basic.append(rs)
|
1548
|
|
1549
|
if self.MODEL != "RT-730":
|
1550
|
rs = RadioSetting("voxgain", "VOX Gain",
|
1551
|
RadioSettingValueList(
|
1552
|
VOX_GAIN, VOX_GAIN[_settings.voxgain]))
|
1553
|
basic.append(rs)
|
1554
|
|
1555
|
rs = RadioSetting("voxdelay", "VOX Delay",
|
1556
|
RadioSettingValueList(
|
1557
|
VOX_DELAY, VOX_DELAY[_settings.voxdelay]))
|
1558
|
basic.append(rs)
|
1559
|
|
1560
|
rs = RadioSetting("ponmsg", "Power-On Message",
|
1561
|
RadioSettingValueList(
|
1562
|
PONMSG_LIST, PONMSG_LIST[_settings.ponmsg]))
|
1563
|
basic.append(rs)
|
1564
|
|
1565
|
# mic gain
|
1566
|
if self.MODEL not in H8_LIST:
|
1567
|
_mic = self._memobj.mic
|
1568
|
rs = RadioSetting("micgain", "MIC GAIN",
|
1569
|
RadioSettingValueList(
|
1570
|
MIC_GAIN_LIST,
|
1571
|
current_index=_mic.micgain))
|
1572
|
basic.append(rs)
|
1573
|
|
1574
|
if self.MODEL not in H8_LIST:
|
1575
|
rs = RadioSetting("kill", "Kill",
|
1576
|
RadioSettingValueBoolean(_settings.kill))
|
1577
|
basic.append(rs)
|
1578
|
rs = RadioSetting("stun", "Stun",
|
1579
|
RadioSettingValueBoolean(_settings.stun))
|
1580
|
basic.append(rs)
|
1581
|
|
1582
|
def _filter(name):
|
1583
|
filtered = ""
|
1584
|
for char in str(name):
|
1585
|
if char in chirp_common.CHARSET_ASCII:
|
1586
|
filtered += char
|
1587
|
else:
|
1588
|
filtered += " "
|
1589
|
return filtered
|
1590
|
|
1591
|
rs = RadioSetting("poweron_msg.msg1", "Power-On Message 1",
|
1592
|
RadioSettingValueString(0, 16, _filter(_msg.msg1)))
|
1593
|
basic.append(rs)
|
1594
|
rs = RadioSetting("poweron_msg.msg2", "Power-On Message 2",
|
1595
|
RadioSettingValueString(0, 16, _filter(_msg.msg2)))
|
1596
|
basic.append(rs)
|
1597
|
rs = RadioSetting("poweron_msg.msg3", "Power-On Message 3",
|
1598
|
RadioSettingValueString(0, 16, _filter(_msg.msg3)))
|
1599
|
basic.append(rs)
|
1600
|
if self.MODEL == "RT-730":
|
1601
|
rsvs = RadioSettingValueString(0, 16, _filter(_msg.msg4))
|
1602
|
rs = RadioSetting("poweron_msg.msg4", "Power-On Message 4", rsvs)
|
1603
|
basic.append(rs)
|
1604
|
|
1605
|
if self.MODEL == "RT-730":
|
1606
|
rs = RadioSetting("ligcon", "Light Control",
|
1607
|
RadioSettingValueList(
|
1608
|
LIGHT730_LIST,
|
1609
|
LIGHT730_LIST[_settings.ligcon]))
|
1610
|
basic.append(rs)
|
1611
|
|
1612
|
rs = RadioSetting("tot", "Time-out Timer",
|
1613
|
RadioSettingValueList(
|
1614
|
TIMEOUT730_LIST, TIMEOUT730_LIST[
|
1615
|
_settings.tot]))
|
1616
|
basic.append(rs)
|
1617
|
|
1618
|
rs = RadioSetting("press.rogerprompt", "Roger",
|
1619
|
RadioSettingValueList(
|
1620
|
PTTID_LIST, PTTID_LIST[_press.rogerprompt]))
|
1621
|
basic.append(rs)
|
1622
|
|
1623
|
rs = RadioSetting("lang", "Language",
|
1624
|
RadioSettingValueList(
|
1625
|
LANG_LIST, LANG_LIST[_settings.lang]))
|
1626
|
basic.append(rs)
|
1627
|
|
1628
|
rs = RadioSetting("save", "Battery Save",
|
1629
|
RadioSettingValueList(
|
1630
|
OFFON_LIST, OFFON_LIST[_settings.save]))
|
1631
|
basic.append(rs)
|
1632
|
|
1633
|
rs = RadioSetting("mdfa", "Channel Names",
|
1634
|
RadioSettingValueList(
|
1635
|
OFFON_LIST, OFFON_LIST[_settings.mdfa]))
|
1636
|
basic.append(rs)
|
1637
|
|
1638
|
rs = RadioSetting("hoptype", "Hop Type",
|
1639
|
RadioSettingValueList(
|
1640
|
HOP_LIST, HOP_LIST[_settings.hoptype]))
|
1641
|
basic.append(rs)
|
1642
|
|
1643
|
rs = RadioSetting("tailclean", "QT/DQT Tail",
|
1644
|
RadioSettingValueBoolean(_settings.tailclean))
|
1645
|
basic.append(rs)
|
1646
|
|
1647
|
rs = RadioSetting("press.ssidekey1", "PF1 Key(Short)",
|
1648
|
RadioSettingValueList(
|
1649
|
SHORT_KEY730_LIST, SHORT_KEY730_LIST[
|
1650
|
_press.ssidekey1]))
|
1651
|
basic.append(rs)
|
1652
|
rs = RadioSetting("press.lsidekey1", "PF1 Key(Long)",
|
1653
|
RadioSettingValueList(
|
1654
|
LONG_KEY730_LIST,
|
1655
|
LONG_KEY730_LIST[_press.lsidekey1]))
|
1656
|
basic.append(rs)
|
1657
|
rs = RadioSetting("press.ssidekey2", "PF2 Key(Short)",
|
1658
|
RadioSettingValueList(
|
1659
|
SHORT_KEY730_LIST, SHORT_KEY730_LIST[
|
1660
|
_press.ssidekey2]))
|
1661
|
basic.append(rs)
|
1662
|
rs = RadioSetting("press.lsidekey2", "PF2 Key(Long)",
|
1663
|
RadioSettingValueList(
|
1664
|
LONG_KEY730_LIST,
|
1665
|
LONG_KEY730_LIST[_press.lsidekey2]))
|
1666
|
basic.append(rs)
|
1667
|
|
1668
|
rs = RadioSetting("voxgain", "VOX Gain",
|
1669
|
RadioSettingValueList(
|
1670
|
VOX_GAIN730,
|
1671
|
VOX_GAIN730[_settings.voxgain]))
|
1672
|
basic.append(rs)
|
1673
|
|
1674
|
rs = RadioSetting("voxdelay", "VOX Delay",
|
1675
|
RadioSettingValueList(
|
1676
|
VOX_DELAY730,
|
1677
|
VOX_DELAY730[_settings.voxdelay]))
|
1678
|
basic.append(rs)
|
1679
|
|
1680
|
if self.MODEL != "RT-730":
|
1681
|
group.append(abblock)
|
1682
|
|
1683
|
# A channel
|
1684
|
a_freq = int(_vfoa.rxfreqa)
|
1685
|
freqa = "%i.%05i" % (a_freq / 100000, a_freq % 100000)
|
1686
|
if freqa == "0.00000":
|
1687
|
val1a = RadioSettingValueString(0, 7, '0.00000')
|
1688
|
else:
|
1689
|
val1a = RadioSettingValueFloat(
|
1690
|
136, 520, float(freqa), 0.00001, 5)
|
1691
|
rs = RadioSetting("rxfreqa", "A Channel - Frequency", val1a)
|
1692
|
abblock.append(rs)
|
1693
|
|
1694
|
# Offset
|
1695
|
# If the offset is 12.345
|
1696
|
# Then the data obtained is [0x45, 0x23, 0x01, 0x00]
|
1697
|
a_set_val = _aoffset.ofseta
|
1698
|
a_set_list = len(_aoffset.ofseta) - 1
|
1699
|
real_val = ''
|
1700
|
for i in range(a_set_list, -1, -1):
|
1701
|
real_val += str(a_set_val[i])[2:]
|
1702
|
if real_val == "FFFFFFFF":
|
1703
|
rs = RadioSetting("ofseta", "A Offset Frequency",
|
1704
|
RadioSettingValueString(0, 7, ""))
|
1705
|
|
1706
|
else:
|
1707
|
real_val = int(real_val)
|
1708
|
real_val = "%i.%05i" % (real_val / 100000, real_val % 100000)
|
1709
|
rs = RadioSetting("ofseta", "A Offset Frequency",
|
1710
|
RadioSettingValueFloat(
|
1711
|
0.00000, 59.99750, real_val, 0.00001, 5))
|
1712
|
abblock.append(rs)
|
1713
|
|
1714
|
rs = RadioSetting("offset", "A Offset",
|
1715
|
RadioSettingValueList(
|
1716
|
A_OFFSET, A_OFFSET[_vfoa.offset]))
|
1717
|
abblock.append(rs)
|
1718
|
|
1719
|
rs = RadioSetting("lowpower", "A TX Power",
|
1720
|
RadioSettingValueList(
|
1721
|
A_TX_POWER, A_TX_POWER[_vfoa.lowpower]))
|
1722
|
abblock.append(rs)
|
1723
|
|
1724
|
rs = RadioSetting("wide", "A Band",
|
1725
|
RadioSettingValueList(
|
1726
|
A_BAND, A_BAND[_vfoa.wide]))
|
1727
|
abblock.append(rs)
|
1728
|
|
1729
|
rs = RadioSetting("bcl", "A Busy Lock",
|
1730
|
RadioSettingValueList(
|
1731
|
A_BUSYLOCK, A_BUSYLOCK[_vfoa.bcl]))
|
1732
|
abblock.append(rs)
|
1733
|
|
1734
|
rs = RadioSetting("specialqta", "A Special QT/DQT",
|
1735
|
RadioSettingValueList(
|
1736
|
A_SPEC_QTDQT,
|
1737
|
A_SPEC_QTDQT[_vfoa.specialqta]))
|
1738
|
abblock.append(rs)
|
1739
|
|
1740
|
rs = RadioSetting("aworkmode", "A Work Mode",
|
1741
|
RadioSettingValueList(
|
1742
|
A_WORKMODE, A_WORKMODE[_settings.aworkmode]))
|
1743
|
abblock.append(rs)
|
1744
|
|
1745
|
# B channel
|
1746
|
b_freq = int(str(int(_vfob.rxfreqb)).ljust(8, '0'))
|
1747
|
freqb = "%i.%05i" % (b_freq / 100000, b_freq % 100000)
|
1748
|
if freqb == "0.00000":
|
1749
|
val1a = RadioSettingValueString(0, 7, '0.00000')
|
1750
|
else:
|
1751
|
val1a = RadioSettingValueFloat(
|
1752
|
136, 520, float(freqb), 0.00001, 5)
|
1753
|
rs = RadioSetting("rxfreqb", "B Channel - Frequency", val1a)
|
1754
|
abblock.append(rs)
|
1755
|
|
1756
|
# Offset frequency
|
1757
|
# If the offset is 12.345
|
1758
|
# Then the data obtained is [0x45, 0x23, 0x01, 0x00]
|
1759
|
# Need to use the following anonymous function to process data
|
1760
|
b_set_val = _boffset.ofsetb
|
1761
|
b_set_list = len(_boffset.ofsetb) - 1
|
1762
|
real_val = ''
|
1763
|
for i in range(b_set_list, -1, -1):
|
1764
|
real_val += str(b_set_val[i])[2:]
|
1765
|
if real_val == "FFFFFFFF":
|
1766
|
rs = RadioSetting("ofsetb", "B Offset Frequency",
|
1767
|
RadioSettingValueString(0, 7, " "))
|
1768
|
else:
|
1769
|
real_val = int(real_val)
|
1770
|
real_val = "%i.%05i" % (real_val / 100000, real_val % 100000)
|
1771
|
rs = RadioSetting("ofsetb", "B Offset Frequency",
|
1772
|
RadioSettingValueFloat(
|
1773
|
0.00000, 59.99750, real_val, 0.00001, 5))
|
1774
|
abblock.append(rs)
|
1775
|
|
1776
|
rs = RadioSetting("offsetb", "B Offset",
|
1777
|
RadioSettingValueList(
|
1778
|
B_OFFSET, B_OFFSET[_vfob.offsetb]))
|
1779
|
abblock.append(rs)
|
1780
|
|
1781
|
rs = RadioSetting("lowpowerb", "B TX Power",
|
1782
|
RadioSettingValueList(
|
1783
|
B_TX_POWER, B_TX_POWER[_vfob.lowpowerb]))
|
1784
|
abblock.append(rs)
|
1785
|
|
1786
|
rs = RadioSetting("wideb", "B Band",
|
1787
|
RadioSettingValueList(
|
1788
|
B_BAND, B_BAND[_vfob.wideb]))
|
1789
|
abblock.append(rs)
|
1790
|
|
1791
|
rs = RadioSetting("bclb", "B Busy Lock",
|
1792
|
RadioSettingValueList(
|
1793
|
B_BUSYLOCK, B_BUSYLOCK[_vfob.bclb]))
|
1794
|
abblock.append(rs)
|
1795
|
|
1796
|
rs = RadioSetting("specialqtb", "B Special QT/DQT",
|
1797
|
RadioSettingValueList(
|
1798
|
B_SPEC_QTDQT,
|
1799
|
B_SPEC_QTDQT[_vfob.specialqtb]))
|
1800
|
abblock.append(rs)
|
1801
|
|
1802
|
rs = RadioSetting("bworkmode", "B Work Mode",
|
1803
|
RadioSettingValueList(
|
1804
|
B_WORKMODE, B_WORKMODE[_settings.bworkmode]))
|
1805
|
abblock.append(rs)
|
1806
|
|
1807
|
group.append(fmmode)
|
1808
|
|
1809
|
rs = RadioSetting("fmworkmode", "Work Mode",
|
1810
|
RadioSettingValueList(
|
1811
|
FM_WORKMODE, FM_WORKMODE[_settings.fmworkmode]))
|
1812
|
fmmode.append(rs)
|
1813
|
|
1814
|
rs = RadioSetting("fmroad", "Channel",
|
1815
|
RadioSettingValueList(
|
1816
|
FM_CHANNEL, FM_CHANNEL[_settings.fmroad]))
|
1817
|
fmmode.append(rs)
|
1818
|
|
1819
|
rs = RadioSetting("fmrec", "Forbid Receive",
|
1820
|
RadioSettingValueBoolean(_settings.fmrec))
|
1821
|
fmmode.append(rs)
|
1822
|
|
1823
|
# FM
|
1824
|
numeric = '0123456789.'
|
1825
|
for i in range(25):
|
1826
|
if self._memobj.fmusedflags[i]:
|
1827
|
_fm = self._get_fm(i).fmblock
|
1828
|
try:
|
1829
|
if not (760 < int(_fm) < 1080):
|
1830
|
raise ValueError()
|
1831
|
val = '%.1f' % (int(_fm) / 10)
|
1832
|
except ValueError:
|
1833
|
LOG.warning('FM channel index %i is invalid', i)
|
1834
|
val = ''
|
1835
|
else:
|
1836
|
val = ''
|
1837
|
rs = RadioSetting('block%02i' % i, "Channel %i" % (i + 1),
|
1838
|
RadioSettingValueString(0, 5,
|
1839
|
val,
|
1840
|
False, charset=numeric))
|
1841
|
fmmode.append(rs)
|
1842
|
|
1843
|
try:
|
1844
|
_fmv = int(self._memobj.fmvfo) / 10
|
1845
|
except ValueError:
|
1846
|
LOG.warning('FM VFO is invalid')
|
1847
|
_fmv = 0
|
1848
|
|
1849
|
rs = RadioSetting(
|
1850
|
"fmvfo", "VFO", RadioSettingValueFloat(
|
1851
|
76.0, 108.0, _fmv, 0.1, 1))
|
1852
|
fmmode.append(rs)
|
1853
|
|
1854
|
if self.MODEL != "RT-730":
|
1855
|
group.append(dtmf)
|
1856
|
|
1857
|
# DTMF
|
1858
|
gcode_val = str(_gcode.gcode)[2:]
|
1859
|
if gcode_val == "FF":
|
1860
|
gcode_val = "Off"
|
1861
|
elif gcode_val == "0F":
|
1862
|
gcode_val = "#"
|
1863
|
elif gcode_val == "0E":
|
1864
|
gcode_val = "*"
|
1865
|
elif gcode_val == '00':
|
1866
|
gcode_val = ""
|
1867
|
else:
|
1868
|
gcode_val = gcode_val[1]
|
1869
|
rs = RadioSetting("gcode", "Group Code",
|
1870
|
RadioSettingValueList(GROUPCODE,
|
1871
|
gcode_val))
|
1872
|
dtmf.append(rs)
|
1873
|
|
1874
|
icode_list = self._memobj.icode.idcode
|
1875
|
used_icode = ''
|
1876
|
for i in icode_list:
|
1877
|
if i == 0xFF:
|
1878
|
continue
|
1879
|
used_icode += str(i)[3]
|
1880
|
dtmfcharsani = "0123456789ABCD "
|
1881
|
i_val = RadioSettingValueString(0, 3, used_icode)
|
1882
|
rs = RadioSetting("icode", "ID Code", i_val)
|
1883
|
i_val.set_charset(dtmfcharsani)
|
1884
|
dtmf.append(rs)
|
1885
|
|
1886
|
gcode_list_1 = self._memobj.group1.group1
|
1887
|
used_group1 = ''
|
1888
|
for i in gcode_list_1:
|
1889
|
if i == 0xFF:
|
1890
|
continue
|
1891
|
used_group1 += str(i)[3]
|
1892
|
group1_val = RadioSettingValueString(0, 7, used_group1)
|
1893
|
rs = RadioSetting("group1", "1", group1_val)
|
1894
|
group1_val.set_charset(dtmfcharsani)
|
1895
|
dtmf.append(rs)
|
1896
|
|
1897
|
gcode_list_2 = self._memobj.group2.group2
|
1898
|
used_group2 = ''
|
1899
|
for i in gcode_list_2:
|
1900
|
if i == 0xFF:
|
1901
|
continue
|
1902
|
used_group2 += str(i)[3]
|
1903
|
group2_val = RadioSettingValueString(0, 7, used_group2)
|
1904
|
rs = RadioSetting("group2", "2", group2_val)
|
1905
|
group2_val.set_charset(dtmfcharsani)
|
1906
|
dtmf.append(rs)
|
1907
|
|
1908
|
gcode_list_3 = self._memobj.group3.group3
|
1909
|
used_group3 = ''
|
1910
|
for i in gcode_list_3:
|
1911
|
if i == 0xFF:
|
1912
|
continue
|
1913
|
used_group3 += str(i)[3]
|
1914
|
group3_val = RadioSettingValueString(0, 7, used_group3)
|
1915
|
rs = RadioSetting("group3", "3", group3_val)
|
1916
|
group3_val.set_charset(dtmfcharsani)
|
1917
|
dtmf.append(rs)
|
1918
|
|
1919
|
gcode_list_4 = self._memobj.group4.group4
|
1920
|
used_group4 = ''
|
1921
|
for i in gcode_list_4:
|
1922
|
if i == 0xFF:
|
1923
|
continue
|
1924
|
used_group4 += str(i)[3]
|
1925
|
group4_val = RadioSettingValueString(0, 7, used_group4)
|
1926
|
rs = RadioSetting("group4", "4", group4_val)
|
1927
|
group4_val.set_charset(dtmfcharsani)
|
1928
|
dtmf.append(rs)
|
1929
|
|
1930
|
gcode_list_5 = self._memobj.group5.group5
|
1931
|
used_group5 = ''
|
1932
|
for i in gcode_list_5:
|
1933
|
if i == 0xFF:
|
1934
|
continue
|
1935
|
used_group5 += str(i)[3]
|
1936
|
group5_val = RadioSettingValueString(0, 7, used_group5)
|
1937
|
rs = RadioSetting("group5", "5", group5_val)
|
1938
|
group5_val.set_charset(dtmfcharsani)
|
1939
|
dtmf.append(rs)
|
1940
|
|
1941
|
gcode_list_6 = self._memobj.group6.group6
|
1942
|
used_group6 = ''
|
1943
|
for i in gcode_list_6:
|
1944
|
if i == 0xFF:
|
1945
|
continue
|
1946
|
used_group6 += str(i)[3]
|
1947
|
group6_val = RadioSettingValueString(0, 7, used_group6)
|
1948
|
rs = RadioSetting("group6", "6", group6_val)
|
1949
|
group6_val.set_charset(dtmfcharsani)
|
1950
|
dtmf.append(rs)
|
1951
|
|
1952
|
gcode_list_7 = self._memobj.group7.group7
|
1953
|
used_group7 = ''
|
1954
|
for i in gcode_list_7:
|
1955
|
if i == 0xFF:
|
1956
|
continue
|
1957
|
used_group7 += str(i)[3]
|
1958
|
group7_val = RadioSettingValueString(0, 7, used_group7)
|
1959
|
rs = RadioSetting("group7", "7", group7_val)
|
1960
|
group7_val.set_charset(dtmfcharsani)
|
1961
|
dtmf.append(rs)
|
1962
|
|
1963
|
gcode_list_8 = self._memobj.group8.group8
|
1964
|
used_group8 = ''
|
1965
|
for i in gcode_list_8:
|
1966
|
if i == 0xFF:
|
1967
|
continue
|
1968
|
used_group8 += str(i)[3]
|
1969
|
group8_val = RadioSettingValueString(0, 7, used_group8)
|
1970
|
rs = RadioSetting("group8", "8", group7_val)
|
1971
|
group8_val.set_charset(dtmfcharsani)
|
1972
|
dtmf.append(rs)
|
1973
|
|
1974
|
scode_list = self._memobj.startcode.scode
|
1975
|
used_scode = ''
|
1976
|
for i in scode_list:
|
1977
|
if i == 0xFF:
|
1978
|
continue
|
1979
|
used_scode += str(i)[3]
|
1980
|
scode_val = RadioSettingValueString(0, 7, used_scode)
|
1981
|
rs = RadioSetting("scode", "PTT ID Starting(BOT)", scode_val)
|
1982
|
scode_val.set_charset(dtmfcharsani)
|
1983
|
dtmf.append(rs)
|
1984
|
|
1985
|
ecode_list = self._memobj.endcode.ecode
|
1986
|
used_ecode = ''
|
1987
|
for i in ecode_list:
|
1988
|
if i == 0xFF:
|
1989
|
continue
|
1990
|
used_ecode += str(i)[3]
|
1991
|
ecode_val = RadioSettingValueString(0, 7, used_ecode)
|
1992
|
rs = RadioSetting("ecode", "PTT ID Ending(BOT)", ecode_val)
|
1993
|
dtmf.append(rs)
|
1994
|
# H3
|
1995
|
if self.MODEL not in H8_LIST:
|
1996
|
# stuncode
|
1997
|
ecode_list = self._memobj.skcode.stuncode
|
1998
|
used_ecode = ''
|
1999
|
for i in ecode_list:
|
2000
|
if i == 0xFF:
|
2001
|
continue
|
2002
|
used_ecode += str(i)[3]
|
2003
|
ecode_val = RadioSettingValueString(0, 16, used_ecode)
|
2004
|
rs = RadioSetting("stuncode", "Stun Code", ecode_val)
|
2005
|
dtmf.append(rs)
|
2006
|
# killcode
|
2007
|
ecode_list = self._memobj.skcode.killcode
|
2008
|
used_ecode = ''
|
2009
|
for i in ecode_list:
|
2010
|
if i == 0xFF:
|
2011
|
continue
|
2012
|
used_ecode += str(i)[3]
|
2013
|
ecode_val = RadioSettingValueString(0, 16, used_ecode)
|
2014
|
rs = RadioSetting("killcode", "Kill Code", ecode_val)
|
2015
|
dtmf.append(rs)
|
2016
|
|
2017
|
return group
|
2018
|
|
2019
|
def get_settings(self):
|
2020
|
try:
|
2021
|
return self._get_settings()
|
2022
|
except Exception:
|
2023
|
raise InvalidValueError("Setting Failed!")
|
2024
|
|
2025
|
def set_settings(self, settings):
|
2026
|
|
2027
|
def fm_validate(value):
|
2028
|
if 760 > value or value > 1080:
|
2029
|
msg = ("FM Channel must be between 76.0-108.0")
|
2030
|
raise InvalidValueError(msg)
|
2031
|
|
2032
|
_settings = self._memobj.settings
|
2033
|
_press = self._memobj.press
|
2034
|
_aoffset = self._memobj.aoffset
|
2035
|
_boffset = self._memobj.boffset
|
2036
|
_vfoa = self._memobj.vfoa
|
2037
|
_vfob = self._memobj.vfob
|
2038
|
_fmmode = self._memobj.fmmode
|
2039
|
|
2040
|
for element in settings:
|
2041
|
if not isinstance(element, RadioSetting):
|
2042
|
if element.get_name() == "fm_preset":
|
2043
|
self._set_fm_preset(element)
|
2044
|
else:
|
2045
|
self.set_settings(element)
|
2046
|
continue
|
2047
|
else:
|
2048
|
try:
|
2049
|
name = element.get_name()
|
2050
|
if "." in name:
|
2051
|
bits = name.split(".")
|
2052
|
obj = self._memobj
|
2053
|
for bit in bits[:-1]:
|
2054
|
if "/" in bit:
|
2055
|
bit, index = bit.split("/", 1)
|
2056
|
index = int(index)
|
2057
|
obj = getattr(obj, bit)[index]
|
2058
|
else:
|
2059
|
obj = getattr(obj, bit)
|
2060
|
setting = bits[-1]
|
2061
|
elif name in PRESS_NAME:
|
2062
|
obj = _press
|
2063
|
setting = element.get_name()
|
2064
|
|
2065
|
elif name in VFOA_NAME:
|
2066
|
obj = _vfoa
|
2067
|
setting = element.get_name()
|
2068
|
elif name == "ofseta":
|
2069
|
obj = _aoffset
|
2070
|
setting = element.get_name()
|
2071
|
elif name in VFOB_NAME:
|
2072
|
obj = _vfob
|
2073
|
setting = element.get_name()
|
2074
|
elif name == "ofsetb":
|
2075
|
obj = _boffset
|
2076
|
setting = element.get_name()
|
2077
|
elif "block" in name:
|
2078
|
obj = _fmmode
|
2079
|
setting = element.get_name()
|
2080
|
elif "fmvfo" in name:
|
2081
|
obj = self._memobj.fmvfo
|
2082
|
setting = element.get_name()
|
2083
|
elif "gcode" in name:
|
2084
|
obj = self._memobj.groupcode.gcode
|
2085
|
setting = element.get_name()
|
2086
|
elif "idcode" in name:
|
2087
|
obj = self._memobj.icode.idcode
|
2088
|
setting = element.get_name()
|
2089
|
elif "scode" in name:
|
2090
|
obj = self._memobj.startcode.scode
|
2091
|
setting = element.get_name()
|
2092
|
elif "ecode" in name:
|
2093
|
obj = self._memobj.endcode.ecode
|
2094
|
setting = element.get_name()
|
2095
|
elif "group1" in name:
|
2096
|
obj = self._memobj.group1.group1
|
2097
|
setting = element.get_name()
|
2098
|
elif "group2" in name:
|
2099
|
obj = self._memobj.group2.group2
|
2100
|
setting = element.get_name()
|
2101
|
elif "group3" in name:
|
2102
|
obj = self._memobj.group3.group3
|
2103
|
setting = element.get_name()
|
2104
|
elif "group4" in name:
|
2105
|
obj = self._memobj.group4.group4
|
2106
|
setting = element.get_name()
|
2107
|
elif "group5" in name:
|
2108
|
obj = self._memobj.group5.group5
|
2109
|
setting = element.get_name()
|
2110
|
elif "group6" in name:
|
2111
|
obj = self._memobj.group6.group6
|
2112
|
setting = element.get_name()
|
2113
|
elif "group7" in name:
|
2114
|
obj = self._memobj.group7.group7
|
2115
|
setting = element.get_name()
|
2116
|
elif "group8" in name:
|
2117
|
obj = self._memobj.group8.group8
|
2118
|
setting = element.get_name()
|
2119
|
elif "micgain" in name:
|
2120
|
obj = self._memobj.mic.micgain
|
2121
|
setting = element.get_name()
|
2122
|
elif "killcode" in name:
|
2123
|
obj = self._memobj.skcode.killcode
|
2124
|
setting = element.get_name()
|
2125
|
elif "stuncode" in name:
|
2126
|
obj = self._memobj.skcode.stuncode
|
2127
|
setting = element.get_name()
|
2128
|
else:
|
2129
|
obj = _settings
|
2130
|
setting = element.get_name()
|
2131
|
if element.has_apply_callback():
|
2132
|
LOG.debug("Using apply callback")
|
2133
|
element.run_apply_callback()
|
2134
|
|
2135
|
# Channel A
|
2136
|
elif setting == "rxfreqa" and element.value.get_mutable():
|
2137
|
val = int(str(element.value).replace(
|
2138
|
'.', '').ljust(8, '0'))
|
2139
|
if (val >= 13600000 and val <= 17400000) or \
|
2140
|
(val >= 40000000 and val <= 52000000):
|
2141
|
setattr(obj, setting, val)
|
2142
|
else:
|
2143
|
msg = (
|
2144
|
"Frequency must be between "
|
2145
|
"136.00000-174.00000 or 400.00000-520.00000")
|
2146
|
raise InvalidValueError(msg)
|
2147
|
|
2148
|
elif setting == "ofseta" and element.value.get_mutable():
|
2149
|
if '.' in str(element.value):
|
2150
|
val = str(element.value).replace(' ', '')
|
2151
|
if len(
|
2152
|
val[val.index(".") + 1:]
|
2153
|
) >= 1 and int(val[val.index(".") + 1:]
|
2154
|
) != 0:
|
2155
|
val = '00' + val.replace('.', '')
|
2156
|
else:
|
2157
|
val = '0' + val.replace('.', '')
|
2158
|
val = val.ljust(8, '0')
|
2159
|
lenth_val = 0
|
2160
|
list_val = []
|
2161
|
else:
|
2162
|
val = '0' + str(element.value).replace(' ', '')
|
2163
|
val = val.ljust(8, '0')
|
2164
|
lenth_val = 0
|
2165
|
list_val = []
|
2166
|
if (int(val) >= 0 and int(val) <= 5999750):
|
2167
|
if int(val) == 0:
|
2168
|
_aoffset.ofseta = [0xFF, 0xFF, 0xFF, 0xFF]
|
2169
|
else:
|
2170
|
while lenth_val < (len(val)):
|
2171
|
list_val.insert(
|
2172
|
0, val[lenth_val:lenth_val + 2])
|
2173
|
lenth_val += 2
|
2174
|
for i in range(len(list_val)):
|
2175
|
list_val[i] = int(list_val[i], 16)
|
2176
|
_aoffset.ofseta = list_val
|
2177
|
else:
|
2178
|
msg = ("Offset must be between 0.00000-59.99750")
|
2179
|
raise InvalidValueError(msg)
|
2180
|
|
2181
|
# B channel
|
2182
|
elif setting == "rxfreqb" and element.value.get_mutable():
|
2183
|
val = 0
|
2184
|
val = int(str(element.value).replace(
|
2185
|
'.', '').ljust(8, '0'))
|
2186
|
if (val >= 13600000 and val <= 17400000) or \
|
2187
|
(val >= 40000000 and val <= 52000000):
|
2188
|
setattr(obj, setting, val)
|
2189
|
else:
|
2190
|
msg = (
|
2191
|
"Frequency must be between "
|
2192
|
"136.00000-174.00000 or 400.00000-520.00000")
|
2193
|
raise InvalidValueError(msg)
|
2194
|
# setattr(obj, setting, val)
|
2195
|
|
2196
|
elif setting == "ofsetb" and element.value.get_mutable():
|
2197
|
if '.' in str(element.value):
|
2198
|
val = str(element.value).replace(' ', '')
|
2199
|
if len(val[val.index(".") + 1:]
|
2200
|
) >= 1 and int(val[val.index(".") + 1:]
|
2201
|
) != 0:
|
2202
|
val = '00' + \
|
2203
|
str(element.value).replace('.', '')
|
2204
|
else:
|
2205
|
val = '0' + str(element.value).replace('.', '')
|
2206
|
val = val.ljust(8, '0')
|
2207
|
lenth_val = 0
|
2208
|
list_val = []
|
2209
|
else:
|
2210
|
val = '0' + str(element.value).replace(' ', '')
|
2211
|
val = val.ljust(8, '0')
|
2212
|
lenth_val = 0
|
2213
|
list_val = []
|
2214
|
if (int(val) >= 0 and int(val) <= 5999750):
|
2215
|
if int(val) == 0:
|
2216
|
_boffset.ofsetb = [0xFF, 0xFF, 0xFF, 0xFF]
|
2217
|
else:
|
2218
|
while lenth_val < (len(val)):
|
2219
|
list_val.insert(
|
2220
|
0, val[lenth_val:lenth_val + 2])
|
2221
|
lenth_val += 2
|
2222
|
for i in range(len(list_val)):
|
2223
|
list_val[i] = int(list_val[i], 16)
|
2224
|
_boffset.ofsetb = list_val
|
2225
|
else:
|
2226
|
msg = ("Offset must be between 0.00000-59.99750")
|
2227
|
raise InvalidValueError(msg)
|
2228
|
|
2229
|
# FM
|
2230
|
elif "block" in name:
|
2231
|
num = int(name[-2:], 10)
|
2232
|
val = str(element.value)
|
2233
|
if val.strip():
|
2234
|
try:
|
2235
|
val = int(float(val) * 10)
|
2236
|
except ValueError:
|
2237
|
raise InvalidValueError(
|
2238
|
'Value must be between 76.0-108.0')
|
2239
|
fm_validate(val)
|
2240
|
else:
|
2241
|
val = 0
|
2242
|
self._memobj.fmmode[num].fmblock = val
|
2243
|
self._memobj.fmusedflags[num] = bool(val)
|
2244
|
|
2245
|
elif setting == 'fmvfo' and element.value.get_mutable():
|
2246
|
self._memobj.fmvfo = int(element.value * 10)
|
2247
|
|
2248
|
elif setting == 'gcode' and element.value.get_mutable():
|
2249
|
val = str(element.value)
|
2250
|
if val == 'Off':
|
2251
|
gcode_used = 0xFF
|
2252
|
elif val == 'A':
|
2253
|
gcode_used = 0x0A
|
2254
|
elif val == 'B':
|
2255
|
gcode_used = 0x0B
|
2256
|
elif val == 'C':
|
2257
|
gcode_used = 0x0C
|
2258
|
elif val == 'D':
|
2259
|
gcode_used = 0x0D
|
2260
|
elif val == '#':
|
2261
|
gcode_used = 0x0F
|
2262
|
elif val == '*':
|
2263
|
gcode_used = 0x0E
|
2264
|
elif val == '':
|
2265
|
gcode_used = 0x00
|
2266
|
self._memobj.groupcode.gcode = gcode_used
|
2267
|
|
2268
|
elif setting == 'icode' and element.value.get_mutable():
|
2269
|
val = str(element.value)
|
2270
|
list_val = []
|
2271
|
lenth_val = 0
|
2272
|
while lenth_val < (len(val)):
|
2273
|
if val[lenth_val] != ' ':
|
2274
|
list_val.append(int(val[lenth_val], 16))
|
2275
|
lenth_val += 1
|
2276
|
else:
|
2277
|
list_val.append(0xFF)
|
2278
|
lenth_val += 1
|
2279
|
self._memobj.icode.idcode = list_val
|
2280
|
|
2281
|
elif setting == 'scode' and element.value.get_mutable():
|
2282
|
val = str(element.value)
|
2283
|
list_val = []
|
2284
|
lenth_val = 0
|
2285
|
while lenth_val < (len(val)):
|
2286
|
if val[lenth_val] != ' ':
|
2287
|
list_val.append(int(val[lenth_val], 16))
|
2288
|
lenth_val += 1
|
2289
|
else:
|
2290
|
list_val.append(0xFF)
|
2291
|
lenth_val += 1
|
2292
|
self._memobj.startcode.scode = list_val
|
2293
|
|
2294
|
elif setting == 'ecode' and element.value.get_mutable():
|
2295
|
val = str(element.value)
|
2296
|
list_val = []
|
2297
|
lenth_val = 0
|
2298
|
while lenth_val < (len(val)):
|
2299
|
if val[lenth_val] != ' ':
|
2300
|
list_val.append(int(val[lenth_val], 16))
|
2301
|
lenth_val += 1
|
2302
|
else:
|
2303
|
list_val.append(0xFF)
|
2304
|
lenth_val += 1
|
2305
|
self._memobj.endcode.ecode = list_val
|
2306
|
|
2307
|
elif setting == 'group1' and element.value.get_mutable():
|
2308
|
val = str(element.value)
|
2309
|
list_val = []
|
2310
|
lenth_val = 0
|
2311
|
while lenth_val < (len(val)):
|
2312
|
if val[lenth_val] != ' ':
|
2313
|
list_val.append(int(val[lenth_val], 16))
|
2314
|
lenth_val += 1
|
2315
|
else:
|
2316
|
list_val.append(0xFF)
|
2317
|
lenth_val += 1
|
2318
|
self._memobj.group1.group1 = list_val
|
2319
|
|
2320
|
elif setting == 'group2' and element.value.get_mutable():
|
2321
|
val = str(element.value)
|
2322
|
list_val = []
|
2323
|
lenth_val = 0
|
2324
|
while lenth_val < (len(val)):
|
2325
|
if val[lenth_val] != ' ':
|
2326
|
list_val.append(int(val[lenth_val], 16))
|
2327
|
lenth_val += 1
|
2328
|
else:
|
2329
|
list_val.append(0xFF)
|
2330
|
lenth_val += 1
|
2331
|
self._memobj.group2.group2 = list_val
|
2332
|
|
2333
|
elif setting == 'group3' and element.value.get_mutable():
|
2334
|
val = str(element.value)
|
2335
|
list_val = []
|
2336
|
lenth_val = 0
|
2337
|
while lenth_val < (len(val)):
|
2338
|
if val[lenth_val] != ' ':
|
2339
|
list_val.append(int(val[lenth_val], 16))
|
2340
|
lenth_val += 1
|
2341
|
else:
|
2342
|
list_val.append(0xFF)
|
2343
|
lenth_val += 1
|
2344
|
self._memobj.group3.group3 = list_val
|
2345
|
|
2346
|
elif setting == 'group4' and element.value.get_mutable():
|
2347
|
val = str(element.value)
|
2348
|
list_val = []
|
2349
|
lenth_val = 0
|
2350
|
while lenth_val < (len(val)):
|
2351
|
if val[lenth_val] != ' ':
|
2352
|
list_val.append(int(val[lenth_val], 16))
|
2353
|
lenth_val += 1
|
2354
|
else:
|
2355
|
list_val.append(0xFF)
|
2356
|
lenth_val += 1
|
2357
|
self._memobj.group4.group4 = list_val
|
2358
|
|
2359
|
elif setting == 'group5' and element.value.get_mutable():
|
2360
|
val = str(element.value)
|
2361
|
list_val = []
|
2362
|
lenth_val = 0
|
2363
|
while lenth_val < (len(val)):
|
2364
|
if val[lenth_val] != ' ':
|
2365
|
list_val.append(int(val[lenth_val], 16))
|
2366
|
lenth_val += 1
|
2367
|
else:
|
2368
|
list_val.append(0xFF)
|
2369
|
lenth_val += 1
|
2370
|
self._memobj.group5.group5 = list_val
|
2371
|
|
2372
|
elif setting == 'group6' and element.value.get_mutable():
|
2373
|
val = str(element.value)
|
2374
|
list_val = []
|
2375
|
lenth_val = 0
|
2376
|
while lenth_val < (len(val)):
|
2377
|
if val[lenth_val] != ' ':
|
2378
|
list_val.append(int(val[lenth_val], 16))
|
2379
|
lenth_val += 1
|
2380
|
else:
|
2381
|
list_val.append(0xFF)
|
2382
|
lenth_val += 1
|
2383
|
self._memobj.group6.group6 = list_val
|
2384
|
|
2385
|
elif setting == 'group7' and element.value.get_mutable():
|
2386
|
val = str(element.value)
|
2387
|
list_val = []
|
2388
|
lenth_val = 0
|
2389
|
while lenth_val < (len(val)):
|
2390
|
if val[lenth_val] != ' ':
|
2391
|
list_val.append(int(val[lenth_val], 16))
|
2392
|
lenth_val += 1
|
2393
|
else:
|
2394
|
list_val.append(0xFF)
|
2395
|
lenth_val += 1
|
2396
|
self._memobj.group7.group7 = list_val
|
2397
|
|
2398
|
elif setting == 'group8' and element.value.get_mutable():
|
2399
|
val = str(element.value)
|
2400
|
list_val = []
|
2401
|
lenth_val = 0
|
2402
|
while lenth_val < (len(val)):
|
2403
|
if val[lenth_val] != ' ':
|
2404
|
list_val.append(int(val[lenth_val], 16))
|
2405
|
lenth_val += 1
|
2406
|
else:
|
2407
|
list_val.append(0xFF)
|
2408
|
lenth_val += 1
|
2409
|
self._memobj.group8.group8 = list_val
|
2410
|
elif setting == 'micgain':
|
2411
|
self._memobj.mic.micgain = (
|
2412
|
str(element.value))
|
2413
|
elif setting == 'stuncode' and element.value.get_mutable():
|
2414
|
val = str(element.value)
|
2415
|
list_val = []
|
2416
|
lenth_val = 0
|
2417
|
while lenth_val < (len(val)):
|
2418
|
if val[lenth_val] != ' ':
|
2419
|
list_val.append(int(val[lenth_val], 16))
|
2420
|
lenth_val += 1
|
2421
|
else:
|
2422
|
list_val.append(0xFF)
|
2423
|
lenth_val += 1
|
2424
|
self._memobj.skcode.stuncode = list_val
|
2425
|
elif setting == 'killcode' and element.value.get_mutable():
|
2426
|
val = str(element.value)
|
2427
|
list_val = []
|
2428
|
lenth_val = 0
|
2429
|
while lenth_val < (len(val)):
|
2430
|
if val[lenth_val] != ' ':
|
2431
|
list_val.append(int(val[lenth_val], 16))
|
2432
|
lenth_val += 1
|
2433
|
else:
|
2434
|
list_val.append(0xFF)
|
2435
|
lenth_val += 1
|
2436
|
self._memobj.skcode.killcode = list_val
|
2437
|
elif element.value.get_mutable():
|
2438
|
setattr(obj, setting, element.value)
|
2439
|
except Exception:
|
2440
|
LOG.debug(element.get_name())
|
2441
|
raise
|
2442
|
|
2443
|
def _set_fm_preset(self, settings):
|
2444
|
for element in settings:
|
2445
|
try:
|
2446
|
val = element.value
|
2447
|
if self._memobj.fm_presets <= 108.0 * 10 - 650:
|
2448
|
value = int(val.get_value() * 10 - 650)
|
2449
|
else:
|
2450
|
value = int(val.get_value() * 10)
|
2451
|
LOG.debug("Setting fm_presets = %s" % (value))
|
2452
|
self._memobj.fm_presets = value
|
2453
|
except Exception:
|
2454
|
LOG.debug(element.get_name())
|
2455
|
raise
|
2456
|
|
2457
|
|
2458
|
@directory.register
|
2459
|
@directory.detected_by(TDH8)
|
2460
|
class TDH8_HAM(TDH8):
|
2461
|
VENDOR = "TIDRADIO"
|
2462
|
MODEL = "TD-H8-HAM"
|
2463
|
ident_mode = b'P31185\xff\xff'
|
2464
|
_ham = True
|
2465
|
_txbands = [(144000000, 149000000), (420000000, 451000000)]
|
2466
|
|
2467
|
|
2468
|
@directory.register
|
2469
|
@directory.detected_by(TDH8)
|
2470
|
class TDH8_GMRS(TDH8):
|
2471
|
VENDOR = "TIDRADIO"
|
2472
|
MODEL = "TD-H8-GMRS"
|
2473
|
ident_mode = b'P31184\xff\xff'
|
2474
|
_gmrs = True
|
2475
|
_txbands = [(136000000, 175000000), (400000000, 521000000)]
|
2476
|
_tx_power = [chirp_common.PowerLevel("Low", watts=1.00),
|
2477
|
chirp_common.PowerLevel("High", watts=8.00)]
|
2478
|
|
2479
|
def validate_memory(self, mem):
|
2480
|
msgs = super().validate_memory(mem)
|
2481
|
if 31 <= mem.number <= 54 and mem.freq not in GMRS_FREQS:
|
2482
|
msgs.append(chirp_common.ValidationError(
|
2483
|
"The frequency in channels 31-54 must be between"
|
2484
|
"462.55000-462.72500 in 0.025 increments."))
|
2485
|
return msgs
|
2486
|
|
2487
|
|
2488
|
@directory.register
|
2489
|
class UV68(TDH8):
|
2490
|
VENDOR = "TID"
|
2491
|
MODEL = "TD-UV68"
|
2492
|
|
2493
|
|
2494
|
@directory.register
|
2495
|
class TDH3(TDH8):
|
2496
|
VENDOR = "TIDRADIO"
|
2497
|
MODEL = "TD-H3"
|
2498
|
_memsize = 0x1fef
|
2499
|
_ranges_main = [(0x0000, 0x1fef)]
|
2500
|
_idents = [TD_H3]
|
2501
|
_txbands = [(136000000, 600000000)]
|
2502
|
_rxbands = [(50000000, 107999000), (108000000, 136000000)]
|
2503
|
_aux_block = True
|
2504
|
_tri_power = True
|
2505
|
_gmrs = False
|
2506
|
_ham = False
|
2507
|
_mem_params = (0x1F2F)
|
2508
|
_tx_power = [chirp_common.PowerLevel("Low", watts=1.00),
|
2509
|
chirp_common.PowerLevel("High", watts=4.00)]
|
2510
|
|
2511
|
def process_mmap(self):
|
2512
|
self._memobj = bitwise.parse(MEM_FORMAT_H3, self._mmap)
|
2513
|
|
2514
|
|
2515
|
@directory.register
|
2516
|
@directory.detected_by(TDH3)
|
2517
|
class TDH3_HAM(TDH3):
|
2518
|
VENDOR = "TIDRADIO"
|
2519
|
MODEL = "TD-H3-HAM"
|
2520
|
ident_mode = b'P31185\xff\xff'
|
2521
|
_ham = True
|
2522
|
_txbands = [(144000000, 149000000), (420000000, 451000000)]
|
2523
|
|
2524
|
|
2525
|
@directory.register
|
2526
|
@directory.detected_by(TDH3)
|
2527
|
class TDH3_GMRS(TDH3):
|
2528
|
VENDOR = "TIDRADIO"
|
2529
|
MODEL = "TD-H3-GMRS"
|
2530
|
ident_mode = b'P31184\xff\xff'
|
2531
|
_gmrs = True
|
2532
|
_txbands = [(136000000, 175000000), (400000000, 521000000)]
|
2533
|
|
2534
|
def validate_memory(self, mem):
|
2535
|
msgs = super().validate_memory(mem)
|
2536
|
if 31 <= mem.number <= 54 and mem.freq not in GMRS_FREQS:
|
2537
|
msgs.append(chirp_common.ValidationError(
|
2538
|
"The frequency in channels 31-54 must be between"
|
2539
|
"462.55000-462.72500 in 0.025 increments."))
|
2540
|
return msgs
|
2541
|
|
2542
|
|
2543
|
@directory.register
|
2544
|
class RT730(TDH8):
|
2545
|
VENDOR = "Radtel"
|
2546
|
MODEL = "RT-730"
|
2547
|
_memsize = 0x6400
|
2548
|
_ranges_main = [(0x0000, 0x6400)]
|
2549
|
_idents = [RT_730]
|
2550
|
_txbands = [(136000000, 174000000), (174000000, 300000000),
|
2551
|
(300000000, 400000000), (400000000, 520000000),
|
2552
|
(520000000, 630000000)]
|
2553
|
_rxbands = [(10000000, 108000000), (108000000, 136000000)]
|
2554
|
_tri_power = True
|
2555
|
_gmrs = False
|
2556
|
_ham = False
|
2557
|
|
2558
|
def process_mmap(self):
|
2559
|
self._memobj = bitwise.parse(MEM_FORMAT_RT730, self._mmap)
|