Project

General

Profile

New Model #10692 » kgq10h b2p6.py

KG-Q10H - KG-Q10G --- Beta 2.6 - Mel Terechenok, 01/08/2024 03:17 PM

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

    
22
"""Wouxun KG-Q10H radio management module"""
23

    
24
import struct
25
import time
26
import logging
27

    
28
from chirp import util, chirp_common, bitwise, memmap, errors, directory
29
from chirp.settings import RadioSetting, RadioSettingGroup, \
30
    RadioSettingValueBoolean, RadioSettingValueList, \
31
    RadioSettingValueInteger, RadioSettingValueString, \
32
    RadioSettingValueFloat, RadioSettingValueMap, RadioSettings, \
33
    InvalidValueError#, RadioSettingValueRGB
34

    
35

    
36
LOG = logging.getLogger(__name__)
37

    
38
CMD_ID = 128    # \x80
39
CMD_END = 129   # \x81
40
CMD_RD = 130    # \82
41
CMD_WR = 131    # \83
42

    
43
MEM_VALID = 158
44

    
45
# set up map of addresses to upload to known memory locations only
46
# Add new regions as new settings are discovered
47
# 1st entry is start address in hex
48
# 2nd entry is write size (number of bytes to transfer in decimal (64-MAX))
49
# 3rd entry is write count
50
# so 0x00, 64, 512 =  start at 0x00 and write 64*512 bytes = 0 - 32768
51

    
52
# NOTE :   It looks like the radio MUST have write
53
#          sizes in values of 1,2,4,8,16,32 or 64 bytes if using
54
#          a write count value of > 1.
55
#          OTHERWISE - it appears the radio gets out of sync
56
#          and the memory write is messed up
57
#          for that section
58

    
59
Q10H_download_map_full = (
60
    (0x00, 64, 512),  # - Use for full Download testing
61
)
62
Q10H_mem_arrange_map = (
63
    (0x0300, 0x0400),
64
    (0x0200, 0x0300),
65
    (0x0100, 0x0200),
66
    (0x0000, 0x0100),
67

    
68
    (0x0700, 0x0800),
69
    (0x0600, 0x0700),  # channel 1 data start
70
    (0x0500, 0x0600),
71
    (0x0400, 0x0500),
72

    
73
    (0x0b00, 0x0c00),
74
    (0x0a00, 0x0b00),
75
    (0x0900, 0x0a00),
76
    (0x0800, 0x0900),
77

    
78
    (0x0f00, 0x1000),
79
    (0x0e00, 0x0f00),
80
    (0x0d00, 0x0e00),
81
    (0x0c00, 0x0d00),
82

    
83
    (0x1300, 0x1400),
84
    (0x1200, 0x1300),
85
    (0x1100, 0x1200),
86
    (0x1000, 0x1100),
87

    
88
    (0x1700, 0x1800),
89
    (0x1600, 0x1700),
90
    (0x1500, 0x1600),
91
    (0x1400, 0x1500),
92

    
93
    (0x1B00, 0x1c00),
94
    (0x1a00, 0x1b00),
95
    (0x1900, 0x1a00),
96
    (0x1800, 0x1900),
97

    
98
    (0x1f00, 0x2000),
99
    (0x1e00, 0x1f00),
100
    (0x1d00, 0x1e00),
101
    (0x1c00, 0x1d00),
102

    
103
    (0x2300, 0x2400),
104
    (0x2200, 0x2300),
105
    (0x2100, 0x2200),
106
    (0x2000, 0x2100),
107

    
108
    (0x2700, 0x2800),
109
    (0x2600, 0x2700),
110
    (0x2500, 0x2600),
111
    (0x2400, 0x2500),
112

    
113
    (0x2B00, 0x2C00),
114
    (0x2a00, 0x2b00),
115
    (0x2900, 0x2a00),
116
    (0x2800, 0x2900),
117

    
118
    (0x2f00, 0x3000),
119
    (0x2e00, 0x2f00),
120
    (0x2d00, 0x2e00),
121
    (0x2c00, 0x2d00),
122

    
123
    (0x3300, 0x3400),
124
    (0x3200, 0x3300),
125
    (0x3100, 0x3200),
126
    (0x3000, 0x3100),
127

    
128
    (0x3700, 0x3800),
129
    (0x3600, 0x3700),
130
    (0x3500, 0x3600),
131
    (0x3400, 0x3500),
132

    
133
    (0x3B00, 0x3C00),
134
    (0x3a00, 0x3b00),
135
    (0x3900, 0x3a00),
136
    (0x3800, 0x3900),
137

    
138
    (0x3f00, 0x4000),
139
    (0x3e00, 0x3f00),
140
    (0x3d00, 0x3e00),
141
    (0x3c00, 0x3d00),
142

    
143
    (0x4300, 0x4400),
144
    (0x4200, 0x4300),
145
    (0x4100, 0x4200),
146
    (0x4000, 0x4100),
147

    
148
    (0x4700, 0x4760),
149

    
150
    (0x4760, 0x4800),  # start of Ch names
151
    (0x4600, 0x4700),
152
    (0x4500, 0x4600),
153
    (0x4400, 0x4500),
154
    (0x4b00, 0x4c00),
155
    (0x4a00, 0x4B00),
156
    (0x4900, 0x4a00),
157
    (0x4800, 0x4900),
158
    (0x4f00, 0x5000),
159
    (0x4E00, 0x4F00),
160
    (0x4D00, 0x4E00),
161
    (0x4C00, 0x4d00),
162
    (0x5300, 0x5400),
163
    (0x5200, 0x5300),
164
    (0x5100, 0x5200),
165
    (0x5000, 0x5100),
166
    (0x5700, 0x5800),
167
    (0x5600, 0x5700),
168
    (0x5500, 0x5600),
169
    (0x5400, 0x5500),
170
    (0x5B00, 0x5C00),
171
    (0x5A00, 0x5B00),
172
    (0x5900, 0x5A00),
173
    (0x5800, 0x5900),
174
    (0x5F00, 0x6000),
175
    (0x5E00, 0x5F00),
176
    (0x5D00, 0x5E00),
177
    (0x5C00, 0x5D00),
178
    (0x6300, 0x6400),
179
    (0x6200, 0x6300),
180
    (0x6100, 0x6200),
181
    (0x6000, 0x6100),
182
    (0x6700, 0x6800),
183
    (0x6600, 0x6700),
184
    (0x6500, 0x6600),
185
    (0x6400, 0x6500),
186
    (0x6b00, 0x6c00),
187
    (0x6a00, 0x6b00),
188
    (0x6900, 0x6a00),
189
    (0x6800, 0x6900),
190
    (0x6F00, 0x7000),
191
    (0x6e00, 0x6F00),
192
    (0X6D00, 0X6E00),
193
    (0X6C00, 0X6D00),
194
    (0x7300, 0x7400),
195
    (0x7200, 0x7300),
196
    (0x7100, 0x7200),
197
    (0x7000, 0x7040),  # End of Ch Names
198

    
199
    (0x7040, 0x7100),  # start of ch valid
200
    (0x7700, 0x7800),
201
    (0x7600, 0x7700),
202
    (0x7500, 0x7600),
203
    (0x7400, 0x7440),  # end of ch valid
204

    
205
    (0x7440, 0x7500),
206
    # (0x7800, 0x8000),
207
    (0x7b00, 0x7c00),
208
    (0x7a00, 0x7b00),
209
    (0x7900, 0x7a00),
210
    (0x7800, 0x7900),
211
    (0x7f00, 0x9000),
212
    (0x7e00, 0x7f00),
213
    (0x7d00, 0x7e00),
214
    (0x7c00, 0x7d00),
215
)
216

    
217

    
218
Q10H_mem_arrange_map_OLD = (
219
    (0x0000, 0x0400),
220
    (0x0600, 0x06E0),
221
    (0x0700, 0x0800),
222

    
223
    (0x06E0, 0x0700),  # channel 1 data start
224
    (0x0500, 0x0600),
225
    (0x0400, 0x0500),
226

    
227
    (0x0b00, 0x0c00),
228
    (0x0a00, 0x0b00),
229
    (0x0900, 0x0a00),
230
    (0x0800, 0x0900),
231

    
232
    (0x0f00, 0x1000),
233
    (0x0e00, 0x0f00),
234
    (0x0d00, 0x0e00),
235
    (0x0c00, 0x0d00),
236

    
237
    (0x1300, 0x1400),
238
    (0x1200, 0x1300),
239
    (0x1100, 0x1200),
240
    (0x1000, 0x1100),
241

    
242
    (0x1700, 0x1800),
243
    (0x1600, 0x1700),
244
    (0x1500, 0x1600),
245
    (0x1400, 0x1500),
246

    
247
    (0x1B00, 0x1c00),
248
    (0x1a00, 0x1b00),
249
    (0x1900, 0x1a00),
250
    (0x1800, 0x1900),
251

    
252
    (0x1f00, 0x2000),
253
    (0x1e00, 0x1f00),
254
    (0x1d00, 0x1e00),
255
    (0x1c00, 0x1d00),
256

    
257
    (0x2300, 0x2400),
258
    (0x2200, 0x2300),
259
    (0x2100, 0x2200),
260
    (0x2000, 0x2100),
261

    
262
    (0x2700, 0x2800),
263
    (0x2600, 0x2700),
264
    (0x2500, 0x2600),
265
    (0x2400, 0x2500),
266

    
267
    (0x2B00, 0x2C00),
268
    (0x2a00, 0x2b00),
269
    (0x2900, 0x2a00),
270
    (0x2800, 0x2900),
271

    
272
    (0x2f00, 0x3000),
273
    (0x2e00, 0x2f00),
274
    (0x2d00, 0x2e00),
275
    (0x2c00, 0x2d00),
276

    
277
    (0x3300, 0x3400),
278
    (0x3200, 0x3300),
279
    (0x3100, 0x3200),
280
    (0x3000, 0x3100),
281

    
282
    (0x3700, 0x3800),
283
    (0x3600, 0x3700),
284
    (0x3500, 0x3600),
285
    (0x3400, 0x3500),
286

    
287
    (0x3B00, 0x3C00),
288
    (0x3a00, 0x3b00),
289
    (0x3900, 0x3a00),
290
    (0x3800, 0x3900),
291

    
292
    (0x3f00, 0x4000),
293
    (0x3e00, 0x3f00),
294
    (0x3d00, 0x3e00),
295
    (0x3c00, 0x3d00),
296

    
297
    (0x4300, 0x4400),
298
    (0x4200, 0x4300),
299
    (0x4100, 0x4200),
300
    (0x4000, 0x4100),
301

    
302
    (0x4700, 0x4760),
303

    
304
    (0x4760, 0x4800),  # start of Ch names
305
    (0x4600, 0x4700),
306
    (0x4500, 0x4600),
307
    (0x4400, 0x4500),
308
    (0x4b00, 0x4c00),
309
    (0x4a00, 0x4B00),
310
    (0x4900, 0x4a00),
311
    (0x4800, 0x4900),
312
    (0x4f00, 0x5000),
313
    (0x4E00, 0x4F00),
314
    (0x4D00, 0x4E00),
315
    (0x4C00, 0x4d00),
316
    (0x5300, 0x5400),
317
    (0x5200, 0x5300),
318
    (0x5100, 0x5200),
319
    (0x5000, 0x5100),
320
    (0x5700, 0x5800),
321
    (0x5600, 0x5700),
322
    (0x5500, 0x5600),
323
    (0x5400, 0x5500),
324
    (0x5B00, 0x5C00),
325
    (0x5A00, 0x5B00),
326
    (0x5900, 0x5A00),
327
    (0x5800, 0x5900),
328
    (0x5F00, 0x6000),
329
    (0x5E00, 0x5F00),
330
    (0x5D00, 0x5E00),
331
    (0x5C00, 0x5D00),
332
    (0x6300, 0x6400),
333
    (0x6200, 0x6300),
334
    (0x6100, 0x6200),
335
    (0x6000, 0x6100),
336
    (0x6700, 0x6800),
337
    (0x6600, 0x6700),
338
    (0x6500, 0x6600),
339
    (0x6400, 0x6500),
340
    (0x6b00, 0x6c00),
341
    (0x6a00, 0x6b00),
342
    (0x6900, 0x6a00),
343
    (0x6800, 0x6900),
344
    (0x6F00, 0x7000),
345
    (0x6e00, 0x6F00),
346
    (0X6D00, 0X6E00),
347
    (0X6C00, 0X6D00),
348
    (0x7300, 0x7400),
349
    (0x7200, 0x7300),
350
    (0x7100, 0x7200),
351
    (0x7000, 0x7040),  # End of Ch Names
352

    
353
    (0x7040, 0x7100),  # start of ch valid
354
    (0x7700, 0x7800),
355
    (0x7600, 0x7700),
356
    (0x7500, 0x7600),
357
    (0x7400, 0x7440),  # end of ch valid
358

    
359
    (0x7440, 0x7500),
360
    # (0x7800, 0x8000),
361
    (0x7b00, 0x7c00),
362
    (0x7a00, 0x7b00),
363
    (0x7900, 0x7a00),
364
    (0x7800, 0x7900),
365
    (0x7f00, 0x9000),
366
    (0x7e00, 0x7f00),
367
    (0x7d00, 0x7e00),
368
    (0x7c00, 0x7d00),
369
)
370

    
371
Q10H_upload_map = (
372
    #  This map serves 2 purposes-
373
    #   To limit the Upload to Radio Writes to known settings only
374
    #   And also to send the rearranged Chirp Memory data back to the radio
375
    #   using the proper radio addresses.
376
    #    Radio   Radio   Chirp   Chirp  Blk  cnt
377
    #    start   end     start   end     sz
378
    # (0x0000, 0x0400, 0x0000, 0x0400, 64, 16),
379
    # (0x0600, 0x06E0, 0x0400, 0x04E0, 32, 7),
380
    # (0x0002, 0x0022, 0x0302, 0x0322, 32, 1), # Tx Limits
381
    # (0x00a6, 0x00fe, 0x00a6, 0x00fe,  8, 11), # Rx Limits
382
    # (0x030a, 0x030a, 0x030a, 0x030a,  1, 1),  # Factory Locked Mode
383
    # (0x0640, 0x06c0, 0x0440, 0x04c0, 32, 7),  # VFO settings
384
    # (0x0700, 0x0800, 0x04E0, 0x05E0, 64, 4),  # settings
385
    # (0x06E0, 0x0700, 0x05E0, 0x0600, 32, 1),  # channel 1 data start
386
    (0x0300, 0x0400, 0x0000, 0x0100, 64, 4),
387
    (0x0200, 0x0300, 0x0100, 0x0200, 64, 4),
388
    (0x0100, 0x0200, 0x0200, 0x0300, 64, 4),
389
    (0x0000, 0x0100, 0x0300, 0x0400, 64, 4),
390
    (0x0700, 0x0800, 0x0400, 0x0500, 64, 4),
391
    (0x0600, 0x0700, 0x0500, 0x0600, 64, 4),
392
    (0x0500, 0x0600, 0x0600, 0x0700, 64, 4),
393
    (0x0400, 0x0500, 0x0700, 0x0800, 64, 4),
394
    (0x0b00, 0x0c00, 0x0800, 0x0900, 64, 4),
395
    (0x0a00, 0x0b00, 0x0900, 0x0A00, 64, 4),
396
    (0x0900, 0x0a00, 0x0A00, 0x0B00, 64, 4),
397
    (0x0800, 0x0900, 0x0B00, 0x0C00, 64, 4),
398
    (0x0f00, 0x1000, 0x0C00, 0x0D00, 64, 4),
399
    (0x0e00, 0x0f00, 0x0D00, 0x0E00, 64, 4),
400
    (0x0d00, 0x0e00, 0x0E00, 0x0F00, 64, 4),
401
    (0x0c00, 0x0d00, 0x0F00, 0x1000, 64, 4),
402
    (0x1300, 0x1400, 0x1000, 0x1100, 64, 4),
403
    (0x1200, 0x1300, 0x1100, 0x1200, 64, 4),
404
    (0x1100, 0x1200, 0x1200, 0x1300, 64, 4),
405
    (0x1000, 0x1100, 0x1300, 0x1400, 64, 4),
406
    (0x1700, 0x1800, 0x1400, 0x1500, 64, 4),
407
    (0x1600, 0x1700, 0x1500, 0x1600, 64, 4),
408
    (0x1500, 0x1600, 0x1600, 0x1700, 64, 4),
409
    (0x1400, 0x1500, 0x1700, 0x1800, 64, 4),
410
    (0x1B00, 0x1c00, 0x1800, 0x1900, 64, 4),
411
    (0x1a00, 0x1b00, 0x1900, 0x1A00, 64, 4),
412
    (0x1900, 0x1a00, 0x1A00, 0x1B00, 64, 4),
413
    (0x1800, 0x1900, 0x1B00, 0x1C00, 64, 4),
414
    (0x1f00, 0x2000, 0x1C00, 0x1D00, 64, 4),
415
    (0x1e00, 0x1f00, 0x1D00, 0x1E00, 64, 4),
416
    (0x1d00, 0x1e00, 0x1E00, 0x1F00, 64, 4),
417
    (0x1c00, 0x1d00, 0x1F00, 0x2000, 64, 4),
418
    (0x2300, 0x2400, 0x2000, 0x2100, 64, 4),
419
    (0x2200, 0x2300, 0x2100, 0x2200, 64, 4),
420
    (0x2100, 0x2200, 0x2200, 0x2300, 64, 4),
421
    (0x2000, 0x2100, 0x2300, 0x2400, 64, 4),
422
    (0x2700, 0x2800, 0x2400, 0x2500, 64, 4),
423
    (0x2600, 0x2700, 0x2500, 0x2600, 64, 4),
424
    (0x2500, 0x2600, 0x2600, 0x2700, 64, 4),
425
    (0x2400, 0x2500, 0x2700, 0x2800, 64, 4),
426
    (0x2B00, 0x2C00, 0x2800, 0x2900, 64, 4),
427
    (0x2a00, 0x2b00, 0x2900, 0x2A00, 64, 4),
428
    (0x2900, 0x2a00, 0x2A00, 0x2B00, 64, 4),
429
    (0x2800, 0x2900, 0x2B00, 0x2C00, 64, 4),
430
    (0x2f00, 0x3000, 0x2C00, 0x2D00, 64, 4),
431
    (0x2e00, 0x2f00, 0x2D00, 0x2E00, 64, 4),
432
    (0x2d00, 0x2e00, 0x2E00, 0x2F00, 64, 4),
433
    (0x2c00, 0x2d00, 0x2F00, 0x3000, 64, 4),
434
    (0x3300, 0x3400, 0x3000, 0x3100, 64, 4),
435
    (0x3200, 0x3300, 0x3100, 0x3200, 64, 4),
436
    (0x3100, 0x3200, 0x3200, 0x3300, 64, 4),
437
    (0x3000, 0x3100, 0x3300, 0x3400, 64, 4),
438
    (0x3700, 0x3800, 0x3400, 0x3500, 64, 4),
439
    (0x3600, 0x3700, 0x3500, 0x3600, 64, 4),
440
    (0x3500, 0x3600, 0x3600, 0x3700, 64, 4),
441
    (0x3400, 0x3500, 0x3700, 0x3800, 64, 4),
442
    (0x3B00, 0x3C00, 0x3800, 0x3900, 64, 4),
443
    (0x3a00, 0x3b00, 0x3900, 0x3A00, 64, 4),
444
    (0x3900, 0x3a00, 0x3A00, 0x3B00, 64, 4),
445
    (0x3800, 0x3900, 0x3B00, 0x3C00, 64, 4),
446
    (0x3f00, 0x4000, 0x3C00, 0x3D00, 64, 4),
447
    (0x3e00, 0x3f00, 0x3D00, 0x3E00, 64, 4),
448
    (0x3d00, 0x3e00, 0x3E00, 0x3F00, 64, 4),
449
    (0x3c00, 0x3d00, 0x3F00, 0x4000, 64, 4),
450
    (0x4300, 0x4400, 0x4000, 0x4100, 64, 4),
451
    (0x4200, 0x4300, 0x4100, 0x4200, 64, 4),
452
    (0x4100, 0x4200, 0x4200, 0x4300, 64, 4),
453
    (0x4000, 0x4100, 0x4300, 0x4400, 64, 4),
454
    (0x4700, 0x4760, 0x4400, 0x4460, 32, 3),  # End of Ch Data
455
    (0x4760, 0x4800, 0x4460, 0x4500, 32, 5),  # start of Ch names
456
    (0x4600, 0x4700, 0x4500, 0x4600, 64, 4),
457
    (0x4500, 0x4600, 0x4600, 0x4700, 64, 4),
458
    (0x4400, 0x4500, 0x4700, 0x4800, 64, 4),
459
    (0x4b00, 0x4c00, 0x4800, 0x4900, 64, 4),
460
    (0x4a00, 0x4B00, 0x4900, 0x4A00, 64, 4),
461
    (0x4900, 0x4a00, 0x4A00, 0x4B00, 64, 4),
462
    (0x4800, 0x4900, 0x4B00, 0x4C00, 64, 4),
463
    (0x4f00, 0x5000, 0x4C00, 0x4D00, 64, 4),
464
    (0x4E00, 0x4F00, 0x4D00, 0x4E00, 64, 4),
465
    (0x4D00, 0x4E00, 0x4E00, 0x4F00, 64, 4),
466
    (0x4C00, 0x4d00, 0x4F00, 0x5000, 64, 4),
467
    (0x5300, 0x5400, 0x5000, 0x5100, 64, 4),
468
    (0x5200, 0x5300, 0x5100, 0x5200, 64, 4),
469
    (0x5100, 0x5200, 0x5200, 0x5300, 64, 4),
470
    (0x5000, 0x5100, 0x5300, 0x5400, 64, 4),
471
    (0x5700, 0x5800, 0x5400, 0x5500, 64, 4),
472
    (0x5600, 0x5700, 0x5500, 0x5600, 64, 4),
473
    (0x5500, 0x5600, 0x5600, 0x5700, 64, 4),
474
    (0x5400, 0x5500, 0x5700, 0x5800, 64, 4),
475
    (0x5B00, 0x5C00, 0x5800, 0x5900, 64, 4),
476
    (0x5A00, 0x5B00, 0x5900, 0x5A00, 64, 4),
477
    (0x5900, 0x5A00, 0x5A00, 0x5B00, 64, 4),
478
    (0x5800, 0x5900, 0x5B00, 0x5C00, 64, 4),
479
    (0x5F00, 0x6000, 0x5C00, 0x5D00, 64, 4),
480
    (0x5E00, 0x5F00, 0x5D00, 0x5E00, 64, 4),
481
    (0x5D00, 0x5E00, 0x5E00, 0x5F00, 64, 4),
482
    (0x5C00, 0x5D00, 0x5F00, 0x6000, 64, 4),
483
    (0x6300, 0x6400, 0x6000, 0x6100, 64, 4),
484
    (0x6200, 0x6300, 0x6100, 0x6200, 64, 4),
485
    (0x6100, 0x6200, 0x6200, 0x6300, 64, 4),
486
    (0x6000, 0x6100, 0x6300, 0x6400, 64, 4),
487
    (0x6700, 0x6800, 0x6400, 0x6500, 64, 4),
488
    (0x6600, 0x6700, 0x6500, 0x6600, 64, 4),
489
    (0x6500, 0x6600, 0x6600, 0x6700, 64, 4),
490
    (0x6400, 0x6500, 0x6700, 0x6800, 64, 4),
491
    (0x6b00, 0x6c00, 0x6800, 0x6900, 64, 4),
492
    (0x6a00, 0x6b00, 0x6900, 0x6A00, 64, 4),
493
    (0x6900, 0x6a00, 0x6A00, 0x6B00, 64, 4),
494
    (0x6800, 0x6900, 0x6B00, 0x6C00, 64, 4),
495
    (0x6F00, 0x7000, 0x6C00, 0x6D00, 64, 4),
496
    (0x6e00, 0x6F00, 0x6D00, 0x6E00, 64, 4),
497
    (0x6D00, 0x6E00, 0x6E00, 0x6F00, 64, 4),
498
    (0x6C00, 0x6D00, 0x6F00, 0x7000, 64, 4),
499
    (0x7300, 0x7400, 0x7000, 0x7100, 64, 4),
500
    (0x7200, 0x7300, 0x7100, 0x7200, 64, 4),
501
    (0x7100, 0x7200, 0x7200, 0x7300, 64, 4),
502
    (0x7000, 0x7040, 0x7300, 0x7340, 64, 1),  # End of Ch Names
503
    (0x7040, 0x7100, 0x7340, 0x7400, 64, 3),  # start of ch valid
504
    (0x7700, 0x7800, 0x7400, 0x7500, 64, 4),
505
    (0x7600, 0x7700, 0x7500, 0x7600, 64, 4),
506
    (0x7500, 0x7600, 0x7600, 0x7700, 64, 4),
507
    (0x7400, 0x7440, 0x7700, 0x7740, 64, 1),  # end of ch valid
508
    (0x7440, 0x74e0, 0x7740, 0x77e0, 32, 5),  # scan groups
509
    (0x74e0, 0x74e8, 0x77e0, 0x77e8, 8, 1),  # VFO Scan range
510
    (0x7bB0, 0x7c00, 0x78B0, 0x7900, 16, 5),  # FM presets / Call ID Start
511
    (0x7a00, 0x7b00, 0x7900, 0x7A00, 64, 4),
512
    (0x7900, 0x7a00, 0x7A00, 0x7B00, 64, 4),
513
    (0x7800, 0x7900, 0x7B00, 0x7C00, 64, 4),  # Call ID end / Call Name Start
514
    (0x7f00, 0x8000, 0x7C00, 0x7D00, 64, 4),
515
    (0x7e00, 0x7f00, 0x7D00, 0x7E00, 64, 4),
516
    (0x7d00, 0x7e00, 0x7E00, 0x7F00, 64, 4),
517
    (0x7c00, 0x7d00, 0x7F00, 0x8000, 64, 4),  # Call Name End
518
)
519

    
520
Q10H_upload_map_nolims = (
521
    #  This map serves 2 purposes-
522
    #   To limit the Upload to Radio Writes to known settings only
523
    #   And also to send the rearranged Chirp Memory data back to the radio
524
    #   using the proper radio addresses.
525
    #    Radio   Radio   Chirp   Chirp  Blk  cnt
526
    #    start   end     start   end     sz
527
    # (0x0300, 0x0400, 0x0000, 0x0100, 64, 4),
528
    # (0x0200, 0x0300, 0x0100, 0x0200, 64, 4),
529
    # (0x0100, 0x0200, 0x0200, 0x0300, 64, 4),
530
    (0x030A, 0x030A, 0x000a, 0x000a, 1, 1),  # Unlock
531
    (0x0040, 0x0100, 0x0340, 0x0400, 64, 3),  # settings
532
    (0x0700, 0x0800, 0x0400, 0x0500, 64, 4),  # channel data
533
    (0x0600, 0x0700, 0x0500, 0x0600, 64, 4),
534
    (0x0500, 0x0600, 0x0600, 0x0700, 64, 4),
535
    (0x0400, 0x0500, 0x0700, 0x0800, 64, 4),
536
    (0x0b00, 0x0c00, 0x0800, 0x0900, 64, 4),
537
    (0x0a00, 0x0b00, 0x0900, 0x0A00, 64, 4),
538
    (0x0900, 0x0a00, 0x0A00, 0x0B00, 64, 4),
539
    (0x0800, 0x0900, 0x0B00, 0x0C00, 64, 4),
540
    (0x0f00, 0x1000, 0x0C00, 0x0D00, 64, 4),
541
    (0x0e00, 0x0f00, 0x0D00, 0x0E00, 64, 4),
542
    (0x0d00, 0x0e00, 0x0E00, 0x0F00, 64, 4),
543
    (0x0c00, 0x0d00, 0x0F00, 0x1000, 64, 4),
544
    (0x1300, 0x1400, 0x1000, 0x1100, 64, 4),
545
    (0x1200, 0x1300, 0x1100, 0x1200, 64, 4),
546
    (0x1100, 0x1200, 0x1200, 0x1300, 64, 4),
547
    (0x1000, 0x1100, 0x1300, 0x1400, 64, 4),
548
    (0x1700, 0x1800, 0x1400, 0x1500, 64, 4),
549
    (0x1600, 0x1700, 0x1500, 0x1600, 64, 4),
550
    (0x1500, 0x1600, 0x1600, 0x1700, 64, 4),
551
    (0x1400, 0x1500, 0x1700, 0x1800, 64, 4),
552
    (0x1B00, 0x1c00, 0x1800, 0x1900, 64, 4),
553
    (0x1a00, 0x1b00, 0x1900, 0x1A00, 64, 4),
554
    (0x1900, 0x1a00, 0x1A00, 0x1B00, 64, 4),
555
    (0x1800, 0x1900, 0x1B00, 0x1C00, 64, 4),
556
    (0x1f00, 0x2000, 0x1C00, 0x1D00, 64, 4),
557
    (0x1e00, 0x1f00, 0x1D00, 0x1E00, 64, 4),
558
    (0x1d00, 0x1e00, 0x1E00, 0x1F00, 64, 4),
559
    (0x1c00, 0x1d00, 0x1F00, 0x2000, 64, 4),
560
    (0x2300, 0x2400, 0x2000, 0x2100, 64, 4),
561
    (0x2200, 0x2300, 0x2100, 0x2200, 64, 4),
562
    (0x2100, 0x2200, 0x2200, 0x2300, 64, 4),
563
    (0x2000, 0x2100, 0x2300, 0x2400, 64, 4),
564
    (0x2700, 0x2800, 0x2400, 0x2500, 64, 4),
565
    (0x2600, 0x2700, 0x2500, 0x2600, 64, 4),
566
    (0x2500, 0x2600, 0x2600, 0x2700, 64, 4),
567
    (0x2400, 0x2500, 0x2700, 0x2800, 64, 4),
568
    (0x2B00, 0x2C00, 0x2800, 0x2900, 64, 4),
569
    (0x2a00, 0x2b00, 0x2900, 0x2A00, 64, 4),
570
    (0x2900, 0x2a00, 0x2A00, 0x2B00, 64, 4),
571
    (0x2800, 0x2900, 0x2B00, 0x2C00, 64, 4),
572
    (0x2f00, 0x3000, 0x2C00, 0x2D00, 64, 4),
573
    (0x2e00, 0x2f00, 0x2D00, 0x2E00, 64, 4),
574
    (0x2d00, 0x2e00, 0x2E00, 0x2F00, 64, 4),
575
    (0x2c00, 0x2d00, 0x2F00, 0x3000, 64, 4),
576
    (0x3300, 0x3400, 0x3000, 0x3100, 64, 4),
577
    (0x3200, 0x3300, 0x3100, 0x3200, 64, 4),
578
    (0x3100, 0x3200, 0x3200, 0x3300, 64, 4),
579
    (0x3000, 0x3100, 0x3300, 0x3400, 64, 4),
580
    (0x3700, 0x3800, 0x3400, 0x3500, 64, 4),
581
    (0x3600, 0x3700, 0x3500, 0x3600, 64, 4),
582
    (0x3500, 0x3600, 0x3600, 0x3700, 64, 4),
583
    (0x3400, 0x3500, 0x3700, 0x3800, 64, 4),
584
    (0x3B00, 0x3C00, 0x3800, 0x3900, 64, 4),
585
    (0x3a00, 0x3b00, 0x3900, 0x3A00, 64, 4),
586
    (0x3900, 0x3a00, 0x3A00, 0x3B00, 64, 4),
587
    (0x3800, 0x3900, 0x3B00, 0x3C00, 64, 4),
588
    (0x3f00, 0x4000, 0x3C00, 0x3D00, 64, 4),
589
    (0x3e00, 0x3f00, 0x3D00, 0x3E00, 64, 4),
590
    (0x3d00, 0x3e00, 0x3E00, 0x3F00, 64, 4),
591
    (0x3c00, 0x3d00, 0x3F00, 0x4000, 64, 4),
592
    (0x4300, 0x4400, 0x4000, 0x4100, 64, 4),
593
    (0x4200, 0x4300, 0x4100, 0x4200, 64, 4),
594
    (0x4100, 0x4200, 0x4200, 0x4300, 64, 4),
595
    (0x4000, 0x4100, 0x4300, 0x4400, 64, 4),
596
    (0x4700, 0x4760, 0x4400, 0x4460, 32, 3),  # End of Ch Data
597
    (0x4760, 0x4800, 0x4460, 0x4500, 32, 5),  # start of Ch names
598
    (0x4600, 0x4700, 0x4500, 0x4600, 64, 4),
599
    (0x4500, 0x4600, 0x4600, 0x4700, 64, 4),
600
    (0x4400, 0x4500, 0x4700, 0x4800, 64, 4),
601
    (0x4b00, 0x4c00, 0x4800, 0x4900, 64, 4),
602
    (0x4a00, 0x4B00, 0x4900, 0x4A00, 64, 4),
603
    (0x4900, 0x4a00, 0x4A00, 0x4B00, 64, 4),
604
    (0x4800, 0x4900, 0x4B00, 0x4C00, 64, 4),
605
    (0x4f00, 0x5000, 0x4C00, 0x4D00, 64, 4),
606
    (0x4E00, 0x4F00, 0x4D00, 0x4E00, 64, 4),
607
    (0x4D00, 0x4E00, 0x4E00, 0x4F00, 64, 4),
608
    (0x4C00, 0x4d00, 0x4F00, 0x5000, 64, 4),
609
    (0x5300, 0x5400, 0x5000, 0x5100, 64, 4),
610
    (0x5200, 0x5300, 0x5100, 0x5200, 64, 4),
611
    (0x5100, 0x5200, 0x5200, 0x5300, 64, 4),
612
    (0x5000, 0x5100, 0x5300, 0x5400, 64, 4),
613
    (0x5700, 0x5800, 0x5400, 0x5500, 64, 4),
614
    (0x5600, 0x5700, 0x5500, 0x5600, 64, 4),
615
    (0x5500, 0x5600, 0x5600, 0x5700, 64, 4),
616
    (0x5400, 0x5500, 0x5700, 0x5800, 64, 4),
617
    (0x5B00, 0x5C00, 0x5800, 0x5900, 64, 4),
618
    (0x5A00, 0x5B00, 0x5900, 0x5A00, 64, 4),
619
    (0x5900, 0x5A00, 0x5A00, 0x5B00, 64, 4),
620
    (0x5800, 0x5900, 0x5B00, 0x5C00, 64, 4),
621
    (0x5F00, 0x6000, 0x5C00, 0x5D00, 64, 4),
622
    (0x5E00, 0x5F00, 0x5D00, 0x5E00, 64, 4),
623
    (0x5D00, 0x5E00, 0x5E00, 0x5F00, 64, 4),
624
    (0x5C00, 0x5D00, 0x5F00, 0x6000, 64, 4),
625
    (0x6300, 0x6400, 0x6000, 0x6100, 64, 4),
626
    (0x6200, 0x6300, 0x6100, 0x6200, 64, 4),
627
    (0x6100, 0x6200, 0x6200, 0x6300, 64, 4),
628
    (0x6000, 0x6100, 0x6300, 0x6400, 64, 4),
629
    (0x6700, 0x6800, 0x6400, 0x6500, 64, 4),
630
    (0x6600, 0x6700, 0x6500, 0x6600, 64, 4),
631
    (0x6500, 0x6600, 0x6600, 0x6700, 64, 4),
632
    (0x6400, 0x6500, 0x6700, 0x6800, 64, 4),
633
    (0x6b00, 0x6c00, 0x6800, 0x6900, 64, 4),
634
    (0x6a00, 0x6b00, 0x6900, 0x6A00, 64, 4),
635
    (0x6900, 0x6a00, 0x6A00, 0x6B00, 64, 4),
636
    (0x6800, 0x6900, 0x6B00, 0x6C00, 64, 4),
637
    (0x6F00, 0x7000, 0x6C00, 0x6D00, 64, 4),
638
    (0x6e00, 0x6F00, 0x6D00, 0x6E00, 64, 4),
639
    (0x6D00, 0x6E00, 0x6E00, 0x6F00, 64, 4),
640
    (0x6C00, 0x6D00, 0x6F00, 0x7000, 64, 4),
641
    (0x7300, 0x7400, 0x7000, 0x7100, 64, 4),
642
    (0x7200, 0x7300, 0x7100, 0x7200, 64, 4),
643
    (0x7100, 0x7200, 0x7200, 0x7300, 64, 4),
644
    (0x7000, 0x7040, 0x7300, 0x7340, 64, 1),  # End of Ch Names
645
    (0x7040, 0x7100, 0x7340, 0x7400, 64, 3),  # start of ch valid
646
    (0x7700, 0x7800, 0x7400, 0x7500, 64, 4),
647
    (0x7600, 0x7700, 0x7500, 0x7600, 64, 4),
648
    (0x7500, 0x7600, 0x7600, 0x7700, 64, 4),
649
    (0x7400, 0x7440, 0x7700, 0x7740, 64, 1),  # end of ch valid
650
    (0x7440, 0x74e0, 0x7740, 0x77e0, 32, 5),  # scan groups
651
    (0x74e0, 0x74e8, 0x77e0, 0x77e8, 8, 1),  # VFO Scan range
652
    (0x7bB0, 0x7c00, 0x78B0, 0x7900, 16, 5),  # FM presets / Call ID Start
653
    (0x7a00, 0x7b00, 0x7900, 0x7A00, 64, 4),
654
    (0x7900, 0x7a00, 0x7A00, 0x7B00, 64, 4),
655
    (0x7800, 0x7900, 0x7B00, 0x7C00, 64, 4),  # Call ID end / Call Name Start
656
    (0x7f00, 0x8000, 0x7C00, 0x7D00, 64, 4),
657
    (0x7e00, 0x7f00, 0x7D00, 0x7E00, 64, 4),
658
    (0x7d00, 0x7e00, 0x7E00, 0x7F00, 64, 4),
659
    (0x7c00, 0x7d00, 0x7F00, 0x8000, 64, 4),  # Call Name End
660
)
661

    
662
Q10G_upload_map_nolims = (
663
    #  This map serves 2 purposes-
664
    #   To limit the Upload to Radio Writes to known settings only
665
    #   And also to send the rearranged Chirp Memory data back to the radio
666
    #   using the proper radio addresses.
667
    #    Radio   Radio   Chirp   Chirp  Blk  cnt
668
    #    start   end     start   end     sz
669
    # (0x0300, 0x0400, 0x0000, 0x0100, 64, 4),
670
    # (0x0200, 0x0300, 0x0100, 0x0200, 64, 4),
671
    # (0x0100, 0x0200, 0x0200, 0x0300, 64, 4),
672
    # (0x030A, 0x030A, 0x000a, 0x000a, 1, 1), # Unlock
673
    (0x0040, 0x0100, 0x0340, 0x0400, 64, 3),  # settings
674
    (0x0700, 0x0800, 0x0400, 0x0500, 64, 4),  # channel data
675
    (0x0600, 0x0700, 0x0500, 0x0600, 64, 4),
676
    (0x0500, 0x0600, 0x0600, 0x0700, 64, 4),
677
    (0x0400, 0x0500, 0x0700, 0x0800, 64, 4),
678
    (0x0b00, 0x0c00, 0x0800, 0x0900, 64, 4),
679
    (0x0a00, 0x0b00, 0x0900, 0x0A00, 64, 4),
680
    (0x0900, 0x0a00, 0x0A00, 0x0B00, 64, 4),
681
    (0x0800, 0x0900, 0x0B00, 0x0C00, 64, 4),
682
    (0x0f00, 0x1000, 0x0C00, 0x0D00, 64, 4),
683
    (0x0e00, 0x0f00, 0x0D00, 0x0E00, 64, 4),
684
    (0x0d00, 0x0e00, 0x0E00, 0x0F00, 64, 4),
685
    (0x0c00, 0x0d00, 0x0F00, 0x1000, 64, 4),
686
    (0x1300, 0x1400, 0x1000, 0x1100, 64, 4),
687
    (0x1200, 0x1300, 0x1100, 0x1200, 64, 4),
688
    (0x1100, 0x1200, 0x1200, 0x1300, 64, 4),
689
    (0x1000, 0x1100, 0x1300, 0x1400, 64, 4),
690
    (0x1700, 0x1800, 0x1400, 0x1500, 64, 4),
691
    (0x1600, 0x1700, 0x1500, 0x1600, 64, 4),
692
    (0x1500, 0x1600, 0x1600, 0x1700, 64, 4),
693
    (0x1400, 0x1500, 0x1700, 0x1800, 64, 4),
694
    (0x1B00, 0x1c00, 0x1800, 0x1900, 64, 4),
695
    (0x1a00, 0x1b00, 0x1900, 0x1A00, 64, 4),
696
    (0x1900, 0x1a00, 0x1A00, 0x1B00, 64, 4),
697
    (0x1800, 0x1900, 0x1B00, 0x1C00, 64, 4),
698
    (0x1f00, 0x2000, 0x1C00, 0x1D00, 64, 4),
699
    (0x1e00, 0x1f00, 0x1D00, 0x1E00, 64, 4),
700
    (0x1d00, 0x1e00, 0x1E00, 0x1F00, 64, 4),
701
    (0x1c00, 0x1d00, 0x1F00, 0x2000, 64, 4),
702
    (0x2300, 0x2400, 0x2000, 0x2100, 64, 4),
703
    (0x2200, 0x2300, 0x2100, 0x2200, 64, 4),
704
    (0x2100, 0x2200, 0x2200, 0x2300, 64, 4),
705
    (0x2000, 0x2100, 0x2300, 0x2400, 64, 4),
706
    (0x2700, 0x2800, 0x2400, 0x2500, 64, 4),
707
    (0x2600, 0x2700, 0x2500, 0x2600, 64, 4),
708
    (0x2500, 0x2600, 0x2600, 0x2700, 64, 4),
709
    (0x2400, 0x2500, 0x2700, 0x2800, 64, 4),
710
    (0x2B00, 0x2C00, 0x2800, 0x2900, 64, 4),
711
    (0x2a00, 0x2b00, 0x2900, 0x2A00, 64, 4),
712
    (0x2900, 0x2a00, 0x2A00, 0x2B00, 64, 4),
713
    (0x2800, 0x2900, 0x2B00, 0x2C00, 64, 4),
714
    (0x2f00, 0x3000, 0x2C00, 0x2D00, 64, 4),
715
    (0x2e00, 0x2f00, 0x2D00, 0x2E00, 64, 4),
716
    (0x2d00, 0x2e00, 0x2E00, 0x2F00, 64, 4),
717
    (0x2c00, 0x2d00, 0x2F00, 0x3000, 64, 4),
718
    (0x3300, 0x3400, 0x3000, 0x3100, 64, 4),
719
    (0x3200, 0x3300, 0x3100, 0x3200, 64, 4),
720
    (0x3100, 0x3200, 0x3200, 0x3300, 64, 4),
721
    (0x3000, 0x3100, 0x3300, 0x3400, 64, 4),
722
    (0x3700, 0x3800, 0x3400, 0x3500, 64, 4),
723
    (0x3600, 0x3700, 0x3500, 0x3600, 64, 4),
724
    (0x3500, 0x3600, 0x3600, 0x3700, 64, 4),
725
    (0x3400, 0x3500, 0x3700, 0x3800, 64, 4),
726
    (0x3B00, 0x3C00, 0x3800, 0x3900, 64, 4),
727
    (0x3a00, 0x3b00, 0x3900, 0x3A00, 64, 4),
728
    (0x3900, 0x3a00, 0x3A00, 0x3B00, 64, 4),
729
    (0x3800, 0x3900, 0x3B00, 0x3C00, 64, 4),
730
    (0x3f00, 0x4000, 0x3C00, 0x3D00, 64, 4),
731
    (0x3e00, 0x3f00, 0x3D00, 0x3E00, 64, 4),
732
    (0x3d00, 0x3e00, 0x3E00, 0x3F00, 64, 4),
733
    (0x3c00, 0x3d00, 0x3F00, 0x4000, 64, 4),
734
    (0x4300, 0x4400, 0x4000, 0x4100, 64, 4),
735
    (0x4200, 0x4300, 0x4100, 0x4200, 64, 4),
736
    (0x4100, 0x4200, 0x4200, 0x4300, 64, 4),
737
    (0x4000, 0x4100, 0x4300, 0x4400, 64, 4),
738
    (0x4700, 0x4760, 0x4400, 0x4460, 32, 3),  # End of Ch Data
739
    (0x4760, 0x4800, 0x4460, 0x4500, 32, 5),  # start of Ch names
740
    (0x4600, 0x4700, 0x4500, 0x4600, 64, 4),
741
    (0x4500, 0x4600, 0x4600, 0x4700, 64, 4),
742
    (0x4400, 0x4500, 0x4700, 0x4800, 64, 4),
743
    (0x4b00, 0x4c00, 0x4800, 0x4900, 64, 4),
744
    (0x4a00, 0x4B00, 0x4900, 0x4A00, 64, 4),
745
    (0x4900, 0x4a00, 0x4A00, 0x4B00, 64, 4),
746
    (0x4800, 0x4900, 0x4B00, 0x4C00, 64, 4),
747
    (0x4f00, 0x5000, 0x4C00, 0x4D00, 64, 4),
748
    (0x4E00, 0x4F00, 0x4D00, 0x4E00, 64, 4),
749
    (0x4D00, 0x4E00, 0x4E00, 0x4F00, 64, 4),
750
    (0x4C00, 0x4d00, 0x4F00, 0x5000, 64, 4),
751
    (0x5300, 0x5400, 0x5000, 0x5100, 64, 4),
752
    (0x5200, 0x5300, 0x5100, 0x5200, 64, 4),
753
    (0x5100, 0x5200, 0x5200, 0x5300, 64, 4),
754
    (0x5000, 0x5100, 0x5300, 0x5400, 64, 4),
755
    (0x5700, 0x5800, 0x5400, 0x5500, 64, 4),
756
    (0x5600, 0x5700, 0x5500, 0x5600, 64, 4),
757
    (0x5500, 0x5600, 0x5600, 0x5700, 64, 4),
758
    (0x5400, 0x5500, 0x5700, 0x5800, 64, 4),
759
    (0x5B00, 0x5C00, 0x5800, 0x5900, 64, 4),
760
    (0x5A00, 0x5B00, 0x5900, 0x5A00, 64, 4),
761
    (0x5900, 0x5A00, 0x5A00, 0x5B00, 64, 4),
762
    (0x5800, 0x5900, 0x5B00, 0x5C00, 64, 4),
763
    (0x5F00, 0x6000, 0x5C00, 0x5D00, 64, 4),
764
    (0x5E00, 0x5F00, 0x5D00, 0x5E00, 64, 4),
765
    (0x5D00, 0x5E00, 0x5E00, 0x5F00, 64, 4),
766
    (0x5C00, 0x5D00, 0x5F00, 0x6000, 64, 4),
767
    (0x6300, 0x6400, 0x6000, 0x6100, 64, 4),
768
    (0x6200, 0x6300, 0x6100, 0x6200, 64, 4),
769
    (0x6100, 0x6200, 0x6200, 0x6300, 64, 4),
770
    (0x6000, 0x6100, 0x6300, 0x6400, 64, 4),
771
    (0x6700, 0x6800, 0x6400, 0x6500, 64, 4),
772
    (0x6600, 0x6700, 0x6500, 0x6600, 64, 4),
773
    (0x6500, 0x6600, 0x6600, 0x6700, 64, 4),
774
    (0x6400, 0x6500, 0x6700, 0x6800, 64, 4),
775
    (0x6b00, 0x6c00, 0x6800, 0x6900, 64, 4),
776
    (0x6a00, 0x6b00, 0x6900, 0x6A00, 64, 4),
777
    (0x6900, 0x6a00, 0x6A00, 0x6B00, 64, 4),
778
    (0x6800, 0x6900, 0x6B00, 0x6C00, 64, 4),
779
    (0x6F00, 0x7000, 0x6C00, 0x6D00, 64, 4),
780
    (0x6e00, 0x6F00, 0x6D00, 0x6E00, 64, 4),
781
    (0x6D00, 0x6E00, 0x6E00, 0x6F00, 64, 4),
782
    (0x6C00, 0x6D00, 0x6F00, 0x7000, 64, 4),
783
    (0x7300, 0x7400, 0x7000, 0x7100, 64, 4),
784
    (0x7200, 0x7300, 0x7100, 0x7200, 64, 4),
785
    (0x7100, 0x7200, 0x7200, 0x7300, 64, 4),
786
    (0x7000, 0x7040, 0x7300, 0x7340, 64, 1),  # End of Ch Names
787
    (0x7040, 0x7100, 0x7340, 0x7400, 64, 3),  # start of ch valid
788
    (0x7700, 0x7800, 0x7400, 0x7500, 64, 4),
789
    (0x7600, 0x7700, 0x7500, 0x7600, 64, 4),
790
    (0x7500, 0x7600, 0x7600, 0x7700, 64, 4),
791
    (0x7400, 0x7440, 0x7700, 0x7740, 64, 1),  # end of ch valid
792
    (0x7440, 0x74e0, 0x7740, 0x77e0, 32, 5),  # scan groups
793
    (0x74e0, 0x74e8, 0x77e0, 0x77e8, 8, 1),  # VFO Scan range
794
    (0x7bB0, 0x7c00, 0x78B0, 0x7900, 16, 5),  # FM presets / Call ID Start
795
    (0x7a00, 0x7b00, 0x7900, 0x7A00, 64, 4),
796
    (0x7900, 0x7a00, 0x7A00, 0x7B00, 64, 4),
797
    (0x7800, 0x7900, 0x7B00, 0x7C00, 64, 4),  # Call ID end / Call Name Start
798
    (0x7f00, 0x8000, 0x7C00, 0x7D00, 64, 4),
799
    (0x7e00, 0x7f00, 0x7D00, 0x7E00, 64, 4),
800
    (0x7d00, 0x7e00, 0x7E00, 0x7F00, 64, 4),
801
    (0x7c00, 0x7d00, 0x7F00, 0x8000, 64, 4),  # Call Name End
802
)
803

    
804

    
805
Q10H_upload_map_OLD = (
806
    #   OLD MAP before rearranging 0-400 - EVENTUALLY DELETE
807
    #   This map serves 2 purposes-
808
    #   To limit the Upload to Radio Writes to known settings only
809
    #   And also to send the rearranged Chirp Memory data back to the radio
810
    #   using the proper radio addresses.
811
    #    Radio   Radio   Chirp   Chirp  Blk  cnt
812
    #    start   end     start   end     sz
813
    # (0x0000, 0x0400, 0x0000, 0x0400, 64, 16),
814
    # (0x0600, 0x06E0, 0x0400, 0x04E0, 32, 7),
815
    (0x0002, 0x0022, 0x0002, 0x0022, 32, 1),  # Tx Limits
816
    (0x00a6, 0x00fe, 0x00a6, 0x00fe,  8, 11),  # Rx Limits
817
    (0x030a, 0x030a, 0x030a, 0x030a,  1, 1),  # Factory Locked Mode
818
    (0x0640, 0x06c0, 0x0440, 0x04c0, 32, 7),  # VFO settings
819
    (0x0700, 0x0800, 0x04E0, 0x05E0, 64, 4),  # settings
820
    (0x06E0, 0x0700, 0x05E0, 0x0600, 32, 1),  # channel 1 data start
821
    (0x0500, 0x0600, 0x0600, 0x0700, 64, 4),
822
    (0x0400, 0x0500, 0x0700, 0x0800, 64, 4),
823
    (0x0b00, 0x0c00, 0x0800, 0x0900, 64, 4),
824
    (0x0a00, 0x0b00, 0x0900, 0x0A00, 64, 4),
825
    (0x0900, 0x0a00, 0x0A00, 0x0B00, 64, 4),
826
    (0x0800, 0x0900, 0x0B00, 0x0C00, 64, 4),
827
    (0x0f00, 0x1000, 0x0C00, 0x0D00, 64, 4),
828
    (0x0e00, 0x0f00, 0x0D00, 0x0E00, 64, 4),
829
    (0x0d00, 0x0e00, 0x0E00, 0x0F00, 64, 4),
830
    (0x0c00, 0x0d00, 0x0F00, 0x1000, 64, 4),
831
    (0x1300, 0x1400, 0x1000, 0x1100, 64, 4),
832
    (0x1200, 0x1300, 0x1100, 0x1200, 64, 4),
833
    (0x1100, 0x1200, 0x1200, 0x1300, 64, 4),
834
    (0x1000, 0x1100, 0x1300, 0x1400, 64, 4),
835
    (0x1700, 0x1800, 0x1400, 0x1500, 64, 4),
836
    (0x1600, 0x1700, 0x1500, 0x1600, 64, 4),
837
    (0x1500, 0x1600, 0x1600, 0x1700, 64, 4),
838
    (0x1400, 0x1500, 0x1700, 0x1800, 64, 4),
839
    (0x1B00, 0x1c00, 0x1800, 0x1900, 64, 4),
840
    (0x1a00, 0x1b00, 0x1900, 0x1A00, 64, 4),
841
    (0x1900, 0x1a00, 0x1A00, 0x1B00, 64, 4),
842
    (0x1800, 0x1900, 0x1B00, 0x1C00, 64, 4),
843
    (0x1f00, 0x2000, 0x1C00, 0x1D00, 64, 4),
844
    (0x1e00, 0x1f00, 0x1D00, 0x1E00, 64, 4),
845
    (0x1d00, 0x1e00, 0x1E00, 0x1F00, 64, 4),
846
    (0x1c00, 0x1d00, 0x1F00, 0x2000, 64, 4),
847
    (0x2300, 0x2400, 0x2000, 0x2100, 64, 4),
848
    (0x2200, 0x2300, 0x2100, 0x2200, 64, 4),
849
    (0x2100, 0x2200, 0x2200, 0x2300, 64, 4),
850
    (0x2000, 0x2100, 0x2300, 0x2400, 64, 4),
851
    (0x2700, 0x2800, 0x2400, 0x2500, 64, 4),
852
    (0x2600, 0x2700, 0x2500, 0x2600, 64, 4),
853
    (0x2500, 0x2600, 0x2600, 0x2700, 64, 4),
854
    (0x2400, 0x2500, 0x2700, 0x2800, 64, 4),
855
    (0x2B00, 0x2C00, 0x2800, 0x2900, 64, 4),
856
    (0x2a00, 0x2b00, 0x2900, 0x2A00, 64, 4),
857
    (0x2900, 0x2a00, 0x2A00, 0x2B00, 64, 4),
858
    (0x2800, 0x2900, 0x2B00, 0x2C00, 64, 4),
859
    (0x2f00, 0x3000, 0x2C00, 0x2D00, 64, 4),
860
    (0x2e00, 0x2f00, 0x2D00, 0x2E00, 64, 4),
861
    (0x2d00, 0x2e00, 0x2E00, 0x2F00, 64, 4),
862
    (0x2c00, 0x2d00, 0x2F00, 0x3000, 64, 4),
863
    (0x3300, 0x3400, 0x3000, 0x3100, 64, 4),
864
    (0x3200, 0x3300, 0x3100, 0x3200, 64, 4),
865
    (0x3100, 0x3200, 0x3200, 0x3300, 64, 4),
866
    (0x3000, 0x3100, 0x3300, 0x3400, 64, 4),
867
    (0x3700, 0x3800, 0x3400, 0x3500, 64, 4),
868
    (0x3600, 0x3700, 0x3500, 0x3600, 64, 4),
869
    (0x3500, 0x3600, 0x3600, 0x3700, 64, 4),
870
    (0x3400, 0x3500, 0x3700, 0x3800, 64, 4),
871
    (0x3B00, 0x3C00, 0x3800, 0x3900, 64, 4),
872
    (0x3a00, 0x3b00, 0x3900, 0x3A00, 64, 4),
873
    (0x3900, 0x3a00, 0x3A00, 0x3B00, 64, 4),
874
    (0x3800, 0x3900, 0x3B00, 0x3C00, 64, 4),
875
    (0x3f00, 0x4000, 0x3C00, 0x3D00, 64, 4),
876
    (0x3e00, 0x3f00, 0x3D00, 0x3E00, 64, 4),
877
    (0x3d00, 0x3e00, 0x3E00, 0x3F00, 64, 4),
878
    (0x3c00, 0x3d00, 0x3F00, 0x4000, 64, 4),
879
    (0x4300, 0x4400, 0x4000, 0x4100, 64, 4),
880
    (0x4200, 0x4300, 0x4100, 0x4200, 64, 4),
881
    (0x4100, 0x4200, 0x4200, 0x4300, 64, 4),
882
    (0x4000, 0x4100, 0x4300, 0x4400, 64, 4),
883
    (0x4700, 0x4760, 0x4400, 0x4460, 32, 3),  # End of Ch Data
884
    (0x4760, 0x4800, 0x4460, 0x4500, 32, 5),  # start of Ch names
885
    (0x4600, 0x4700, 0x4500, 0x4600, 64, 4),
886
    (0x4500, 0x4600, 0x4600, 0x4700, 64, 4),
887
    (0x4400, 0x4500, 0x4700, 0x4800, 64, 4),
888
    (0x4b00, 0x4c00, 0x4800, 0x4900, 64, 4),
889
    (0x4a00, 0x4B00, 0x4900, 0x4A00, 64, 4),
890
    (0x4900, 0x4a00, 0x4A00, 0x4B00, 64, 4),
891
    (0x4800, 0x4900, 0x4B00, 0x4C00, 64, 4),
892
    (0x4f00, 0x5000, 0x4C00, 0x4D00, 64, 4),
893
    (0x4E00, 0x4F00, 0x4D00, 0x4E00, 64, 4),
894
    (0x4D00, 0x4E00, 0x4E00, 0x4F00, 64, 4),
895
    (0x4C00, 0x4d00, 0x4F00, 0x5000, 64, 4),
896
    (0x5300, 0x5400, 0x5000, 0x5100, 64, 4),
897
    (0x5200, 0x5300, 0x5100, 0x5200, 64, 4),
898
    (0x5100, 0x5200, 0x5200, 0x5300, 64, 4),
899
    (0x5000, 0x5100, 0x5300, 0x5400, 64, 4),
900
    (0x5700, 0x5800, 0x5400, 0x5500, 64, 4),
901
    (0x5600, 0x5700, 0x5500, 0x5600, 64, 4),
902
    (0x5500, 0x5600, 0x5600, 0x5700, 64, 4),
903
    (0x5400, 0x5500, 0x5700, 0x5800, 64, 4),
904
    (0x5B00, 0x5C00, 0x5800, 0x5900, 64, 4),
905
    (0x5A00, 0x5B00, 0x5900, 0x5A00, 64, 4),
906
    (0x5900, 0x5A00, 0x5A00, 0x5B00, 64, 4),
907
    (0x5800, 0x5900, 0x5B00, 0x5C00, 64, 4),
908
    (0x5F00, 0x6000, 0x5C00, 0x5D00, 64, 4),
909
    (0x5E00, 0x5F00, 0x5D00, 0x5E00, 64, 4),
910
    (0x5D00, 0x5E00, 0x5E00, 0x5F00, 64, 4),
911
    (0x5C00, 0x5D00, 0x5F00, 0x6000, 64, 4),
912
    (0x6300, 0x6400, 0x6000, 0x6100, 64, 4),
913
    (0x6200, 0x6300, 0x6100, 0x6200, 64, 4),
914
    (0x6100, 0x6200, 0x6200, 0x6300, 64, 4),
915
    (0x6000, 0x6100, 0x6300, 0x6400, 64, 4),
916
    (0x6700, 0x6800, 0x6400, 0x6500, 64, 4),
917
    (0x6600, 0x6700, 0x6500, 0x6600, 64, 4),
918
    (0x6500, 0x6600, 0x6600, 0x6700, 64, 4),
919
    (0x6400, 0x6500, 0x6700, 0x6800, 64, 4),
920
    (0x6b00, 0x6c00, 0x6800, 0x6900, 64, 4),
921
    (0x6a00, 0x6b00, 0x6900, 0x6A00, 64, 4),
922
    (0x6900, 0x6a00, 0x6A00, 0x6B00, 64, 4),
923
    (0x6800, 0x6900, 0x6B00, 0x6C00, 64, 4),
924
    (0x6F00, 0x7000, 0x6C00, 0x6D00, 64, 4),
925
    (0x6e00, 0x6F00, 0x6D00, 0x6E00, 64, 4),
926
    (0x6D00, 0x6E00, 0x6E00, 0x6F00, 64, 4),
927
    (0x6C00, 0x6D00, 0x6F00, 0x7000, 64, 4),
928
    (0x7300, 0x7400, 0x7000, 0x7100, 64, 4),
929
    (0x7200, 0x7300, 0x7100, 0x7200, 64, 4),
930
    (0x7100, 0x7200, 0x7200, 0x7300, 64, 4),
931
    (0x7000, 0x7040, 0x7300, 0x7340, 64, 1),  # End of Ch Names
932
    (0x7040, 0x7100, 0x7340, 0x7400, 64, 3),  # start of ch valid
933
    (0x7700, 0x7800, 0x7400, 0x7500, 64, 4),
934
    (0x7600, 0x7700, 0x7500, 0x7600, 64, 4),
935
    (0x7500, 0x7600, 0x7600, 0x7700, 64, 4),
936
    (0x7400, 0x7440, 0x7700, 0x7740, 64, 1),  # end of ch valid
937
    # (0x7440, 0x7500, 0x7740, 0x7800, 64, 3),
938
    (0x7440, 0x74e0, 0x7740, 0x77e0, 32, 5),  # scan groups
939
    (0x74e0, 0x74e8, 0x77e0, 0x77e8, 8, 1),  # VFO Scan range
940
    # (0x7800, 0x8000, 0x7800, 0x8000, 64, 32),
941
    (0x7bB0, 0x7c00, 0x78B0, 0x7900, 16, 5),  # FM presets / Call ID Start
942
    (0x7a00, 0x7b00, 0x7900, 0x7A00, 64, 4),
943
    (0x7900, 0x7a00, 0x7A00, 0x7B00, 64, 4),
944
    (0x7800, 0x7900, 0x7B00, 0x7C00, 64, 4),  # Call ID end / Call Name Start
945
    (0x7f00, 0x8000, 0x7C00, 0x7D00, 64, 4),
946
    (0x7e00, 0x7f00, 0x7D00, 0x7E00, 64, 4),
947
    (0x7d00, 0x7e00, 0x7E00, 0x7F00, 64, 4),
948
    (0x7c00, 0x7d00, 0x7F00, 0x8000, 64, 4),  # Call Name End
949
    # (0x7bb0, 0x7bf0, 0x7bb0, 0x7bf0, 16, 3) # FM Radio Presets
950
)
951

    
952
# This map contains 4 values
953
# 1st entry is Physical Address that radio Uses for data
954
# 2nd entry is block size to write
955
# 3rd entry is number of blocks to write
956
# 4th entry is the memory address Chirp is using for data
957
# Essentially, the Q10H does not store channel memory infomation in contiguous
958
# blocks
959
# so the driver reads the data in a specific address order to allow Chirp to
960
# have the data in a contiguous data address range.   This TABLE reverses the
961
# contiguous to the non-contiguous addressing that the radio is using.
962
# Bad Wouxun - this is just obfuscation to try and thwart 3rd party
963
# programmers
964

    
965
Q10H_upload_mapfull = (
966
    # - Use for full radio address order upload testing
967
    (0x0000, 0x8000, 0x0000, 0x8000, 64, 512),
968
    )
969

    
970
AB_LIST = ["A", "B"]
971
STEPS = [2.5, 5.0, 6.25, 8.33, 10.0, 12.5, 25.0, 50.0, 100.0]
972
STEP_LIST = [str(x) + "k" for x in STEPS]
973
STEPS2 = [2.5, 5.0, 6.25, 8.33, 10.0, 12.5, 20.0, 25.0, 50.0, 100.0]
974
STEP2_LIST = [str(x) + "k" for x in STEPS2]
975
ROGER_LIST = ["OFF", "Begin", "End", "Both"]
976
TIMEOUT_LIST = ["OFF"] + [str(x) + "s" for x in range(15, 901, 15)]
977
BANDWIDTH_LIST = ["Narrow", "Wide"]
978
SCANMODE_LIST = ["TO", "CO", "SE"]
979
# PFKEYLONG_LIST = ["undef", "FRQ2-PTT", "Selec Call", "Scan", "Flashlight",
980
#                   "Alarm", "SOS", "FM Radio", "Moni", "Strobe", "Weather",
981
#                   "Tlk A", "Reverse", "CTC Scan", "DCS Scan", "BRT"]
982
# PFKEYSHORT_LIST = ["undef", "Scan", "Flashlight", "Alarm", "SOS", "FM Radio",
983
#                    "Moni", "Strobe", "Weather", "Tlk A", "Reverse",
984
#                    "CTC Scan", "DCS Scan", "BRT"]
985

    
986
# PFKEYLONG_LIST = ["undef", "FRQ2-PTT", "Selec Call", "Favorite",
987
#                            "Bright+", "Scan", "Flashlight", "Alarm", "SOS",
988
#                            "FM Radio", "Moni", "Strobe", "Weather", "Tlk A",
989
#                            "Reverse", "CTC Scan", "DCS Scan", "Backlight"]
990
# PFKEYSHORT_LIST = ["undef", "Favorite", "Bright+", "Scan",
991
#                             "Flashlight", "Alarm", "SOS", "FM Radio",
992
#                             "Moni", "Strobe", "Weather", "Tlk A", "Reverse",
993
#                             "CTC Scan", "DCS Scan", "Backlight"]
994
WORKMODE_LIST = ["VFO", "Ch.Number.", "Ch.Freq.", "Ch.Name"]
995
BACKLIGHT_LIST = ["Always On"] + [str(x) + "s" for x in range(1, 21)] + \
996
    ["Always Off"]
997
OFFSET_LIST = ["OFF", "Plus Shift", "Minus Shift"]
998
PONMSG_LIST = ["Startup Display", "Battery Volts"]
999
SPMUTE_LIST = ["QT", "QT+DTMF", "QT*DTMF"]
1000
DTMFST_LIST = ["OFF", "DTMF", "ANI", "DTMF+ANI"]
1001
DTMF_TIMES = [('%dms' % dtmf, (dtmf // 10)) for dtmf in range(50, 501, 10)]
1002
ALERTS = [1750, 2100, 1000, 1450]
1003
ALERTS_LIST = [str(x) + " Hz" for x in ALERTS]
1004
PTTID_LIST = ["OFF", "BOT", "EOT", "Both"]
1005
MAP_1_99 = [(str(x), x) for x in range(1, 100)]
1006
LIST_10 = ["OFF"] + ["%s" % x for x in range(1, 11)]
1007
LIST_10S = ["OFF"] + ["%s" % x + "s" for x in range(1, 11)]
1008
LIST_TOA = ["OFF"] + ["%s" % x + "s" for x in range(1, 11)]
1009
SCANGRP_LIST = ["All"] + ["%s" % x for x in range(1, 11)]
1010
SMUTESET_LIST = ["OFF", "Rx", "Tx", "Rx+Tx"]
1011
POWER_LIST = ["Lo", "Mid", "Hi", "UltraHigh"]
1012
HOLD_TIMES = ["OFF"] + ["%s" % x + "s" for x in range(100, 5001, 100)]
1013
RPTTYPE_MAP = [("X-DIRPT", 1), ("X-TWRPT", 2)]
1014
THEME_LIST = ["White-1", "White-2", "Black-1", "Black-2",
1015
              "Cool", "Rain", "NotARubi", "Sky", "BTWR", "Candy",
1016
              "Custom 1", "Custom 2", "Custom 3", "Custom 4"]
1017
DSPBRTSBY_LIST = ["OFF", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
1018
DSPBRTACT_MAP = [("1", 1), ("2", 2), ("3", 3), ("4", 4), ("5", 5),
1019
                 ("6", 6), ("7", 7), ("8", 8), ("9", 9), ("10", 10)]
1020
TONESCANSAVELIST = ["Rx", "Tx", "Tx/Rx"]
1021
PTTDELAY_TIMES = [('%dms' % pttdelay,
1022
                  (pttdelay // 100)) for pttdelay in range(100, 3001, 100)]
1023
SCRAMBLE_LIST = ["OFF"] + [str(x) for x in range(1, 9)]
1024
ONOFF_LIST = ["OFF", "ON"]
1025
TONE_MAP = [('OFF - No Tone', 0x0000)] + \
1026
           [('%.1f' % tone,
1027
            int(0x8000 + tone * 10)) for tone in chirp_common.TONES] + \
1028
           [('D%03dn' % tone, int(0x4000 + int(str(tone), 8)))
1029
               for tone in chirp_common.DTCS_CODES] + \
1030
           [('D%03di' % tone, int(0x6000 + int(str(tone), 8)))
1031
               for tone in chirp_common.DTCS_CODES]
1032
BATT_DISP_LIST = ["Icon", "Voltage", "Percent"]
1033
WX_TYPE = ["Weather", "Icon-Only", "Tone", "Flash", "Tone-Flash"]
1034
AM_MODE = ["OFF", "AM Rx", "AM Rx+Tx"]
1035
AM_MODE_2 = ["OFF", "AM Rx"]
1036
AM_MODE_CH = [("",0), ("AM Rx", 1), ("AM Rx+Tx", 2)]
1037
AM_MODE_CH2 = [("",0), ("AM Rx", 1)]
1038

    
1039
TIME_ZONE = ["GMT-12", "GMT-11", "GMT-10", "GMT-9", "GMT-8",
1040
             "GMT-7", "GMT-6", "GMT-5", "GMT-4", "GMT-3",
1041
             "GMT-2", "GMT-1", "GMT", "GMT+1", "GMT+2",
1042
             "GMT+3", "GMT+4", "GMT+5", "GMT+6", "GMT+7",
1043
             "GMT+8", "GMT+9", "GMT+10", "GMT+11", "GMT+12"]
1044
GPS_SEND_FREQ = ["OFF", "PTT SEND", "1 min", "2 min", "3 min",
1045
                 "4 min", "5 min", "6 min", "7 min", "8 min",
1046
                 "9 min", "10 min"]
1047
VFOABAND_MAP = [("150M", 0),
1048
                ("400M", 1),
1049
                ("200M", 2),
1050
                ("66M", 3),
1051
                ("800M", 4),
1052
                ("300M", 5)]
1053
VFOABAND_MAP2 = [("150M", 0),
1054
                 ("400M", 1),
1055
                 ("200M", 2),
1056
                 ("26M", 3),
1057
                 ("800M", 4),
1058
                 ("300M", 5)]
1059

    
1060
VFOBBAND_MAP = [("150M", 0),
1061
                ("400M", 1)]
1062
PTT_LIST = ["Area A", "Area B", "Main Tx", "Secondary Tx", "Low Power",
1063
            "Ultra Hi Power", "Call"]
1064
PROG_KEY_LIST = ["DISABLE/UNDEF", "ALARM", "BACKLIGHT", "BRIGHT+", "FAVORITE",
1065
                 "FLASHLIGHT", "FM-RADIO", "DISPLAY-MAP", "MONITOR",
1066
                 "REVERSE", "SCAN", "SCAN-CTC", "SCAN-DCS", "SOS",
1067
                 "STROBE", "TALK-AROUND", "WEATHER"]
1068
PROG_KEY_LIST2 = ["DISABLE/UNDEF", "ALARM", "BACKLIGHT", "BRIGHT+", "FAVORITE",
1069
                  "FLASHLIGHT", "FM-RADIO", "DISPLAY-MAP", "MONITOR",
1070
                  "REVERSE", "SCAN", "SCAN-CTC", "SCAN-DCS", "SOS",
1071
                  "STROBE", "TALK-AROUND", "WEATHER", "FM/AM", "CH-WIZARD"]
1072

    
1073
VFO_SCANMODE_LIST = ["Current Band", "Range", "All"]
1074
ACTIVE_AREA_LIST = ["Area A - Top", "Area B - Bottom"]
1075
TDR_LIST = ["TDR ON", "TDR OFF"]
1076
PRICHAN_LIST = ["OFF", "ON Standby - Rx OFF", "Always On"]
1077
# First Q10H Firmware revison did not support 20k Step Size option
1078
NO_20K_STEP_FIRMWARE = ["VC1.00"]
1079
# memory slot 0 is not used, start at 1 (so need 1000 slots, not 999)
1080
# structure elements whose name starts with x are currently unidentified
1081

    
1082
_MEM_FORMAT_Q10H_oem_read = """
1083
    #seekto 0x0002;
1084
    struct {
1085
        ul32    tworx_start;
1086
        ul32    tworx_stop;
1087
        ul32    cm70_tx_start;  //70cm Tx
1088
        ul32    cm70_tx_stop;   //70cm Tx
1089
        ul32    m125_tx_start;  //1.25m Tx
1090
        ul32    m125_tx_stop;   //1.25m Tx
1091
        ul32    m6_tx_start;    //6m Tx
1092
        ul32    m6_tx_stop;     //6m Tx
1093
        #seekto 0x00a6;
1094
        ul32    rx1lim_start;
1095
        ul32    rx1lim_stop;
1096
        ul32    rx2lim_start;
1097
        ul32    rx2lim_stop;
1098
        ul32    rx3lim_start;
1099
        ul32    rx3lim_stop;
1100
        ul32    rx4lim_start;
1101
        ul32    rx4lim_stop;
1102
        ul32    rx5lim_start;
1103
        ul32    rx5lim_stop;
1104
        ul32    rx6lim_start;
1105
        ul32    rx6lim_stop;
1106
        ul32    rx7lim_start;
1107
        ul32    rx7lim_stop;
1108
        ul32    rx8lim_start;
1109
        ul32    rx8lim_stop;
1110
        ul32    m2tx_start;     // 2m Tx
1111
        ul32    m2tx_stop;      // 2m tx
1112
        ul32    rx10lim_start;
1113
        ul32    rx10lim_stop;
1114
        ul32    rx11lim_start;
1115
        ul32    rx11lim_stop;
1116
    } limits;
1117

    
1118
    #seekto 0x0040;
1119
    struct {
1120
        char     oem1[8];
1121
        #seekto 0x006c; //0x002c;
1122
        char    name[8];
1123
        #seekto 0x0092; //0x0052;
1124
        char     firmware[6];
1125
        #seekto 0x0078; //0x0038;
1126
        char     date[10];
1127
        #seekto 0x030a;
1128
        u8      locked;
1129
    } oem_info;
1130

    
1131
    #seekto 0x7740;
1132
    struct {
1133
        struct {
1134
            ul16 scan_st;
1135
            ul16 scan_end;
1136
        } addrs[10];
1137
        struct {
1138
            char name[12];
1139
        } names[10];
1140
    } scn_grps;
1141

    
1142
    #seekto 0x78e0;
1143
    struct {
1144
        u8 cid[6];
1145
    } call_ids[100];
1146

    
1147
    #seekto 0x7B40;
1148
    struct {
1149
        char    call_name[12];
1150
    } call_names[100];
1151

    
1152

    
1153
    #seekto 0x0520;
1154
    struct {
1155
        u8      channel_menu;
1156
        u8      power_save;
1157
        u8      roger_beep;
1158
        u8      timeout;
1159
        u8      toalarm;
1160
        u8      wxalert;
1161
        u8      wxalert_type;
1162
        u8      vox;
1163
        u8      unk_xp8;
1164
        u8      voice;
1165
        u8      beep;
1166
        u8      scan_rev;
1167
        u8      backlight;
1168
        u8      DspBrtAct;
1169
        u8      DspBrtSby;
1170
        u8      ponmsg;
1171
        u8      ptt_id; //0x530
1172
        u8      ptt_delay;
1173
        u8      dtmf_st;
1174
        u8      dtmf_tx_time;
1175
        u8      dtmf_interval;
1176
        u8      ring_time;
1177
        u8      alert;
1178
        u8      autolock;
1179
        ul16     pri_ch;
1180
        u8      prich_sw;
1181
        u8      rpttype;
1182
        u8      rpt_spk;
1183
        u8      rpt_ptt;
1184
        u8      rpt_tone;
1185
        u8      rpt_hold;
1186
        u8      scan_det;
1187
        u8      smuteset; //0x540
1188
        u8      batt_ind;
1189
        u8      ToneScnSave;
1190
        #seekto 0x0544;
1191
        u8      theme;
1192
        u8      unkx545;
1193
        u8      disp_time;
1194
        u8      time_zone;
1195
        u8      GPS_send_freq;
1196
        u8      GPS;
1197
        u8      GPS_rcv;
1198
        ul16    custcol1_text;
1199
        ul16    custcol1_bg;
1200
        ul16    custcol1_icon;
1201
        ul16    custcol1_line;
1202
        ul16    custcol2_text;
1203
        ul16    custcol2_bg;
1204
        ul16    custcol2_icon;
1205
        ul16    custcol2_line;
1206
        ul16    custcol3_text;
1207
        ul16    custcol3_bg;
1208
        ul16    custcol3_icon;
1209
        ul16    custcol3_line;
1210
        ul16    custcol4_text;
1211
        ul16    custcol4_bg;
1212
        ul16    custcol4_icon;
1213
        ul16    custcol4_line;
1214
//        #seekto 0x056b;
1215
        char      mode_sw_pwd[6];
1216
        char      reset_pwd[6];
1217
        u8      work_mode_a;
1218
        u8      work_mode_b;
1219
        ul16      work_ch_a;
1220
        ul16      work_ch_b;
1221
        u8      vfostepA;
1222
        u8      vfostepB;
1223
        u8      squelchA;
1224
        u8      squelchB;
1225
        u8      BCL_A;
1226
        u8      BCL_B;
1227
        u8      vfobandA;
1228
        u8      vfobandB;
1229
        #seekto 0x0587;
1230
        u8      top_short;
1231
        u8      top_long;
1232
        u8      ptt1;
1233
        u8      ptt2;
1234
        u8      pf1_short;
1235
        u8      pf1_long;
1236
        u8      pf2_short;
1237
        u8      pf2_long;
1238
        u8      ScnGrpA_Act;
1239
        u8      ScnGrpB_Act;
1240
        u8      vfo_scanmodea;
1241
        u8      vfo_scanmodeb; //x592
1242
        u8      ani_id[6];
1243
        u8      scc[6];
1244
        #seekto 0x05A1;
1245
        u8      act_area;
1246
        u8      tdr;
1247
        u8      keylock;
1248
        #seekto 0x05A9;
1249
        char    dispstr[12];
1250
        #seekto 0x05BD;
1251
        char    areamsg[12];
1252
        u8      xunk_1;
1253
        u8      xunk_2;
1254
        u8      xunk_ani_sw;
1255
        u8      xani_code[6];
1256
        u8      xpf1_shrt;
1257
        u8      xpf1_long;
1258
        u8      xpf2_shrt;
1259
        u8      xpf2_long;
1260
        u8      main_band;
1261
        u8      xTDR_single_mode;
1262
        u8      xunk1;
1263
        u8      xunk2;
1264
        u8      cur_call_grp;
1265
        u8 VFO_repeater_a;
1266
        u8 VFO_repeater_b;
1267
        u8 sim_rec;
1268
    } settings;
1269

    
1270
    #seekto 0x78B0;
1271
    struct {
1272
        ul16    FM_radio;
1273
    } fm[20];
1274

    
1275
    #seekto 0x0440;
1276
    struct {
1277
        ul32     rxfreq;
1278
        ul32     offset;
1279
        ul16     rxtone;
1280
        ul16     txtone;
1281
        u8      scrambler:4,
1282
                am_mode:2,
1283
                power:2;
1284
        u8      ofst_dir:3,
1285
                unknown:1,
1286
                compander:1,
1287
                mute_mode:2,
1288
                iswide:1;
1289
        u8      call_group;
1290
        u8      unknown6;
1291
      } vfoa[6];
1292

    
1293
    #seekto 0x04a0;
1294
    struct {
1295
        ul32     rxfreq;
1296
        ul32     offset;
1297
        ul16     rxtone;
1298
        ul16     txtone;
1299
        u8      scrambler:4,
1300
                am_mode:2,
1301
                power:2;
1302
        u8      ofst_dir:3,
1303
                unknown:1,
1304
                compander:1,
1305
                mute_mode:2,
1306
                iswide:1;
1307
        u8      call_group;
1308
        u8      unknown6;
1309
    } vfob[2];
1310

    
1311
    #seekto 0x05E0;
1312
    struct {
1313
        ul32     rxfreq;
1314
        ul32     txfreq;
1315
        ul16     rxtone;
1316
        ul16     txtone;
1317
        u8      scrambler:4,
1318
                am_mode:2,
1319
                power:2;
1320
        u8      unknown3:1,
1321
                send_loc:1,
1322
                scan_add:1,
1323
                favorite:1,
1324
                compander:1,
1325
                mute_mode:2,
1326
                iswide:1;
1327
        u8      call_group;
1328
        u8      unknown6;
1329
    } memory[1000];
1330

    
1331
    #seekto 0x4460;
1332
    struct {
1333
        u8    name[12];
1334
    } names[1000];
1335

    
1336
    #seekto 0x7340;
1337
    u8          valid[1000];
1338

    
1339
    #seekto 0x77E0;
1340
    struct {
1341
        ul16    vfo_scan_start_A;
1342
        ul16    vfo_scan_end_A;
1343
        ul16    vfo_scan_start_B;
1344
        ul16    vfo_scan_end_B;
1345
    } vfo_scan;
1346

    
1347
    """
1348

    
1349
_MEM_FORMAT_Q10H_oem_read2 = """
1350
    #seekto 0x02c2;
1351
    struct {
1352
        ul32    rx12lim_start;
1353
        ul32    rx12lim_stop;
1354
        ul32    rx13lim_start;
1355
        ul32    rx13lim_stop;
1356
        ul32    rx14lim_start;
1357
        ul32    rx14lim_stop;
1358
        ul32    rx15lim_start;
1359
        ul32    rx15lim_stop;
1360
        ul32    rx16lim_start;
1361
        ul32    rx16lim_stop;
1362
        ul32    rx17lim_start;
1363
        ul32    rx17lim_stop;
1364
        ul32    rx18lim_start;
1365
        ul32    rx18lim_stop;
1366
        ul32    rx19lim_start;
1367
        ul32    rx19lim_stop;
1368
        #seekto 0x0302;
1369
        ul32    tworx_start;
1370
        ul32    tworx_stop;
1371
        ul32    cm70_tx_start;  //70cm Tx
1372
        ul32    cm70_tx_stop;   //70cm Tx
1373
        ul32    m125_tx_start;  //1.25m Tx
1374
        ul32    m125_tx_stop;   //1.25m Tx
1375
        ul32    m6_tx_start;    //6m Tx
1376
        ul32    m6_tx_stop;     //6m Tx
1377
        #seekto 0x03a6;
1378
        ul32    rx1lim_start;
1379
        ul32    rx1lim_stop;
1380
        ul32    rx2lim_start;
1381
        ul32    rx2lim_stop;
1382
        ul32    rx3lim_start;
1383
        ul32    rx3lim_stop;
1384
        ul32    rx4lim_start;
1385
        ul32    rx4lim_stop;
1386
        ul32    rx5lim_start;
1387
        ul32    rx5lim_stop;
1388
        ul32    rx6lim_start;
1389
        ul32    rx6lim_stop;
1390
        ul32    rx7lim_start;
1391
        ul32    rx7lim_stop;
1392
        ul32    rx8lim_start;
1393
        ul32    rx8lim_stop;
1394
        ul32    m2tx_start;     // 2m Tx
1395
        ul32    m2tx_stop;      // 2m tx
1396
        ul32    rx10lim_start;
1397
        ul32    rx10lim_stop;
1398
        ul32    rx11lim_start;
1399
        ul32    rx11lim_stop;
1400
        #seekto 0x3a6;
1401
        struct {
1402
        ul32    lim_start;
1403
        ul32    lim_stop;
1404
        } more_limits[14];
1405
    } limits;
1406

    
1407
    #seekto 0x0340;
1408
    struct {
1409
        char     oem1[8];
1410
        #seekto 0x036c; //0x002c;
1411
        char    name[8];
1412
        #seekto 0x0392; //0x0052;
1413
        char     firmware[6];
1414
        #seekto 0x0378; //0x0038;
1415
        char     date[10];
1416
        #seekto 0x000a;
1417
        u8      locked;
1418
    } oem_info;
1419

    
1420
    #seekto 0x7740;
1421
    struct {
1422
        struct {
1423
            ul16 scan_st;
1424
            ul16 scan_end;
1425
        } addrs[10];
1426
        struct {
1427
            char name[12];
1428
        } names[10];
1429
    } scn_grps;
1430

    
1431
    #seekto 0x78e0;
1432
    struct {
1433
        u8 cid[6];
1434
    } call_ids[100];
1435

    
1436
    #seekto 0x7B40;
1437
    struct {
1438
        char    call_name[12];
1439
    } call_names[100];
1440

    
1441

    
1442
    #seekto 0x0440;
1443
    struct {
1444
        u8      channel_menu;
1445
        u8      power_save;
1446
        u8      roger_beep;
1447
        u8      timeout;
1448
        u8      toalarm;
1449
        u8      wxalert;
1450
        u8      wxalert_type;
1451
        u8      vox;
1452
        u8      unk_xp8;
1453
        u8      voice;
1454
        u8      beep;
1455
        u8      scan_rev;
1456
        u8      backlight;
1457
        u8      DspBrtAct;
1458
        u8      DspBrtSby;
1459
        u8      ponmsg;
1460
        u8      ptt_id; //0x530
1461
        u8      ptt_delay;
1462
        u8      dtmf_st;
1463
        u8      dtmf_tx_time;
1464
        u8      dtmf_interval;
1465
        u8      ring_time;
1466
        u8      alert;
1467
        u8      autolock;
1468
        ul16     pri_ch;
1469
        u8      prich_sw;
1470
        u8      rpttype;
1471
        u8      rpt_spk;
1472
        u8      rpt_ptt;
1473
        u8      rpt_tone;
1474
        u8      rpt_hold;
1475
        u8      scan_det;
1476
        u8      smuteset; //0x540
1477
        u8      batt_ind;
1478
        u8      ToneScnSave;
1479
        #seekto 0x0464;
1480
        u8      theme;
1481
        u8      unkx545;
1482
        u8      disp_time;
1483
        u8      time_zone;
1484
        u8      GPS_send_freq;
1485
        u8      GPS;
1486
        u8      GPS_rcv;
1487
        ul16    custcol1_text;
1488
        ul16    custcol1_bg;
1489
        ul16    custcol1_icon;
1490
        ul16    custcol1_line;
1491
        ul16    custcol2_text;
1492
        ul16    custcol2_bg;
1493
        ul16    custcol2_icon;
1494
        ul16    custcol2_line;
1495
        ul16    custcol3_text;
1496
        ul16    custcol3_bg;
1497
        ul16    custcol3_icon;
1498
        ul16    custcol3_line;
1499
        ul16    custcol4_text;
1500
        ul16    custcol4_bg;
1501
        ul16    custcol4_icon;
1502
        ul16    custcol4_line;
1503
//        #seekto 0x048b;
1504
        char      mode_sw_pwd[6];
1505
        char      reset_pwd[6];
1506
        u8      work_mode_a;
1507
        u8      work_mode_b;
1508
        ul16      work_ch_a;
1509
        ul16      work_ch_b;
1510
        u8      vfostepA;
1511
        u8      vfostepB;
1512
        u8      squelchA;
1513
        u8      squelchB;
1514
        u8      BCL_A;
1515
        u8      BCL_B;
1516
        u8      vfobandA;
1517
        u8      vfobandB;
1518
        #seekto 0x04a7;
1519
        u8      top_short;
1520
        u8      top_long;
1521
        u8      ptt1;
1522
        u8      ptt2;
1523
        u8      pf1_short;
1524
        u8      pf1_long;
1525
        u8      pf2_short;
1526
        u8      pf2_long;
1527
        u8      ScnGrpA_Act;
1528
        u8      ScnGrpB_Act;
1529
        u8      vfo_scanmodea;
1530
        u8      vfo_scanmodeb; //x592
1531
        u8      ani_id[6];
1532
        u8      scc[6];
1533
        #seekto 0x04c1;
1534
        u8      act_area;
1535
        u8      tdr;
1536
        u8      keylock;
1537
        #seekto 0x04c7;
1538
        u8      stopwatch; //0x04c7
1539
        u8      x0x04c8;
1540
        char    dispstr[12];
1541
        #seekto 0x04dD;
1542
        char    areamsg[12];
1543
        u8      xUnk_1;
1544
        u8      xunk_2;
1545
        u8      xunk_ani_sw;
1546
        u8      xani_code[6];
1547
        u8      xpf1_shrt;
1548
        u8      xpf1_long;
1549
        u8      xpf2_shrt;
1550
        u8      xpf2_long;
1551
        u8      main_band;
1552
        u8      xTDR_single_mode;
1553
        u8      xunk1;
1554
        u8      xunk2;
1555
        u8      cur_call_grp;
1556
        u8 VFO_repeater_a;
1557
        u8 VFO_repeater_b;
1558
        u8 sim_rec;
1559
    } settings;
1560

    
1561
    #seekto 0x78B0;
1562
    struct {
1563
        ul16    FM_radio;
1564
    } fm[20];
1565

    
1566
    #seekto 0x0540;
1567
    struct {
1568
        ul32     rxfreq;
1569
        ul32     offset;
1570
        ul16     rxtone;
1571
        ul16     txtone;
1572
        u8      scrambler:4,
1573
                am_mode:2,
1574
                power:2;
1575
        u8      ofst_dir:3,
1576
                unknown:1,
1577
                compander:1,
1578
                mute_mode:2,
1579
                iswide:1;
1580
        u8      call_group;
1581
        u8      unknown6;
1582
      } vfoa[6];
1583

    
1584
    #seekto 0x05a0;
1585
    struct {
1586
        ul32     rxfreq;
1587
        ul32     offset;
1588
        ul16     rxtone;
1589
        ul16     txtone;
1590
        u8      scrambler:4,
1591
                am_mode:2,
1592
                power:2;
1593
        u8      ofst_dir:3,
1594
                unknown:1,
1595
                compander:1,
1596
                mute_mode:2,
1597
                iswide:1;
1598
        u8      call_group;
1599
        u8      unknown6;
1600
    } vfob[2];
1601

    
1602
    #seekto 0x05E0;
1603
    struct {
1604
        ul32     rxfreq;
1605
        ul32     txfreq;
1606
        ul16     rxtone;
1607
        ul16     txtone;
1608
        u8      scrambler:4,
1609
                am_mode:2,
1610
                power:2;
1611
        u8      unknown3:1,
1612
                send_loc:1,
1613
                scan_add:1,
1614
                favorite:1,
1615
                compander:1,
1616
                mute_mode:2,
1617
                iswide:1;
1618
        u8      call_group;
1619
        u8      unknown6;
1620
    } memory[1000];
1621

    
1622
    #seekto 0x4460;
1623
    struct {
1624
        u8    name[12];
1625
    } names[1000];
1626

    
1627
    #seekto 0x7340;
1628
    u8          valid[1000];
1629

    
1630
    #seekto 0x77E0;
1631
    struct {
1632
        ul16    vfo_scan_start_A;
1633
        ul16    vfo_scan_end_A;
1634
        ul16    vfo_scan_start_B;
1635
        ul16    vfo_scan_end_B;
1636
    } vfo_scan;
1637

    
1638
    """
1639

    
1640
_MEM_FORMAT_Q10H_oem_read_nolims = """
1641

    
1642
    #seekto 0x0340;
1643
    struct {
1644
        char     oem1[8];
1645
        #seekto 0x036c; //0x002c;
1646
        char    name[8];
1647
        #seekto 0x0392; //0x0052;
1648
        char     firmware[6];
1649
        #seekto 0x0378; //0x0038;
1650
        char     date[10];
1651
        #seekto 0x000a;
1652
        u8      locked;
1653
    } oem_info;
1654

    
1655
    #seekto 0x7740;
1656
    struct {
1657
        struct {
1658
            ul16 scan_st;
1659
            ul16 scan_end;
1660
        } addrs[10];
1661
        struct {
1662
            char name[12];
1663
        } names[10];
1664
    } scn_grps;
1665

    
1666
    #seekto 0x78e0;
1667
    struct {
1668
        u8 cid[6];
1669
    } call_ids[100];
1670

    
1671
    #seekto 0x7B40;
1672
    struct {
1673
        char    call_name[12];
1674
    } call_names[100];
1675

    
1676

    
1677
    #seekto 0x0440;
1678
    struct {
1679
        u8      channel_menu;
1680
        u8      power_save;
1681
        u8      roger_beep;
1682
        u8      timeout;
1683
        u8      toalarm;
1684
        u8      wxalert;
1685
        u8      wxalert_type;
1686
        u8      vox;
1687
        u8      unk_xp8;
1688
        u8      voice;
1689
        u8      beep;
1690
        u8      scan_rev;
1691
        u8      backlight;
1692
        u8      DspBrtAct;
1693
        u8      DspBrtSby;
1694
        u8      ponmsg;
1695
        u8      ptt_id; //0x530
1696
        u8      ptt_delay;
1697
        u8      dtmf_st;
1698
        u8      dtmf_tx_time;
1699
        u8      dtmf_interval;
1700
        u8      ring_time;
1701
        u8      alert;
1702
        u8      autolock;
1703
        ul16     pri_ch;
1704
        u8      prich_sw;
1705
        u8      rpttype;
1706
        u8      rpt_spk;
1707
        u8      rpt_ptt;
1708
        u8      rpt_tone;
1709
        u8      rpt_hold;
1710
        u8      scan_det;
1711
        u8      smuteset; //0x540
1712
        u8      batt_ind;
1713
        u8      ToneScnSave;
1714
        #seekto 0x0464;
1715
        u8      theme;
1716
        u8      unkx545;
1717
        u8      disp_time;
1718
        u8      time_zone;
1719
        u8      GPS_send_freq;
1720
        u8      GPS;
1721
        u8      GPS_rcv;
1722
        ul16    custcol1_text;
1723
        ul16    custcol1_bg;
1724
        ul16    custcol1_icon;
1725
        ul16    custcol1_line;
1726
        ul16    custcol2_text;
1727
        ul16    custcol2_bg;
1728
        ul16    custcol2_icon;
1729
        ul16    custcol2_line;
1730
        ul16    custcol3_text;
1731
        ul16    custcol3_bg;
1732
        ul16    custcol3_icon;
1733
        ul16    custcol3_line;
1734
        ul16    custcol4_text;
1735
        ul16    custcol4_bg;
1736
        ul16    custcol4_icon;
1737
        ul16    custcol4_line;
1738
//        #seekto 0x048b;
1739
        char      mode_sw_pwd[6];
1740
        char      reset_pwd[6];
1741
        u8      work_mode_a;
1742
        u8      work_mode_b;
1743
        ul16      work_ch_a;
1744
        ul16      work_ch_b;
1745
        u8      vfostepA;
1746
        u8      vfostepB;
1747
        u8      squelchA;
1748
        u8      squelchB;
1749
        u8      BCL_A;
1750
        u8      BCL_B;
1751
        u8      vfobandA;
1752
        u8      vfobandB;
1753
        #seekto 0x04a7;
1754
        u8      top_short;
1755
        u8      top_long;
1756
        u8      ptt1;
1757
        u8      ptt2;
1758
        u8      pf1_short;
1759
        u8      pf1_long;
1760
        u8      pf2_short;
1761
        u8      pf2_long;
1762
        u8      ScnGrpA_Act;
1763
        u8      ScnGrpB_Act;
1764
        u8      vfo_scanmodea;
1765
        u8      vfo_scanmodeb; //x592
1766
        u8      ani_id[6];
1767
        u8      scc[6];
1768
        #seekto 0x04c1;
1769
        u8      act_area;
1770
        u8      tdr;
1771
        u8      keylock;
1772
        #seekto 0x04c7;
1773
        u8      stopwatch; //0x04c7
1774
        u8      x0x04c8;
1775
        char    dispstr[12];
1776
        #seekto 0x04dD;
1777
        char    areamsg[12];
1778
        u8      xunk_1;
1779
        u8      xunk_2;
1780
        u8      xunk_ani_sw;
1781
        u8      xani_code[6];
1782
        u8      xpf1_shrt;
1783
        u8      xpf1_long;
1784
        u8      xpf2_shrt;
1785
        u8      xpf2_long;
1786
        u8      main_band;
1787
        u8      xTDR_single_mode;
1788
        u8      xunk1;
1789
        u8      xunk2;
1790
        u8      cur_call_grp;
1791
        u8 VFO_repeater_a;
1792
        u8 VFO_repeater_b;
1793
        u8 sim_rec;
1794
    } settings;
1795

    
1796
    #seekto 0x78B0;
1797
    struct {
1798
        ul16    FM_radio;
1799
    } fm[20];
1800

    
1801
    #seekto 0x0540;
1802
    struct {
1803
        ul32     rxfreq;
1804
        ul32     offset;
1805
        ul16     rxtone;
1806
        ul16     txtone;
1807
        u8      scrambler:4,
1808
                am_mode:2,
1809
                power:2;
1810
        u8      ofst_dir:3,
1811
                unknown:1,
1812
                compander:1,
1813
                mute_mode:2,
1814
                iswide:1;
1815
        u8      call_group;
1816
        u8      unknown6;
1817
      } vfoa[6];
1818

    
1819
    #seekto 0x05a0;
1820
    struct {
1821
        ul32     rxfreq;
1822
        ul32     offset;
1823
        ul16     rxtone;
1824
        ul16     txtone;
1825
        u8      scrambler:4,
1826
                am_mode:2,
1827
                power:2;
1828
        u8      ofst_dir:3,
1829
                unknown:1,
1830
                compander:1,
1831
                mute_mode:2,
1832
                iswide:1;
1833
        u8      call_group;
1834
        u8      unknown6;
1835
    } vfob[2];
1836

    
1837
    #seekto 0x05E0;
1838
    struct {
1839
        ul32     rxfreq;
1840
        ul32     txfreq;
1841
        ul16     rxtone;
1842
        ul16     txtone;
1843
        u8      scrambler:4,
1844
                am_mode:2,
1845
                power:2;
1846
        u8      unknown3:1,
1847
                send_loc:1,
1848
                scan_add:1,
1849
                favorite:1,
1850
                compander:1,
1851
                mute_mode:2,
1852
                iswide:1;
1853
        u8      call_group;
1854
        u8      unknown6;
1855
    } memory[1000];
1856

    
1857
    #seekto 0x4460;
1858
    struct {
1859
        u8    name[12];
1860
    } names[1000];
1861

    
1862
    #seekto 0x7340;
1863
    u8          valid[1000];
1864

    
1865
    #seekto 0x77E0;
1866
    struct {
1867
        ul16    vfo_scan_start_A;
1868
        ul16    vfo_scan_end_A;
1869
        ul16    vfo_scan_start_B;
1870
        ul16    vfo_scan_end_B;
1871
    } vfo_scan;
1872

    
1873
    """
1874

    
1875
# Support for the Wouxun KG-Q10H radio
1876
# Serial coms are at 115200 baud
1877
# The data is passed in variable length records
1878
# Record structure:
1879
#  Offset   Usage
1880
#    0      start of record (\x7c)
1881
#    1      Command (\x80 Identify \x81 End/Reboot \x82 Read \x83 Write)
1882
#    2      direction (\xff PC-> Radio, \x00 Radio -> PC)
1883
#    3      length of payload (excluding header/checksum) (n)
1884
#    4      payload (n bytes)
1885
#    4+n+1  checksum - byte sum (% 256) of bytes 1 -> 4+n
1886
#
1887
# Memory Read Records:
1888
# the payload is 3 bytes, first 2 are offset (big endian),
1889
# 3rd is number of bytes to read
1890
# Memory Write Records:
1891
# the maximum payload size (from the Wouxun software) seems to be 66 bytes
1892
#  (2 bytes location + 64 bytes data).
1893

    
1894

    
1895
def name2str(name):
1896
    """ Convert a callid or scan group name to a string
1897
    Deal with fixed field padding (\0 or \0xff)
1898
    """
1899

    
1900
    namestr = ""
1901
    for i in range(0, len(name)):
1902
        b = ord(name[i].get_value())
1903
        if b != 0 and b != 0xff:
1904
            namestr += chr(b)
1905
    return namestr
1906

    
1907

    
1908
def str2name(val, size=6, fillchar='\0', emptyfill='\0'):
1909
    """ Convert a string to a name. A name is a 6 element bytearray
1910
    with ascii chars.
1911
    """
1912
    val = str(val).rstrip(' \t\r\n\0\xff')
1913
    if len(val) == 0:
1914
        name = "".ljust(size, emptyfill)
1915
    else:
1916
        name = val.ljust(size, fillchar)
1917
    return name
1918

    
1919

    
1920
def str2callid(val):
1921
    """ Convert caller id strings from callid2str.
1922
    """
1923
    ascii2bin = "0123456789"
1924
    s = str(val).strip()
1925
    LOG.debug("val = %s" % val)
1926
    LOG.debug("s = %s" % s)
1927
    if len(s) < 3 or len(s) > 6:
1928
        raise InvalidValueError(
1929
            "Caller ID must be at least 3 and no more than 6 digits")
1930
    if s[0] == '0':
1931
        raise InvalidValueError(
1932
            "First digit of a Caller ID cannot be a zero '0'")
1933
    blk = bytearray()
1934
    for c in s:
1935
        if c not in ascii2bin:
1936
            raise InvalidValueError(
1937
                "Caller ID must be all digits 0x%x" % c)
1938
        b = ascii2bin.index(c)
1939
        blk.append(b)
1940
    if len(blk) < 6:
1941
        blk.append(0x0F)  # EOL a short ID
1942
    if len(blk) < 6:
1943
        for i in range(0, (6 - len(blk))):
1944
            blk.append(0xf0)
1945
    LOG.debug("blk = %s" % blk)
1946
    return blk
1947

    
1948

    
1949
def digits2str(digits, padding=' ', width=6):
1950
    """Convert a password or SCC digit string to a string
1951
    Passwords are expanded to and must be 6 chars. Fill them with '0'
1952
    """
1953

    
1954
    bin2ascii = "0123456789"
1955
    digitsstr = ""
1956
    for i in range(0, 6):
1957
        b = digits[i].get_value()
1958
        if b == 0x0F:  # the digits EOL
1959
            break
1960
        if b >= 0xa:
1961
            raise InvalidValueError(
1962
                "Value has illegal byte 0x%x" % ord(b))
1963
        digitsstr += bin2ascii[b]
1964
    digitsstr = digitsstr.ljust(width, padding)
1965
    return digitsstr
1966

    
1967

    
1968
def str2digits(val):
1969
    """ Callback for edited strings from digits2str.
1970
    """
1971
    ascii2bin = " 0123456789"
1972
    s = str(val).strip()
1973
    if len(s) < 3 or len(s) > 6:
1974
        raise InvalidValueError(
1975
            "Value must be at least 3 and no more than 6 digits")
1976
    blk = bytearray()
1977
    for c in s:
1978
        if c not in ascii2bin:
1979
            raise InvalidValueError("Value must be all digits 0x%x" % c)
1980
        blk.append(int(c))
1981
    for i in range(len(blk), 6):
1982
        blk.append(0x0f)  # EOL a short ID
1983
    return blk
1984

    
1985

    
1986
def apply_scc(setting, obj):
1987
    c = str2digits(setting.value)
1988
    obj.scc = c
1989

    
1990

    
1991
@directory.register
1992
class KGQ10HRadio(chirp_common.CloneModeRadio,
1993
                  chirp_common.ExperimentalRadio):
1994

    
1995
    """Wouxun KG-Q10H"""
1996
    VENDOR = "Wouxun"
1997
    MODEL = "KG-Q10H"
1998
    NEEDS_COMPAT_SERIAL = False
1999
    _model = b"KG-Q10H"
2000
    BAUD_RATE = 115200
2001
    POWER_LEVELS = [chirp_common.PowerLevel("L", watts=0.5),
2002
                    chirp_common.PowerLevel("M", watts=4.5),
2003
                    chirp_common.PowerLevel("H", watts=5.5),
2004
                    chirp_common.PowerLevel("U", watts=6.0)]
2005
    _record_start = 0x7C
2006
    _RADIO_ID = ""
2007
    cryptbyte = 0x54
2008
    am_mode_list = AM_MODE
2009
    am_mode_list_ch = AM_MODE_CH
2010
    themelist = THEME_LIST
2011
    vfoa_grp_label = "VFO A Settings"
2012
    vfob_grp_label = "VFO B Settings"
2013
    workmodelist = WORKMODE_LIST
2014
    # pfkeyshort = PFKEYSHORT_LIST
2015
    # pfkeylong = PFKEYLONG_LIST
2016
    dispmesg = "Top Message"
2017
    areamsglabel = "Area Message"
2018
    vfo_area = "VFO "
2019
    # ani_msg = "ANI-ID Switch (ANI-SW)"
2020
    pttdly_msg = "PTT-DLY - menu 34"
2021
    idtx_msg = "PTT-ID - menu 33"
2022
    vfoa3_msg = "66M Settings"
2023
    _prog_key = PROG_KEY_LIST
2024
    _vfoaband = VFOABAND_MAP
2025
    _offset_dir_rpt = OFFSET_LIST
2026
    _offset_dir_rpt_label = "A Shift Dir"
2027
    _offset_dir_rpt_labelB = "B Shift Dir"
2028
    rpttonemenu = 43
2029
    timemenu = 44
2030
    tzmenu = 45
2031
    locmenu = 47
2032

    
2033
    Beta_release = True
2034

    
2035
    if Beta_release:
2036
        use_color = False
2037
        show_limits = False
2038
    else:
2039
        use_color = True
2040
        show_limits = True
2041

    
2042
    def check_for_beta1_file(self):
2043
        check1 = self.get_mmap()[0x0000:0x0005]
2044
        check2 = self.get_mmap()[0x0340:0x0346]
2045
        if ((check1 == b'\xdd\xdd\xdd\xdd\xdd') &
2046
           (check2 == b'\x57\x4F\x55\x58\x55\x4E')):
2047
            beta1 = False
2048
        else:
2049
            beta1 = True
2050
        return beta1
2051

    
2052
    def process_mmap(self):
2053
        if self.show_limits:
2054
            self._memobj = bitwise.parse(_MEM_FORMAT_Q10H_oem_read2,
2055
                                         self._mmap)
2056
        else:
2057
            self._memobj = bitwise.parse(_MEM_FORMAT_Q10H_oem_read_nolims,
2058
                                         self._mmap)
2059

    
2060
    def _checksum(self, data):
2061
        cs = 0
2062
        for byte in data:
2063
            cs += byte
2064
        return cs % 256
2065

    
2066
    def strxor(self, xora, xorb):
2067
        return bytes([xora ^ xorb])
2068

    
2069
    # Wouxun data jumps around the memory map and is not in continuous memory
2070
    # order
2071
    # Rearrange Mem Map to put all memory into order where data is continuous
2072
    def _rearrange_image(self, image_in):
2073
        image_out = b""
2074
        cfgmap = Q10H_mem_arrange_map
2075

    
2076
        for start, end in cfgmap:
2077
            LOG.debug("start = " + str(hex(start)))
2078
            LOG.debug("end = " + str(hex(end)))
2079

    
2080
            for i in range(start, end, 1):
2081
                image_out += image_in[i]
2082

    
2083
        return image_out
2084

    
2085
    def sync_in(self):
2086
        try:
2087
            self._mmap_addrorder = self._download()
2088
            self._mmap = memmap.MemoryMapBytes(self._rearrange_image
2089
                                               (self._mmap_addrorder))
2090
            # self._mmap = self._download()
2091
        except errors.RadioError:
2092
            raise
2093
        except Exception as e:
2094
            raise errors.RadioError("Failed to communicate with radio: %s" % e)
2095
        self.process_mmap()
2096

    
2097
    def sync_out(self):
2098
        self._upload()
2099

    
2100
    def _upload(self):
2101
        # Beta 1.x files had a different memory map arrangement
2102
        # Use of Beta 1.x files with Beta 2.x and beyond driver
2103
        # will send settings
2104
        # to incorrect locations on the radio casuing issues-
2105
        # Detect and Prevent!!
2106
        # Check for specific data (static) at specific locations
2107
        # to confirm Beta2 vs Beta1 memory layout.
2108
        beta1 = self.check_for_beta1_file()
2109
        if beta1:
2110
            LOG.debug("beta1 file detected = %s" % beta1)
2111
            raise errors.RadioError("Beta 1 img detected!!!\n"
2112
                                    "Upload Canceled!\n"
2113
                                    "Select a Beta 2.x img or\n"
2114
                                    "Download from radio to get a Beta2 img\n"
2115
                                    "Then Retry the Upload")
2116
        try:
2117
            self._identify()
2118
            self._do_upload()
2119
        except errors.RadioError:
2120
            raise
2121
        except Exception as e:
2122
            raise errors.RadioError("Failed to communicate with radio: %s" % e)
2123
        return
2124

    
2125
    def _do_upload(self):
2126
        if self._RADIO_ID == self._model:
2127
            LOG.debug("Starting Upload")
2128
            if self.show_limits:
2129
                cfgmap = Q10H_upload_map
2130
            else:
2131
                cfgmap = Q10H_upload_map_nolims
2132

    
2133
            for (radioaddress, radioend, start, memend,
2134
                 blocksize, count) in cfgmap:
2135
                end = start + (blocksize * count)
2136
                LOG.debug("start = " + str(start))
2137
                LOG.debug("end = " + str(end))
2138
                LOG.debug("blksize = " + str(blocksize))
2139
                ptr2 = radioaddress
2140

    
2141
                for addr in range(start, end, blocksize):
2142
                    ptr = addr
2143
                    LOG.debug("ptr = " + str(hex(ptr)))
2144
                    LOG.debug("ptr2 = " + str(hex(ptr2)))
2145
                    req = struct.pack('>H', ptr2)
2146
                    chunk = self.get_mmap()[ptr:ptr + blocksize]
2147
                    self._write_record(CMD_WR, req + chunk)
2148
                    LOG.debug(util.hexprint(req + chunk))
2149
                    cserr, ack = self._read_record()
2150
                    LOG.debug(util.hexprint(ack))
2151
                    j = struct.unpack('>H', ack)[0]
2152
                    if cserr or j != ptr2:
2153
                        LOG.debug(util.hexprint(ack))
2154
                        raise Exception("Checksum Error on Ack at %i" % ptr)
2155
                    ptr += blocksize
2156
                    ptr2 += blocksize
2157
                    if self.status_fn:
2158
                        status = chirp_common.Status()
2159
                        status.cur = ptr
2160
                        status.max = 0x8000
2161
                        status.msg = "Cloning to radio"
2162
                        self.status_fn(status)
2163
            # fix for errant upload to radio address 0x100 in beta 2.0 driver
2164
            # this writes the correct data back to the radio
2165
            # consider removing for production
2166
            # if self._RADIO_ID == b"KG-Q10H":
2167
            #     fix = struct.pack('>H64B', 0x0100, 0x00, 0x00, 0x00, 0x00,
2168
            #                       0x00, 0x00,
2169
            #                       0x00, 0x00, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
2170
            #                       0xDD, 0xDD, 0xDD,
2171
            #                       0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
2172
            #                       0xDD, 0x28, 0x32,
2173
            #                       0x3D, 0x49, 0x57, 0x00, 0x00, 0x00, 0x00,
2174
            #                       0x00, 0x00, 0x00,
2175
            #                       0x00, 0x00, 0x00, 0x00, 0xDD, 0xDD, 0xDD,
2176
            #                       0xDD, 0xDD, 0xDD,
2177
            #                       0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
2178
            #                       0xDD, 0xDD, 0xDD,
2179
            #                       0x40, 0x7A, 0x41, 0x04, 0x13, 0x17, 0x20,
2180
            #                       0x31)
2181
            #     self._write_record(CMD_WR, fix)
2182
            #     time.sleep(0.02)
2183
            LOG.debug("Upload Completed")
2184
        else:
2185
            raise errors.RadioError("Radio is not a KG-Q10H. Upload Canceled")
2186

    
2187
        self._finish()
2188

    
2189
    def get_features(self):
2190
        rf = chirp_common.RadioFeatures()
2191
        rf.has_settings = True
2192
        rf.has_ctone = True
2193
        rf.has_rx_dtcs = True
2194
        rf.has_cross = True
2195
        rf.has_tuning_step = False
2196
        rf.has_bank = False
2197
        rf.can_odd_split = True
2198
        rf.valid_skips = ["", "S"]
2199
        rf.valid_tmodes = ["", "Tone", "TSQL", "DTCS", "Cross"]
2200
        rf.valid_cross_modes = [
2201
            "Tone->Tone",
2202
            "Tone->DTCS",
2203
            "DTCS->Tone",
2204
            "DTCS->",
2205
            "->Tone",
2206
            "->DTCS",
2207
            "DTCS->DTCS",
2208
        ]
2209
        rf.valid_modes = ["FM", "NFM", "AM"]
2210
        rf.valid_power_levels = self.POWER_LEVELS
2211
        rf.valid_name_length = 12
2212
        rf.valid_duplexes = ["", "-", "+", "split", "off"]
2213
        rf.valid_bands = [(50000000, 54997500),    # 6m
2214
                          (108000000, 174997500),  # AM Airband and VHF
2215
                          (222000000, 225997500),  # 1.25M
2216
                          (320000000, 479997500),  # UHF
2217
                          (714000000, 999997500)]  # Fixed Land Mobile
2218

    
2219
        rf.valid_characters = chirp_common.CHARSET_ASCII
2220
        rf.memory_bounds = (1, 999)  # 999 memories
2221
        rf.valid_tuning_steps = STEPS2
2222
        return rf
2223

    
2224
    @classmethod
2225
    def get_prompts(cls):
2226
        rp = chirp_common.RadioPrompts()
2227
        rp.experimental = \
2228
            ('THIS DRIVER IS BETA 2.x - ''\n'
2229
             'DO NOT USE SAVED IMG FILES FROM''\n'
2230
             'BETA 1.x DRIVER WITH BETA 2.x TO UPLOAD TO RADIO''\n'
2231
             'DOWNLOAD FROM RADIO WITH BETA 2.x FIRST THEN MODIFY'
2232
             ' AND UPLOAD''\n'
2233
             'This driver is experimental.  USE AT YOUR OWN RISK\n'
2234
             '\n'
2235
             'Please save a copy of the image from your radio with Chirp '
2236
             'before modifying any values.\n'
2237
             '\n'
2238
             'Please keep a copy of your memories with the original Wouxon'
2239
             'CPS software if you treasure them, this driver is new and '
2240
             'may contain bugs.\n'
2241
             )
2242
        # rp.pre_download = _(
2243
        #     "Please ensure you have selected the correct radio driver\n")
2244
        rp.pre_upload = (
2245
            "WARNING: THIS DRIVER IS BETA 2.x\n"
2246
            "\n"
2247
            "UPLOADS REQUIRE the use of Beta 2.x Radio img files. \n"
2248
            "DO NOT USE Radio Image files from Beta 1.x"
2249
            " to upload to radio.  \n"
2250
            "It will cause incorrect settings on the radio.\n"
2251
            "\n"
2252
            "Please DOWNLOAD FROM RADIO with this driver"
2253
            " to get a Beta 2.x img file\n"
2254
            "for use BEFORE UPLOADING anything with this driver.\n"
2255
            "CANCEL the Upload if you are using a Beta 1.x img \n"
2256
            "Continue if you are using a Beta 2.x img file. \n"
2257
            "\n"
2258
            "If you don't know the img version...\n"
2259
            "The driver will try a check to confirm.\n"
2260
            "If it fails the check - Do a DOWNLOAD FROM RADIO then try again.")
2261
        return rp
2262

    
2263
    def get_raw_memory(self, number):
2264
        return repr(self._memobj.memory[number])
2265

    
2266
    def _get_tone(self, _mem, mem):
2267
        # MRT - Chirp Uses N for n DCS Tones and R for i DCS Tones
2268
        def _get_dcs(val):
2269
            code = int("%03o" % (val & 0x07FF))
2270
            pol = (val & 0x2000) and "R" or "N"
2271
            return code, pol
2272
        tpol = False
2273
        if _mem.txtone != 0xFFFF and (_mem.txtone & 0x4000) == 0x4000:
2274
            tcode, tpol = _get_dcs(_mem.txtone)
2275
            mem.dtcs = tcode
2276
            txmode = "DTCS"
2277
        elif _mem.txtone != 0xFFFF and _mem.txtone != 0x0:
2278
            mem.rtone = (_mem.txtone & 0x7fff) / 10.0
2279
            txmode = "Tone"
2280
        else:
2281
            txmode = ""
2282
        rpol = False
2283
        if _mem.rxtone != 0xFFFF and (_mem.rxtone & 0x4000) == 0x4000:
2284
            rcode, rpol = _get_dcs(_mem.rxtone)
2285
            mem.rx_dtcs = rcode
2286
            rxmode = "DTCS"
2287
        elif _mem.rxtone != 0xFFFF and _mem.rxtone != 0x0:
2288
            mem.ctone = (_mem.rxtone & 0x7fff) / 10.0
2289
            rxmode = "Tone"
2290
        else:
2291
            rxmode = ""
2292

    
2293
        if txmode == "Tone" and not rxmode:
2294
            mem.tmode = "Tone"
2295
        elif txmode == rxmode and txmode == "Tone" and mem.rtone == mem.ctone:
2296
            mem.tmode = "TSQL"
2297
        elif txmode == rxmode and txmode == "DTCS" and mem.dtcs == mem.rx_dtcs:
2298
            mem.tmode = "DTCS"
2299
        elif rxmode or txmode:
2300
            mem.tmode = "Cross"
2301
            mem.cross_mode = "%s->%s" % (txmode, rxmode)
2302

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

    
2306
        # LOG.debug("Got TX %s (%i) RX %s (%i)" %
2307
        #           (txmode, _mem.txtone, rxmode, _mem.rxtone))
2308

    
2309
    def get_memory(self, number):
2310
        _mem = self._memobj.memory[number]
2311
        _nam = self._memobj.names[number]
2312

    
2313
        mem = chirp_common.Memory()
2314
        mem.number = number
2315
        _valid = self._memobj.valid[mem.number]
2316
        LOG.debug("Channel %d Valid = %s", number, _valid == MEM_VALID)
2317
        if _valid != MEM_VALID:
2318
            mem.empty = True
2319
            return mem
2320
        else:
2321
            mem.empty = False
2322

    
2323
        mem.freq = int(_mem.rxfreq) * 10
2324

    
2325
        if (_mem.txfreq == 0xFFFFFFFF or _mem.txfreq == 0x00000000):
2326
            # TX freq not set
2327
            mem.duplex = "off"
2328
            mem.offset = 0
2329
        elif int(_mem.rxfreq) == int(_mem.txfreq):
2330
            mem.duplex = ""
2331
            mem.offset = 0
2332
        elif abs(int(_mem.rxfreq) * 10 - int(_mem.txfreq) * 10) > 70000000:
2333
            mem.duplex = "split"
2334
            mem.offset = int(_mem.txfreq) * 10
2335
        else:
2336
            mem.duplex = int(_mem.rxfreq) > int(_mem.txfreq) and "-" or "+"
2337
            mem.offset = abs(int(_mem.rxfreq) - int(_mem.txfreq)) * 10
2338

    
2339
        for char in _nam.name:
2340
            if char != 0:
2341
                mem.name += chr(char)
2342
            else:
2343
                # 0x00 in name indicates the end of the name.
2344
                # stop looking at next chars as Wouxun does not 
2345
                # always clear the remaining bytes
2346
                break
2347
        mem.name = mem.name.rstrip()
2348

    
2349
        mem.extra = RadioSettingGroup("Extra", "Extra")
2350
        rs = RadioSetting("mute_mode", "Mute Mode",
2351
                          RadioSettingValueList(
2352
                              SPMUTE_LIST, SPMUTE_LIST[_mem.mute_mode]))
2353
        mem.extra.append(rs)
2354
        rs = RadioSetting("scrambler", "Scramble Descramble",
2355
                          RadioSettingValueList(
2356
                              SCRAMBLE_LIST, SCRAMBLE_LIST[_mem.scrambler]))
2357
        mem.extra.append(rs)
2358
        rs = RadioSetting("compander", "Compander",
2359
                          RadioSettingValueList(
2360
                             ONOFF_LIST, ONOFF_LIST[_mem.compander]))
2361
        mem.extra.append(rs)
2362
    # if _mem.am_mode != 0:
2363
        rs = RadioSetting("am_mode", "AM Mode",
2364
                            RadioSettingValueMap(
2365
                                self.am_mode_list_ch, _mem.am_mode))
2366
        mem.extra.append(rs)
2367
        rs = RadioSetting("favorite", "Favorite",
2368
                          RadioSettingValueList(
2369
                             ONOFF_LIST, ONOFF_LIST[_mem.favorite]))
2370
        mem.extra.append(rs)
2371
        rs = RadioSetting("send_loc", "Send Location",
2372
                          RadioSettingValueList(
2373
                             ONOFF_LIST, ONOFF_LIST[_mem.send_loc]))
2374
        mem.extra.append(rs)
2375

    
2376
        if _mem.call_group == 0:
2377
            _mem.call_group = 1
2378
        rs = RadioSetting("call_group", "Call Group",
2379
                          RadioSettingValueMap(
2380
                             MAP_1_99, _mem.call_group))
2381
        mem.extra.append(rs)
2382

    
2383
        self._get_tone(_mem, mem)
2384

    
2385
        mem.skip = "" if bool(_mem.scan_add) else "S"
2386
        _mem.power = _mem.power & 0x3
2387
        if _mem.power > 3:
2388
            _mem.power = 3
2389
        mem.power = self.POWER_LEVELS[_mem.power]
2390
        if _mem.am_mode != 0:
2391
            mem.mode = "AM"
2392
        elif _mem.iswide:
2393
            mem.mode = "FM"
2394
        else:
2395
            mem.mode = "NFM"
2396
        return mem
2397

    
2398
    def _scan_grp(self):
2399
        """Scan groups
2400
        """
2401
        _settings = self._memobj.settings
2402

    
2403
        def apply_name(setting, obj):
2404
            name = str2name(setting.value, 12, '\0', '\0')
2405
            obj.name = name
2406

    
2407
        def apply_start(setting, obj):
2408
            """Do a callback to deal with RadioSettingInteger limitation
2409
            on memory address resolution
2410
            """
2411
            obj.scan_st = int(setting.value)
2412

    
2413
        def apply_end(setting, obj):
2414
            """Do a callback to deal with RadioSettingInteger limitation
2415
            on memory address resolution
2416
            """
2417
            obj.scan_end = int(setting.value)
2418

    
2419
        sgrp = self._memobj.scn_grps
2420
        scan = RadioSettingGroup("scn_grps", "Channel Scan Groups")
2421
        rs = RadioSetting("ScnGrpA_Act", "Scan Group A Active",
2422
                          RadioSettingValueList(SCANGRP_LIST,
2423
                                                SCANGRP_LIST[_settings.
2424
                                                             ScnGrpA_Act]))
2425
        scan.append(rs)
2426
        rs = RadioSetting("ScnGrpB_Act", "Scan Group B Active",
2427
                          RadioSettingValueList(SCANGRP_LIST,
2428
                                                SCANGRP_LIST[_settings.
2429
                                                             ScnGrpB_Act]))
2430
        scan.append(rs)
2431
        for i in range(0, 10):
2432
            s_grp = sgrp.addrs[i]
2433
            s_name = sgrp.names[i]
2434
            rs_name = RadioSettingValueString(0, 12,
2435
                                              name2str(s_name.name))
2436
            rs = RadioSetting("scn_grps.names[%i].name" % i,
2437
                              "Group %i Name" % (i + 1), rs_name)
2438
            rs.set_apply_callback(apply_name, s_name)
2439
            scan.append(rs)
2440
            rs_st = RadioSettingValueInteger(1, 999, s_grp.scan_st)
2441
            rs = RadioSetting("scn_grps.addrs[%i].scan_st" % i,
2442
                              "     Group %i Start Channel" % (i + 1), rs_st)
2443
            rs.set_apply_callback(apply_start, s_grp)
2444
            scan.append(rs)
2445
            rs_end = RadioSettingValueInteger(1, 999, s_grp.scan_end)
2446
            rs = RadioSetting("scn_grps.addrs[%i].scan_end" % i,
2447
                              "     Group %i End Channel" % (i + 1), rs_end)
2448
            rs.set_apply_callback(apply_end, s_grp)
2449
            scan.append(rs)
2450
        return scan
2451

    
2452
    def _set_tone(self, mem, _mem):
2453
        def _set_dcs(code, pol):
2454
            val = int("%i" % code, 8) | 0x4000
2455
            if pol == "R":
2456
                val += 0x2000
2457
            return val
2458

    
2459
        rx_mode = tx_mode = None
2460
        rxtone = txtone = 0x0000
2461

    
2462
        if mem.tmode == "Tone":
2463
            tx_mode = "Tone"
2464
            rx_mode = None
2465
            txtone = int(mem.rtone * 10) + 0x8000
2466
        elif mem.tmode == "TSQL":
2467
            rx_mode = tx_mode = "Tone"
2468
            rxtone = txtone = int(mem.ctone * 10) + 0x8000
2469
        elif mem.tmode == "DTCS":
2470
            tx_mode = rx_mode = "DTCS"
2471
            txtone = _set_dcs(mem.dtcs, mem.dtcs_polarity[0])
2472
            rxtone = _set_dcs(mem.dtcs, mem.dtcs_polarity[1])
2473
        elif mem.tmode == "Cross":
2474
            tx_mode, rx_mode = mem.cross_mode.split("->")
2475
            if tx_mode == "DTCS":
2476
                txtone = _set_dcs(mem.dtcs, mem.dtcs_polarity[0])
2477
            elif tx_mode == "Tone":
2478
                txtone = int(mem.rtone * 10) + 0x8000
2479
            if rx_mode == "DTCS":
2480
                rxtone = _set_dcs(mem.rx_dtcs, mem.dtcs_polarity[1])
2481
            elif rx_mode == "Tone":
2482
                rxtone = int(mem.ctone * 10) + 0x8000
2483

    
2484
        _mem.rxtone = rxtone
2485
        _mem.txtone = txtone
2486

    
2487
        LOG.debug("Set TX %s (%i) RX %s (%i)" %
2488
                  (tx_mode, _mem.txtone, rx_mode, _mem.rxtone))
2489

    
2490
    def set_memory(self, mem):
2491
        number = mem.number
2492

    
2493
        _mem = self._memobj.memory[number]
2494
        _nam = self._memobj.names[number]
2495

    
2496
        if mem.empty:
2497
            _mem.set_raw("\x00" * (_mem.size() // 8))
2498
            self._memobj.valid[number] = 0
2499
            self._memobj.names[number].set_raw("\x00" * (_nam.size() // 8))
2500
            return
2501

    
2502
        _mem.rxfreq = int(mem.freq / 10)
2503
        if mem.duplex == "off":
2504
            # _mem.txfreq = 0xFFFFFFFF
2505
            _mem.txfreq = 0x00000000
2506
        elif mem.duplex == "split":
2507
            _mem.txfreq = int(mem.offset / 10)
2508
        elif mem.duplex == "off":
2509
            for i in range(0, 4):
2510
                _mem.txfreq[i].set_raw("\xFF")
2511
        elif mem.duplex == "+":
2512
            _mem.txfreq = int(mem.freq / 10) + int(mem.offset / 10)
2513
        elif mem.duplex == "-":
2514
            _mem.txfreq = int(mem.freq / 10) - int(mem.offset / 10)
2515
        else:
2516
            _mem.txfreq = int(mem.freq / 10)
2517
        _mem.scan_add = int(mem.skip != "S")
2518
        if ((mem.mode == "FM") or (mem.mode == "NFM")):
2519
            _mem.iswide = int((mem.mode == "FM"))
2520
            _mem.am_mode = 0
2521
        elif mem.mode == "AM":
2522
            _mem.am_mode = 1
2523
            #  Q10H radio only supports wide AM mode
2524
            _mem.iswide = 1
2525
        # set the tone
2526
        self._set_tone(mem, _mem)
2527

    
2528
        # set the power
2529
        _mem.power = _mem.power & 0x3
2530
        if mem.power:
2531
            if _mem.power > 3:
2532
                _mem.power = 3
2533
            _mem.power = self.POWER_LEVELS.index(mem.power)
2534
        else:
2535
            _mem.power = True
2536

    
2537
        for setting in mem.extra:
2538
            if setting.get_name() != "am_mode":
2539
                setattr(_mem, setting.get_name(), setting.value)
2540
            else:
2541
                if mem.mode != "AM":
2542
                    setattr(_mem, setting.get_name(), 0)
2543
                elif int(setting.value) == 2:
2544
                    setattr(_mem, setting.get_name(), 2)
2545
                elif int(setting.value) == 1:
2546
                    setattr(_mem, setting.get_name(), 1)
2547

    
2548
        for i in range(0, len(_nam.name)):
2549
            if i < len(mem.name) and mem.name[i]:
2550
                _nam.name[i] = ord(mem.name[i])
2551
            else:
2552
                _nam.name[i] = 0x0
2553
        self._memobj.valid[mem.number] = MEM_VALID
2554

    
2555
    def _get_settings(self):
2556
        if self.use_color:
2557
            from chirp.settings import RadioSettingValueRGB
2558

    
2559
        _settings = self._memobj.settings
2560
        _vfoa = self._memobj.vfoa
2561
        _vfob = self._memobj.vfob
2562
        _vfo_scan = self._memobj.vfo_scan
2563
        # _callname = self._memobj.call_names
2564
        _fm = self._memobj.fm
2565
        scan_grp = self._scan_grp()
2566
        _oem = self._memobj.oem_info
2567
        firmware_rev = str(_oem.firmware)
2568
        # release of Q10H Firmware VC1.02 includes 20K Step
2569
        LOG.debug("Firmware revision %s detected" % firmware_rev)
2570
        if firmware_rev not in (NO_20K_STEP_FIRMWARE):
2571
            steps = STEP2_LIST
2572
            LOG.debug("20K Step Included")
2573
        else:
2574
            steps = STEP_LIST
2575
            LOG.debug("20K Step NOT Included")
2576

    
2577
        cfg_grp = RadioSettingGroup("cfg_grp", "Config Settings")
2578
        if self.use_color:
2579
            cfg_grp[0] = RadioSettingGroup("color_grp", "Custom Theme Colors")
2580
        else:
2581
            cfg_grp[0] = RadioSettingGroup("color_grp",
2582
                                           "Custom Theme Colors (RGB565)")
2583
            cfg_grp[0][1] = RadioSettingGroup("color_grp",
2584
                                              "Integer value of RGB565 Color")
2585
            cfg_grp[0][2] = RadioSettingGroup("color_grp",
2586
                                              "Search- RGB565 Color Picker")
2587
        vfoa_grp = RadioSettingGroup("vfoa_grp", self.vfoa_grp_label)
2588
        vfoa_grp[0] = RadioSettingGroup("vfoa150_grp", "150M Settings")
2589
        vfoa_grp[1] = RadioSettingGroup("vfoa400_grp", "400M Settings")
2590
        vfoa_grp[2] = RadioSettingGroup("vfoa200_grp", "200M Settings")
2591
        vfoa_grp[3] = RadioSettingGroup("vfoa3_grp", self.vfoa3_msg)
2592
        vfoa_grp[4] = RadioSettingGroup("vfoa800_grp", "800M Settings")
2593
        vfoa_grp[5] = RadioSettingGroup("vfoa300_grp", "300M Settings")
2594
        vfob_grp = RadioSettingGroup("vfob_grp", self.vfob_grp_label)
2595
        vfob_grp[0] = RadioSettingGroup("vfob150_grp", "150M Settings")
2596
        vfob_grp[1] = RadioSettingGroup("vfob400_grp", "400M Settings")
2597
        key_grp = RadioSettingGroup("key_grp", "Key Settings")
2598
        fmradio_grp = RadioSettingGroup("fmradio_grp", "FM Broadcast Memory")
2599
        lmt_grp = RadioSettingGroup("lmt_grp", "Frequency Limits")
2600
        lmt_grp[0] = RadioSettingGroup("lmt_grp", "TX Limits")
2601
        lmt_grp[1] = RadioSettingGroup("lmt_grp", "RX Limits")
2602
        oem_grp = RadioSettingGroup("oem_grp", "OEM Info")
2603
        scanv_grp = RadioSettingGroup("scnv_grp", "VFO Scan Mode")
2604
        call_grp = RadioSettingGroup("call_grp", "Call Group Settings")
2605

    
2606
        if self.show_limits:
2607
            group = RadioSettings(cfg_grp, vfoa_grp,  vfob_grp,
2608
                                  fmradio_grp, key_grp, scan_grp, scanv_grp,
2609
                                  call_grp, lmt_grp, oem_grp)
2610
        else:
2611
            group = RadioSettings(cfg_grp, vfoa_grp,  vfob_grp,
2612
                                  fmradio_grp, key_grp, scan_grp, scanv_grp,
2613
                                  call_grp, oem_grp)
2614

    
2615
#         # Call Settings
2616

    
2617
        def apply_callid(setting, obj):
2618
            c = str2callid(setting.value)
2619
            obj.cid = c
2620

    
2621
        for i in range(1, 100):
2622
            call = self._memobj.call_names[i].call_name
2623
            _msg = str(call).split("\0")[0]
2624
            val = RadioSettingValueString(0, 12, _msg)
2625
            val.set_mutable(True)
2626
            rs = RadioSetting("call_names[%i].call_name" % i,
2627
                              "Call Name %i" % i, val)
2628
            call_grp.append(rs)
2629

    
2630
            callid = self._memobj.call_ids[i]
2631
            c_id = RadioSettingValueString(0, 6,
2632
                                           self.callid2str(callid.cid),
2633
                                           False)
2634
            rs = RadioSetting("call_ids[%i].cid" % i,
2635
                              "     Call Code %s" % str(i), c_id)
2636
            rs.set_apply_callback(apply_callid, callid)
2637
            call_grp.append(rs)
2638

    
2639
        # Configuration Settings
2640
        #
2641
        rs = RadioSetting("channel_menu", "Menu available in channel mode",
2642
                          RadioSettingValueBoolean(_settings.channel_menu))
2643
        cfg_grp.append(rs)
2644
        rs = RadioSetting("power_save", "Battery Saver - menu 4",
2645
                          RadioSettingValueBoolean(_settings.power_save))
2646
        cfg_grp.append(rs)
2647
        rs = RadioSetting("wxalert", "Weather Alert - menu 5",
2648
                          RadioSettingValueBoolean(_settings.wxalert))
2649
        cfg_grp.append(rs)
2650
        rs = RadioSetting("wxalert_type",
2651
                          "Weather Alert Notification - menu 6",
2652
                          RadioSettingValueList(WX_TYPE,
2653
                                                WX_TYPE[_settings.
2654
                                                        wxalert_type]))
2655
        cfg_grp.append(rs)
2656
        rs = RadioSetting("roger_beep", "Roger Beep - menu 13",
2657
                          RadioSettingValueList(ROGER_LIST,
2658
                                                ROGER_LIST[_settings.
2659
                                                           roger_beep]))
2660
        cfg_grp.append(rs)
2661
        rs = RadioSetting("timeout", "Timeout Timer (TOT) - menu 14",
2662
                          RadioSettingValueList(
2663
                              TIMEOUT_LIST, TIMEOUT_LIST[_settings.timeout]))
2664
        cfg_grp.append(rs)
2665
        rs = RadioSetting("toalarm", "Timeout Pre-Alert (TOA) - menu 15",
2666
                          RadioSettingValueList(LIST_10S,
2667
                                                LIST_10S[_settings.toalarm]))
2668
        cfg_grp.append(rs)
2669
        rs = RadioSetting("vox", "VOX - menu 16",
2670
                          RadioSettingValueList(LIST_10,
2671
                                                LIST_10[_settings.vox]))
2672
        cfg_grp.append(rs)
2673
        rs = RadioSetting("voice", "Voice Guide - menu 17",
2674
                          RadioSettingValueBoolean(_settings.voice))
2675
        cfg_grp.append(rs)
2676
        rs = RadioSetting("beep", "Keypad Beep - menu 18",
2677
                          RadioSettingValueBoolean(_settings.beep))
2678
        cfg_grp.append(rs)
2679
        rs = RadioSetting("scan_rev", "Scan Mode - menu 8",
2680
                          RadioSettingValueList(SCANMODE_LIST,
2681
                                                SCANMODE_LIST[_settings.
2682
                                                              scan_rev]))
2683
        cfg_grp.append(rs)
2684
        rs = RadioSetting("backlight", "Backlight Active Time - menu 3",
2685
                          RadioSettingValueList(BACKLIGHT_LIST,
2686
                                                BACKLIGHT_LIST[_settings.
2687
                                                               backlight]))
2688
        cfg_grp.append(rs)
2689

    
2690
        rs = RadioSetting("DspBrtAct", "Display Brightness ACTIVE - menu 1",
2691
                          RadioSettingValueMap(DSPBRTACT_MAP,
2692
                                               _settings.DspBrtAct))
2693
        cfg_grp.append(rs)
2694
        rs = RadioSetting("DspBrtSby", "Display Brightness STANDBY - menu 2",
2695
                          RadioSettingValueList(
2696
                              DSPBRTSBY_LIST, DSPBRTSBY_LIST[
2697
                                  _settings.DspBrtSby]))
2698
        cfg_grp.append(rs)
2699

    
2700
        rs = RadioSetting("theme", "Theme - menu 7",
2701
                          RadioSettingValueList(
2702
                              self.themelist,
2703
                              self.themelist[_settings.theme]))
2704
        cfg_grp.append(rs)
2705
        rs = RadioSetting("ponmsg", "Startup Display - menu 27",
2706
                          RadioSettingValueList(
2707
                               PONMSG_LIST, PONMSG_LIST[_settings.ponmsg]))
2708
        cfg_grp.append(rs)
2709
        rs = RadioSetting("batt_ind", "Battery Indicator - menu 39",
2710
                          RadioSettingValueList(
2711
                               BATT_DISP_LIST,
2712
                               BATT_DISP_LIST[_settings.batt_ind]))
2713
        cfg_grp.append(rs)
2714
        rs = RadioSetting("ptt_id", self.idtx_msg,
2715
                          RadioSettingValueList(PTTID_LIST,
2716
                                                PTTID_LIST[_settings.ptt_id]))
2717
        cfg_grp.append(rs)
2718
        rs = RadioSetting("ptt_delay", self.pttdly_msg,
2719
                          RadioSettingValueMap(PTTDELAY_TIMES,
2720
                                               _settings.ptt_delay))
2721
        cfg_grp.append(rs)
2722

    
2723
        rs = RadioSetting("dtmf_st", "DTMF Sidetone - menu 31",
2724
                          RadioSettingValueList(DTMFST_LIST,
2725
                                                DTMFST_LIST[_settings.
2726
                                                            dtmf_st]))
2727
        cfg_grp.append(rs)
2728
        rs = RadioSetting("dtmf_tx_time", "DTMF Transmit Time",
2729
                          RadioSettingValueMap(DTMF_TIMES,
2730
                                               _settings.dtmf_tx_time))
2731
        cfg_grp.append(rs)
2732
        rs = RadioSetting("dtmf_interval", "DTMF Interval Time",
2733
                          RadioSettingValueMap(DTMF_TIMES,
2734
                                               _settings.dtmf_interval))
2735
        cfg_grp.append(rs)
2736
        rs = RadioSetting("ring_time", "Ring Time - menu 35",
2737
                          RadioSettingValueList(LIST_10S,
2738
                                                LIST_10S[_settings.ring_time]))
2739
        cfg_grp.append(rs)
2740
        rs = RadioSetting("alert", "Alert Tone - menu 36",
2741
                          RadioSettingValueList(ALERTS_LIST,
2742
                                                ALERTS_LIST[_settings.alert]))
2743
        cfg_grp.append(rs)
2744

    
2745
        rs = RadioSetting("autolock", "Autolock - menu 30",
2746
                          RadioSettingValueBoolean(_settings.autolock))
2747
        cfg_grp.append(rs)
2748

    
2749
        rs = RadioSetting("prich_sw", "Priority Channel Scan - menu 11",
2750
                          RadioSettingValueList(PRICHAN_LIST,
2751
                                                PRICHAN_LIST[
2752
                                                    _settings.prich_sw]))
2753
        cfg_grp.append(rs)
2754
        rs = RadioSetting("pri_ch",
2755
                          "Priority Channel - Can not be empty Channel",
2756
                          RadioSettingValueInteger(1, 999, _settings.pri_ch))
2757
        cfg_grp.append(rs)
2758

    
2759
        if self.MODEL == "KG-Q10H":
2760
            rs = RadioSetting("rpttype", "Repeater Type - menu 40",
2761
                              RadioSettingValueMap(RPTTYPE_MAP,
2762
                                                   _settings.rpttype))
2763
            cfg_grp.append(rs)
2764

    
2765
            rs = RadioSetting("rpt_spk", "Repeater SPK - menu 41",
2766
                              RadioSettingValueBoolean(_settings.rpt_spk))
2767
            cfg_grp.append(rs)
2768

    
2769
            rs = RadioSetting("rpt_ptt", "Repeater PTT - menu 42",
2770
                              RadioSettingValueBoolean(_settings.rpt_ptt))
2771
            cfg_grp.append(rs)
2772

    
2773
        rs = RadioSetting("rpt_tone",
2774
                          "Repeater Tone - menu %i" % self.rpttonemenu,
2775
                          RadioSettingValueBoolean(_settings.rpt_tone))
2776
        cfg_grp.append(rs)
2777
        rs = RadioSetting("rpt_hold", "RPT Hold Time",
2778
                          RadioSettingValueList(
2779
                               HOLD_TIMES, HOLD_TIMES[_settings.rpt_hold]))
2780
        cfg_grp.append(rs)
2781
        rs = RadioSetting("scan_det", "Scan Mode Tone Detect - menu 9",
2782
                          RadioSettingValueBoolean(_settings.scan_det))
2783
        cfg_grp.append(rs)
2784
        rs = RadioSetting("ToneScnSave", "Tone Scan Save - menu 12",
2785
                          RadioSettingValueList(TONESCANSAVELIST,
2786
                                                TONESCANSAVELIST[_settings.
2787
                                                                 ToneScnSave]))
2788
        cfg_grp.append(rs)
2789
        rs = RadioSetting("smuteset", "Sub-Freq Mute (SMUTESET) - menu 38",
2790
                          RadioSettingValueList(SMUTESET_LIST,
2791
                                                SMUTESET_LIST[_settings.
2792
                                                              smuteset]))
2793
        cfg_grp.append(rs)
2794
        # rs = RadioSetting("ani_sw", ani_msg,
2795
        #                   RadioSettingValueBoolean(_settings.ani_sw))
2796
        # cfg_grp.append(rs)
2797

    
2798
#             rs = RadioSetting("sim_rec", "Simultaneous Receive",
2799
#                               RadioSettingValueBoolean(_settings.sim_rec))
2800
#             cfg_grp.append(rs)
2801

    
2802
        rs = RadioSetting("disp_time",
2803
                          "Display Time - menu %i" % self.timemenu,
2804
                          RadioSettingValueBoolean(_settings.disp_time))
2805
        cfg_grp.append(rs)
2806
        rs = RadioSetting("time_zone", "Time Zone - menu %i" % self.tzmenu,
2807
                          RadioSettingValueList(
2808
                              TIME_ZONE,
2809
                              TIME_ZONE[_settings.time_zone]))
2810
        cfg_grp.append(rs)
2811
        rs = RadioSetting("GPS", "GPS - menu %i.1" % self.locmenu,
2812
                          RadioSettingValueBoolean(_settings.GPS))
2813
        cfg_grp.append(rs)
2814
        rs = RadioSetting("GPS_send_freq",
2815
                          "GPS Send Frequency - menu %i.2" % self.locmenu,
2816
                          RadioSettingValueList(
2817
                              GPS_SEND_FREQ,
2818
                              GPS_SEND_FREQ[_settings.GPS_send_freq]))
2819
        cfg_grp.append(rs)
2820
        rs = RadioSetting("GPS_rcv", "GPS Receive - menu %i.3" % self.locmenu,
2821
                          RadioSettingValueBoolean(_settings.GPS_rcv))
2822
        cfg_grp.append(rs)
2823

    
2824
        rs = RadioSetting("stopwatch", "Timer / Stopwatch Enabled - menu 37",
2825
                          RadioSettingValueBoolean(_settings.stopwatch))
2826
        cfg_grp.append(rs)
2827
        rs = RadioSetting("keylock", "Keypad Locked",
2828
                          RadioSettingValueBoolean(_settings.keylock))
2829
        cfg_grp.append(rs)
2830

    
2831
        rs = RadioSetting("act_area", "Active Area",
2832
                          RadioSettingValueList(
2833
                              ACTIVE_AREA_LIST,
2834
                              ACTIVE_AREA_LIST[_settings.act_area]))
2835
        cfg_grp.append(rs)
2836
        rs = RadioSetting("tdr", "TDR",
2837
                          RadioSettingValueList(
2838
                              TDR_LIST,
2839
                              TDR_LIST[_settings.tdr]))
2840
        cfg_grp.append(rs)
2841

    
2842
        pswdchars = "0123456789"
2843
        _msg = str(_settings.mode_sw_pwd).split("\0")[0]
2844
        val = RadioSettingValueString(0, 6, _msg, False)
2845
        val.set_mutable(True)
2846
        val.set_charset(pswdchars)
2847
        rs = RadioSetting("mode_sw_pwd", "Mode SW Pwd", val)
2848
        cfg_grp.append(rs)
2849

    
2850
        _msg = str(_settings.reset_pwd).split("\0")[0]
2851
        val = RadioSettingValueString(0, 6, _msg, False)
2852
        val.set_charset(pswdchars)
2853
        val.set_mutable(True)
2854
        rs = RadioSetting("reset_pwd", "Reset Pwd", val)
2855
        cfg_grp.append(rs)
2856
#         Custom Color Settings
2857
        if self.use_color:
2858
            val = RadioSettingValueRGB.from_rgb16(_settings.custcol1_text)
2859
            rs = RadioSetting("settings.custcol1_text", "Custom 1 - Text",
2860
                              val)
2861
            cfg_grp[0].append(rs)
2862
            val = RadioSettingValueRGB.from_rgb16(_settings.custcol1_bg)
2863
            rs = RadioSetting("settings.custcol1_bg", "Custom 1 - Background",
2864
                              val)
2865
            cfg_grp[0].append(rs)
2866
            val = RadioSettingValueRGB.from_rgb16(_settings.custcol1_icon)
2867
            rs = RadioSetting("settings.custcol1_icon", "Custom 1 - Icon",
2868
                              val)
2869
            cfg_grp[0].append(rs)
2870
            val = RadioSettingValueRGB.from_rgb16(_settings.custcol1_line)
2871
            rs = RadioSetting("settings.custcol1_line", "Custom 1 - Line",
2872
                              val)
2873
            cfg_grp[0].append(rs)
2874

    
2875
            val = RadioSettingValueRGB.from_rgb16(_settings.custcol2_text)
2876
            rs = RadioSetting("settings.custcol2_text", "     Custom 2 - Text",
2877
                              val)
2878
            cfg_grp[0].append(rs)
2879
            val = RadioSettingValueRGB.from_rgb16(_settings.custcol2_bg)
2880
            rs = RadioSetting("settings.custcol2_bg",
2881
                              "     Custom 2 - Background",
2882
                              val)
2883
            cfg_grp[0].append(rs)
2884
            val = RadioSettingValueRGB.from_rgb16(_settings.custcol2_icon)
2885
            rs = RadioSetting("settings.custcol2_icon", "     Custom 2 - Icon",
2886
                              val)
2887
            cfg_grp[0].append(rs)
2888
            val = RadioSettingValueRGB.from_rgb16(_settings.custcol2_line)
2889
            rs = RadioSetting("settings.custcol2_line", "     Custom 2 - Line",
2890
                              val)
2891
            cfg_grp[0].append(rs)
2892
            val = RadioSettingValueRGB.from_rgb16(_settings.custcol3_text)
2893
            rs = RadioSetting("settings.custcol3_text", "Custom 3 - Text",
2894
                              val)
2895
            cfg_grp[0].append(rs)
2896
            val = RadioSettingValueRGB.from_rgb16(_settings.custcol3_bg)
2897
            rs = RadioSetting("settings.custcol3_bg", "Custom 3 - Background",
2898
                              val)
2899
            cfg_grp[0].append(rs)
2900
            val = RadioSettingValueRGB.from_rgb16(_settings.custcol3_icon)
2901
            rs = RadioSetting("settings.custcol3_icon", "Custom 3 - Icon",
2902
                              val)
2903
            cfg_grp[0].append(rs)
2904
            val = RadioSettingValueRGB.from_rgb16(_settings.custcol3_line)
2905
            rs = RadioSetting("settings.custcol3_line", "Custom 3 - Line",
2906
                              val)
2907
            cfg_grp[0].append(rs)
2908
            val = RadioSettingValueRGB.from_rgb16(_settings.custcol4_text)
2909
            rs = RadioSetting("settings.custcol4_text",
2910
                              "     Custom 4 - Text",
2911
                              val)
2912
            cfg_grp[0].append(rs)
2913
            val = RadioSettingValueRGB.from_rgb16(_settings.custcol4_bg)
2914
            rs = RadioSetting("settings.custcol4_bg",
2915
                              "     Custom 4 - Background",
2916
                              val)
2917
            cfg_grp[0].append(rs)
2918
            val = RadioSettingValueRGB.from_rgb16(_settings.custcol4_icon)
2919
            rs = RadioSetting("settings.custcol4_icon",
2920
                              "     Custom 4 - Icon",
2921
                              val)
2922
            cfg_grp[0].append(rs)
2923
            val = RadioSettingValueRGB.from_rgb16(_settings.custcol4_line)
2924
            rs = RadioSetting("settings.custcol4_line",
2925
                              "     Custom 4 - Line",
2926
                              val)
2927
            cfg_grp[0].append(rs)
2928
        else:
2929
            rs = RadioSetting("settings.custcol1_text", "Custom 1 - Text",
2930
                              RadioSettingValueInteger(
2931
                                  0, 65535, _settings.custcol1_text))
2932
            cfg_grp[0].append(rs)
2933
            rs = RadioSetting("settings.custcol1_bg", "Custom 1 - Background",
2934
                              RadioSettingValueInteger(
2935
                                  0, 65535, _settings.custcol1_bg))
2936
            cfg_grp[0].append(rs)
2937
            rs = RadioSetting("settings.custcol1_icon", "Custom 1 - Icon",
2938
                              RadioSettingValueInteger(
2939
                                  0, 65535, _settings.custcol1_icon))
2940
            cfg_grp[0].append(rs)
2941
            rs = RadioSetting("settings.custcol1_line", "Custom 1 - Line",
2942
                              RadioSettingValueInteger(
2943
                                  0, 65535, _settings.custcol1_line))
2944
            cfg_grp[0].append(rs)
2945
            rs = RadioSetting("settings.custcol2_text", "Custom 2 - Text",
2946
                              RadioSettingValueInteger(
2947
                                  0, 65535, _settings.custcol2_text))
2948
            cfg_grp[0].append(rs)
2949
            rs = RadioSetting("settings.custcol2_bg", "Custom 2 - Background",
2950
                              RadioSettingValueInteger(
2951
                                  0, 65535, _settings.custcol1_bg))
2952
            cfg_grp[0].append(rs)
2953
            rs = RadioSetting("settings.custcol2_icon", "Custom 2 - Icon",
2954
                              RadioSettingValueInteger(
2955
                                  0, 65535, _settings.custcol1_icon))
2956
            cfg_grp[0].append(rs)
2957
            rs = RadioSetting("settings.custcol2_line", "Custom 2 - Line",
2958
                              RadioSettingValueInteger(
2959
                                  0, 65535, _settings.custcol2_line))
2960
            cfg_grp[0].append(rs)
2961
            rs = RadioSetting("settings.custcol3_text", "Custom 3 - Text",
2962
                              RadioSettingValueInteger(
2963
                                  0, 65535, _settings.custcol3_text))
2964
            cfg_grp[0].append(rs)
2965
            rs = RadioSetting("settings.custcol3_bg", "Custom 3 - Background",
2966
                              RadioSettingValueInteger(
2967
                                  0, 65535, _settings.custcol3_bg))
2968
            cfg_grp[0].append(rs)
2969
            rs = RadioSetting("settings.custcol3_icon", "Custom 3 - Icon",
2970
                              RadioSettingValueInteger(
2971
                                  0, 65535, _settings.custcol3_icon))
2972
            cfg_grp[0].append(rs)
2973
            rs = RadioSetting("settings.custcol3_line", "Custom 3 - Line",
2974
                              RadioSettingValueInteger(
2975
                                  0, 65535, _settings.custcol3_line))
2976
            cfg_grp[0].append(rs)
2977
            rs = RadioSetting("settings.custcol4_text", "Custom 4 - Text",
2978
                              RadioSettingValueInteger(
2979
                                  0, 65535, _settings.custcol4_text))
2980
            cfg_grp[0].append(rs)
2981
            rs = RadioSetting("settings.custcol4_bg", "Custom 4 - Background",
2982
                              RadioSettingValueInteger(
2983
                                  0, 65535, _settings.custcol4_bg))
2984
            cfg_grp[0].append(rs)
2985
            rs = RadioSetting("settings.custcol4_icon", "Custom 4 - Icon",
2986
                              RadioSettingValueInteger(
2987
                                  0, 65535, _settings.custcol4_icon))
2988
            cfg_grp[0].append(rs)
2989
            rs = RadioSetting("settings.custcol4_line", "Custom 4 - Line",
2990
                              RadioSettingValueInteger(
2991
                                  0, 65535, _settings.custcol4_line))
2992
            cfg_grp[0].append(rs)
2993

    
2994

    
2995
#         # Key Settings
2996
#         #
2997
        _msg = str(_settings.dispstr).split("\0")[0]
2998
        val = RadioSettingValueString(0, 12, _msg)
2999
        val.set_mutable(True)
3000
        rs = RadioSetting("dispstr",
3001
                          self.dispmesg, val)
3002
        key_grp.append(rs)
3003

    
3004
        def _decode(lst):
3005
            _str = ''.join([chr(int(c)) for c in lst
3006
                            if chr(int(c)) in chirp_common.CHARSET_ASCII])
3007
            return _str
3008

    
3009
        _str = _decode(self._memobj.settings.areamsg)
3010
        val = RadioSettingValueString(0, 12, _str)
3011
        val.set_mutable(True)
3012
        rs = RadioSetting("settings.areamsg", self.areamsglabel, val)
3013
        key_grp.append(rs)
3014

    
3015
        def apply_ani_id(setting, obj):
3016
            c = str2callid(setting.value)
3017
            obj.ani_id = c
3018

    
3019
        cid = self._memobj.settings
3020
        my_callid = RadioSettingValueString(3, 6,
3021
                                            self.callid2str(cid.ani_id),
3022
                                            False)
3023
        rs = RadioSetting("ani_id", "Radio ID", my_callid)
3024
        rs.set_apply_callback(apply_ani_id, cid)
3025
        key_grp.append(rs)
3026

    
3027
        stun = self._memobj.settings
3028
        st = RadioSettingValueString(0, 6, digits2str(stun.scc), False)
3029
        rs = RadioSetting("scc", "Control code", st)
3030
        rs.set_apply_callback(apply_scc, stun)
3031
        key_grp.append(rs)
3032

    
3033
        rs = RadioSetting("ptt1", "PTT1 Key function",
3034
                          RadioSettingValueList(
3035
                              PTT_LIST,
3036
                              PTT_LIST[_settings.ptt1]))
3037
        key_grp.append(rs)
3038
        rs = RadioSetting("ptt2", "PTT2 Key function",
3039
                          RadioSettingValueList(
3040
                              PTT_LIST,
3041
                              PTT_LIST[_settings.ptt2]))
3042
        key_grp.append(rs)
3043
        rs = RadioSetting("top_short", "TOP SHORT Key function",
3044
                          RadioSettingValueList(
3045
                              self._prog_key,
3046
                              self._prog_key[_settings.top_short]))
3047
        key_grp.append(rs)
3048
        rs = RadioSetting("top_long", "TOP LONG Key function",
3049
                          RadioSettingValueList(
3050
                              self._prog_key,
3051
                              self._prog_key[_settings.top_long]))
3052
        key_grp.append(rs)
3053

    
3054
        rs = RadioSetting("pf1_short", "PF1 SHORT Key function",
3055
                          RadioSettingValueList(
3056
                              self._prog_key,
3057
                              self._prog_key[_settings.pf1_short]))
3058
        key_grp.append(rs)
3059
        rs = RadioSetting("pf1_long", "PF1 LONG Key function",
3060
                          RadioSettingValueList(
3061
                              self._prog_key,
3062
                              self._prog_key[_settings.pf1_long]))
3063
        key_grp.append(rs)
3064
        rs = RadioSetting("pf2_short", "PF2 SHORT Key function",
3065
                          RadioSettingValueList(
3066
                              self._prog_key,
3067
                              self._prog_key[_settings.pf2_short]))
3068
        key_grp.append(rs)
3069
        rs = RadioSetting("pf2_long", "PF2 LONG Key function",
3070
                          RadioSettingValueList(
3071
                              self._prog_key,
3072
                              self._prog_key[_settings.pf2_long]))
3073
        key_grp.append(rs)
3074

    
3075
# #       SCAN GROUP settings
3076
        rs = RadioSetting("settings.vfo_scanmodea", "VFO A Scan Mode",
3077
                          RadioSettingValueList(
3078
                              VFO_SCANMODE_LIST,
3079
                              VFO_SCANMODE_LIST[_settings.vfo_scanmodea]))
3080
        scanv_grp.append(rs)
3081
        rs = RadioSetting("vfo_scan.vfo_scan_start_A",
3082
                          "     VFO A Scan Start (MHz)",
3083
                          RadioSettingValueInteger(
3084
                              1, 999, _vfo_scan.vfo_scan_start_A))
3085
        scanv_grp.append(rs)
3086
        rs = RadioSetting("vfo_scan.vfo_scan_end_A",
3087
                          "     VFO A Scan End (MHz)",
3088
                          RadioSettingValueInteger(
3089
                              1, 999, _vfo_scan.vfo_scan_end_A))
3090
        scanv_grp.append(rs)
3091
        rs = RadioSetting("settings.vfo_scanmodeb", "VFO B Scan Mode",
3092
                          RadioSettingValueList(
3093
                              VFO_SCANMODE_LIST,
3094
                              VFO_SCANMODE_LIST[_settings.vfo_scanmodeb]))
3095
        scanv_grp.append(rs)
3096
        rs = RadioSetting("vfo_scan.vfo_scan_start_B",
3097
                          "     VFO B Scan Start (MHz)",
3098
                          RadioSettingValueInteger(
3099
                              1, 999, _vfo_scan.vfo_scan_start_B))
3100
        scanv_grp.append(rs)
3101
        rs = RadioSetting("vfo_scan.vfo_scan_end_B",
3102
                          "     VFO B Scan End (MHz)",
3103
                          RadioSettingValueInteger(
3104
                              1, 999, _vfo_scan.vfo_scan_end_B))
3105
        scanv_grp.append(rs)
3106

    
3107
        # VFO A Settings
3108
        #
3109
        wml = self.workmodelist
3110
        rs = RadioSetting("work_mode_a", self.vfo_area + "A Workmode",
3111
                          RadioSettingValueList(wml,
3112
                                                wml[_settings.work_mode_a]))
3113
        vfoa_grp.append(rs)
3114
        rs = RadioSetting("work_ch_a", self.vfo_area + "A Work Channel",
3115
                          RadioSettingValueInteger(1, 999,
3116
                                                   _settings.work_ch_a))
3117
        vfoa_grp.append(rs)
3118
        for i in range(0, 6):
3119
            rs = RadioSetting("vfoa[%i].rxfreq" % i,
3120
                              self.vfo_area + "A Rx Frequency (MHz)",
3121
                              RadioSettingValueFloat(
3122
                                  0.00000, 999.999999,
3123
                                  (_vfoa[i].rxfreq / 100000.0),
3124
                                  0.000001, 6))
3125
            vfoa_grp[i].append(rs)
3126
            if self.MODEL == "KG-Q10H":
3127
                rs = RadioSetting("vfoa[%i].offset" % i,
3128
                                  self.vfo_area + "A Offset (MHz)",
3129
                                  RadioSettingValueFloat(
3130
                                      0.00000, 599.999999,
3131
                                      (_vfoa[i].offset / 100000.0),
3132
                                      0.000001, 6))
3133
                vfoa_grp[i].append(rs)
3134

    
3135
            rs = RadioSetting("vfoa[%i].rxtone" % i,
3136
                              self.vfo_area + "A Rx tone",
3137
                              RadioSettingValueMap(
3138
                                TONE_MAP, _vfoa[i].rxtone))
3139
            vfoa_grp[i].append(rs)
3140
            rs = RadioSetting("vfoa[%i].txtone" % i,
3141
                              self.vfo_area + "A Tx tone",
3142
                              RadioSettingValueMap(
3143
                                  TONE_MAP, _vfoa[i].txtone))
3144
            vfoa_grp[i].append(rs)
3145

    
3146
#         # MRT - AND power with 0x03 to display only the lower 2 bits for
3147
#         # power level and to clear the upper bits
3148
#         # MRT - any bits set in the upper 2 bits will cause radio to show
3149
#         # invalid values for power level and a display glitch
3150
#         # MRT - when PTT is pushed
3151
            _vfoa[i].power = _vfoa[i].power & 0x3
3152
            if _vfoa[i].power > 3:
3153
                _vfoa[i].power = 3
3154
            rs = RadioSetting("vfoa[%i].power" % i, self.vfo_area + "A Power",
3155
                              RadioSettingValueList(
3156
                                  POWER_LIST, POWER_LIST[_vfoa[i].power]))
3157
            vfoa_grp[i].append(rs)
3158
            rs = RadioSetting("vfoa[%i].iswide" % i,
3159
                              self.vfo_area + "A Wide/Narrow",
3160
                              RadioSettingValueList(
3161
                                  BANDWIDTH_LIST,
3162
                                  BANDWIDTH_LIST[_vfoa[i].iswide]))
3163
            vfoa_grp[i].append(rs)
3164
            rs = RadioSetting("vfoa[%i].mute_mode" % i,
3165
                              self.vfo_area + "A Mute (SP Mute)",
3166
                              RadioSettingValueList(
3167
                                  SPMUTE_LIST,
3168
                                  SPMUTE_LIST[_vfoa[i].mute_mode]))
3169
            vfoa_grp[i].append(rs)
3170
            rs = RadioSetting("vfoa[%i].ofst_dir" % i,
3171
                              self.vfo_area + self._offset_dir_rpt_label,
3172
                              RadioSettingValueList(
3173
                                  self._offset_dir_rpt,
3174
                                  self._offset_dir_rpt[_vfoa[i].ofst_dir]))
3175
            vfoa_grp[i].append(rs)
3176
            rs = RadioSetting("vfoa[%i].scrambler" % i,
3177
                              self.vfo_area + "A Scramble/Descramble",
3178
                              RadioSettingValueList(
3179
                                  SCRAMBLE_LIST,
3180
                                  SCRAMBLE_LIST[_vfoa[i].scrambler]))
3181
            vfoa_grp[i].append(rs)
3182

    
3183
            rs = RadioSetting("vfoa[%i].compander" % i,
3184
                              self.vfo_area + "A Compander",
3185
                              RadioSettingValueList(
3186
                                  ONOFF_LIST, ONOFF_LIST[_vfoa[i].compander]))
3187
            vfoa_grp[i].append(rs)
3188
            rs = RadioSetting("vfoa[%i].call_group" % i,
3189
                              self.vfo_area + "A Call Group",
3190
                              RadioSettingValueInteger(
3191
                                  1, 99, _vfoa[i].call_group))
3192
            vfoa_grp[i].append(rs)
3193
            rs = RadioSetting("vfoa[%i].am_mode" % i,
3194
                              self.vfo_area + "A AM Mode",
3195
                              RadioSettingValueList(
3196
                                  self.am_mode_list,
3197
                                  self.am_mode_list[_vfoa[i].am_mode]))
3198
            vfoa_grp[i].append(rs)
3199

    
3200
        rs = RadioSetting("settings.vfostepA", self.vfo_area + "A Step (kHz)",
3201
                          RadioSettingValueList(
3202
                              steps, steps[_settings.vfostepA]))
3203
        vfoa_grp.append(rs)
3204
        rs = RadioSetting("settings.squelchA", self.vfo_area + "A Squelch",
3205
                          RadioSettingValueList(
3206
                              LIST_10, LIST_10[_settings.squelchA]))
3207
        vfoa_grp.append(rs)
3208
        rs = RadioSetting("BCL_A", "Busy Channel Lock-out A",
3209
                          RadioSettingValueBoolean(_settings.BCL_A))
3210
        vfoa_grp.append(rs)
3211
        rs = RadioSetting("settings.vfobandA", "VFO A Current Band",
3212
                          RadioSettingValueMap(self._vfoaband,
3213
                                               _settings.vfobandA))
3214
        vfoa_grp.append(rs)
3215

    
3216
#         # VFO B Settings
3217
        wml = self.workmodelist
3218
        rs = RadioSetting("work_mode_b", self.vfo_area + "B Workmode",
3219
                          RadioSettingValueList(wml,
3220
                                                wml[_settings.work_mode_b]))
3221
        vfob_grp.append(rs)
3222
        rs = RadioSetting("work_ch_b", self.vfo_area + "B Work Channel",
3223
                          RadioSettingValueInteger(1, 999,
3224
                                                   _settings.work_ch_b))
3225
        vfob_grp.append(rs)
3226
        for i in range(0, 2):
3227
            rs = RadioSetting("vfob[%i].rxfreq" % i,
3228
                              self.vfo_area + "B Rx Frequency (MHz)",
3229
                              RadioSettingValueFloat(
3230
                                  0.00000, 999.999999,
3231
                                  (_vfob[i].rxfreq / 100000.0),
3232
                                  0.000001, 6))
3233
            vfob_grp[i].append(rs)
3234
            if self.MODEL == "KG-Q10H":
3235
                rs = RadioSetting("vfob[%i].offset" % i,
3236
                                  self.vfo_area + "B Offset (MHz)",
3237
                                  RadioSettingValueFloat(
3238
                                      0.00000, 599.999999,
3239
                                      (_vfob[i].offset / 100000.0),
3240
                                      0.000001, 6))
3241
                vfob_grp[i].append(rs)
3242

    
3243
            rs = RadioSetting("vfob[%i].rxtone" % i,
3244
                              self.vfo_area + "B Rx tone",
3245
                              RadioSettingValueMap(
3246
                                  TONE_MAP, _vfob[i].rxtone))
3247
            vfob_grp[i].append(rs)
3248
            rs = RadioSetting("vfob[%i].txtone" % i,
3249
                              self.vfo_area + "B Tx tone",
3250
                              RadioSettingValueMap(
3251
                                  TONE_MAP, _vfob[i].txtone))
3252
            vfob_grp[i].append(rs)
3253

    
3254
#         # MRT - AND power with 0x03 to display only the lower 2 bits for
3255
#         # power level and to clear the upper bits
3256
#         # MRT - any bits set in the upper 2 bits will cause radio to show
3257
#         # invalid values for power level and a display glitch
3258
#         # MRT - when PTT is pushed
3259
            _vfob[i].power = _vfob[i].power & 0x3
3260
            if _vfob[i].power > 3:
3261
                _vfob[i].power = 3
3262
            rs = RadioSetting("vfob[%i].power" % i,
3263
                              self.vfo_area + "B Power",
3264
                              RadioSettingValueList(
3265
                                  POWER_LIST, POWER_LIST[_vfob[i].power]))
3266
            vfob_grp[i].append(rs)
3267
            rs = RadioSetting("vfob[%i].iswide" % i,
3268
                              self.vfo_area + "B Wide/Narrow",
3269
                              RadioSettingValueList(
3270
                                  BANDWIDTH_LIST,
3271
                                  BANDWIDTH_LIST[_vfob[i].iswide]))
3272
            vfob_grp[i].append(rs)
3273
            rs = RadioSetting("vfob[%i].mute_mode" % i,
3274
                              self.vfo_area + "B Mute (SP Mute)",
3275
                              RadioSettingValueList(
3276
                                  SPMUTE_LIST,
3277
                                  SPMUTE_LIST[_vfob[i].mute_mode]))
3278
            vfob_grp[i].append(rs)
3279
            rs = RadioSetting("vfob[%i].ofst_dir" % i,
3280
                              self.vfo_area + self._offset_dir_rpt_labelB,
3281
                              RadioSettingValueList(
3282
                                  self._offset_dir_rpt,
3283
                                  self._offset_dir_rpt[_vfob[i].ofst_dir]))
3284
            vfob_grp[i].append(rs)
3285
            rs = RadioSetting("vfob[%i].scrambler" % i,
3286
                              self.vfo_area + "B Scramble/Descramble",
3287
                              RadioSettingValueList(
3288
                                  SCRAMBLE_LIST,
3289
                                  SCRAMBLE_LIST[_vfob[i].scrambler]))
3290
            vfob_grp[i].append(rs)
3291

    
3292
            rs = RadioSetting("vfob[%i].compander" % i,
3293
                              self.vfo_area + "B Compander",
3294
                              RadioSettingValueList(
3295
                                  ONOFF_LIST, ONOFF_LIST[_vfob[i].compander]))
3296
            vfob_grp[i].append(rs)
3297
            rs = RadioSetting("vfob[%i].call_group" % i,
3298
                              self.vfo_area + "B Call Group",
3299
                              RadioSettingValueInteger(
3300
                                  1, 99, _vfob[i].call_group))
3301
            vfob_grp[i].append(rs)
3302

    
3303
        rs = RadioSetting("settings.vfostepB", self.vfo_area + "B Step (kHz)",
3304
                          RadioSettingValueList(
3305
                              steps, steps[_settings.vfostepB]))
3306
        vfob_grp.append(rs)
3307
        rs = RadioSetting("settings.squelchB", self.vfo_area + "B Squelch",
3308
                          RadioSettingValueList(
3309
                              LIST_10, LIST_10[_settings.squelchB]))
3310
        vfob_grp.append(rs)
3311
        rs = RadioSetting("BCL_B", "Busy Channel Lock-out B",
3312
                          RadioSettingValueBoolean(_settings.BCL_B))
3313
        vfob_grp.append(rs)
3314
        rs = RadioSetting("settings.vfobandB", "VFO B Current Band",
3315
                          RadioSettingValueMap(VFOBBAND_MAP,
3316
                                               _settings.vfobandB))
3317
        vfob_grp.append(rs)
3318

    
3319
        # FM RADIO PRESETS
3320

    
3321
        # memory stores raw integer value like 760
3322
        # radio will divide 760 by 10 and interpret correctly at 76.0Mhz
3323
        for i in range(1, 21):
3324
            chan = str(i)
3325
            s = i-1
3326
            rs = RadioSetting("fm[%s].FM_radio" % s, "FM Preset " + chan,
3327
                              RadioSettingValueFloat(76.0, 108.0,
3328
                                                     _fm[i-1].FM_radio / 10.0,
3329
                                                     0.1, 1))
3330
            fmradio_grp.append(rs)
3331

    
3332
        if self.show_limits:
3333
            lim = self._memobj.limits
3334
            rs = RadioSetting("limits.m2tx_start",
3335
                              "2M TX Lower Limit (MHz)",
3336
                              RadioSettingValueFloat(
3337
                                  118.000000, 299.999999,
3338
                                  (lim.m2tx_start / 100000.0),
3339
                                  0.000001, 6))
3340

    
3341
            lmt_grp[0].append(rs)
3342
            rs = RadioSetting("limits.m2tx_stop",
3343
                              "2M TX Upper Limit (MHz)",
3344
                              RadioSettingValueFloat(
3345
                                  118.000000, 299.999999,
3346
                                  (lim.m2tx_stop / 100000.0),
3347
                                  0.000001, 6))
3348
            lmt_grp[0].append(rs)
3349
            rs = RadioSetting("limits.tworx_start",
3350
                              "2M TX SUPER Lower Limit (MHz)",
3351
                              RadioSettingValueFloat(
3352
                                  108.000000, 299.999999,
3353
                                  (lim.tworx_start / 100000.0),
3354
                                  0.000001, 6))
3355
            lmt_grp[0].append(rs)
3356
            rs = RadioSetting("limits.tworx_stop",
3357
                              "2M TX SUPER Upper Limit (MHz)",
3358
                              RadioSettingValueFloat(
3359
                                  108.000000, 299.999999,
3360
                                  (lim.tworx_stop / 100000.0),
3361
                                  0.000001, 6))
3362
            lmt_grp[0].append(rs)
3363

    
3364
            rs = RadioSetting("limits.cm70_tx_start",
3365
                              "70cm TX Lower Limit (MHz)",
3366
                              RadioSettingValueFloat(
3367
                                  300.000000, 999.999999,
3368
                                  (lim.cm70_tx_start / 100000.0),
3369
                                  0.000001, 6))
3370
            lmt_grp[0].append(rs)
3371
            rs = RadioSetting("limits.cm70_tx_stop",
3372
                              "70cm TX Upper Limit (MHz)",
3373
                              RadioSettingValueFloat(
3374
                                  300.000000, 999.999999,
3375
                                  (lim.cm70_tx_stop / 100000.0),
3376
                                  0.000001, 6))
3377
            lmt_grp[0].append(rs)
3378
            rs = RadioSetting("limits.m125_tx_start",
3379
                              "1.25M TX Lower Limit (MHz)",
3380
                              RadioSettingValueFloat(
3381
                                  200.000000, 299.999999,
3382
                                  (lim.m125_tx_start / 100000.0),
3383
                                  0.000001, 6))
3384
            lmt_grp[0].append(rs)
3385
            rs = RadioSetting("limits.m125_tx_stop",
3386
                              "1.25M TX Upper Limit (MHz)",
3387
                              RadioSettingValueFloat(
3388
                                  200.000000, 299.999999,
3389
                                  (lim.m125_tx_stop / 100000.0),
3390
                                  0.000001, 6))
3391
            lmt_grp[0].append(rs)
3392
            rs = RadioSetting("limits.m6_tx_start",
3393
                              "6M TX Lower Limit (MHz)",
3394
                              RadioSettingValueFloat(
3395
                                  26.000000, 99.999999,
3396
                                  (lim.m6_tx_start / 100000.0),
3397
                                  0.000001, 6))
3398
            lmt_grp[0].append(rs)
3399
            rs = RadioSetting("limits.m6_tx_stop",
3400
                              "6M TX Upper Limit (MHz)",
3401
                              RadioSettingValueFloat(
3402
                                  26.000000, 99.999999,
3403
                                  (lim.m6_tx_stop / 100000.0),
3404
                                  0.000001, 6))
3405
            lmt_grp[0].append(rs)
3406
            rs = RadioSetting("limits.rx1lim_start",
3407
                              "2M Area A RX Lower Limit (MHz) - Verified",
3408
                              RadioSettingValueFloat(
3409
                                  108.000000, 299.999999,
3410
                                  (lim.rx1lim_start / 100000.0),
3411
                                  0.000001, 6))
3412
            lmt_grp.append(rs)
3413
            rs = RadioSetting("limits.rx1lim_stop",
3414
                              "2M Area A RX Upper Limit (MHz) - Verified",
3415
                              RadioSettingValueFloat(
3416
                                  0.000000, 999.999999,
3417
                                  (lim.rx1lim_stop / 100000.0),
3418
                                  0.000001, 6))
3419
            lmt_grp.append(rs)
3420
            rs = RadioSetting("limits.rx7lim_start",
3421
                              "2M Area B RX Lower Limit (MHz) - Verified",
3422
                              RadioSettingValueFloat(
3423
                                  136.000000, 999.999999,
3424
                                  (lim.rx7lim_start / 100000.0),
3425
                                  0.000001, 6))
3426
            lmt_grp.append(rs)
3427
            rs = RadioSetting("limits.rx7lim_stop",
3428
                              "2M Area B RX Upper Limit (MHz) - Verified",
3429
                              RadioSettingValueFloat(
3430
                                  0.000000, 999.999999,
3431
                                  (lim.rx7lim_stop / 100000.0),
3432
                                  0.000001, 6))
3433
            lmt_grp.append(rs)
3434
            rs = RadioSetting("limits.rx12lim_start",
3435
                              "2m Area A SUPER Rx Lower Limit (MHz)",
3436
                              RadioSettingValueFloat(
3437
                                  0.000000, 999.999999,
3438
                                  (lim.rx12lim_start / 100000.0),
3439
                                  0.000001, 6))
3440
            lmt_grp.append(rs)
3441
            rs = RadioSetting("limits.rx12lim_stop",
3442
                              "2m Area A SUPER Rx Upper Limit (MHz)",
3443
                              RadioSettingValueFloat(
3444
                                  0.000000, 999.999999,
3445
                                  (lim.rx12lim_stop / 100000.0),
3446
                                  0.000001, 6))
3447
            lmt_grp.append(rs)
3448
            rs = RadioSetting("limits.rx18lim_start",
3449
                              "2m Area B SUPER Rx Lower Limit (MHz)",
3450
                              RadioSettingValueFloat(
3451
                                  0.000000, 999.999999,
3452
                                  (lim.rx18lim_start / 100000.0),
3453
                                  0.000001, 6))
3454
            lmt_grp.append(rs)
3455
            rs = RadioSetting("limits.rx18lim_stop",
3456
                              "2m Area B SUPER Rx Upper Limit (MHz)",
3457
                              RadioSettingValueFloat(
3458
                                  0.000000, 999.999999,
3459
                                  (lim.rx18lim_stop / 100000.0),
3460
                                  0.000001, 6))
3461
            lmt_grp.append(rs)
3462
            rs = RadioSetting("limits.rx13lim_start",
3463
                              "70cm Area A SUPER Rx Lower Limit (MHz)",
3464
                              RadioSettingValueFloat(
3465
                                  0.000000, 999.999999,
3466
                                  (lim.rx13lim_start / 100000.0),
3467
                                  0.000001, 6))
3468
            lmt_grp.append(rs)
3469
            rs = RadioSetting("limits.rx13lim_stop",
3470
                              "70cm Area A SUPER Rx Upper Limit (MHz)",
3471
                              RadioSettingValueFloat(
3472
                                  0.000000, 999.999999,
3473
                                  (lim.rx13lim_stop / 100000.0),
3474
                                  0.000001, 6))
3475
            lmt_grp.append(rs)
3476
            rs = RadioSetting("limits.rx2lim_start",
3477
                              "70cm Area A RX Lower Limit (MHz) - Verified",
3478
                              RadioSettingValueFloat(
3479
                                  0.000000, 999.999999,
3480
                                  (lim.rx2lim_start / 100000.0),
3481
                                  0.000001, 6))
3482
            lmt_grp.append(rs)
3483
            rs = RadioSetting("limits.rx2lim_stop",
3484
                              "70cm Area A RX Upper Limit (MHz) - Verified",
3485
                              RadioSettingValueFloat(
3486
                                  0.000000, 999.999999,
3487
                                  (lim.rx2lim_stop / 100000.0),
3488
                                  0.000001, 6))
3489
            lmt_grp.append(rs)
3490
            rs = RadioSetting("limits.rx8lim_start",
3491
                              "70cm Area B RX Lower Limit (MHz) - Verified",
3492
                              RadioSettingValueFloat(
3493
                                  0.000000, 999.999999,
3494
                                  (lim.rx8lim_start / 100000.0),
3495
                                  0.000001, 6))
3496
            lmt_grp.append(rs)
3497
            rs = RadioSetting("limits.rx8lim_stop",
3498
                              "70cm Area B RX Upper Limit (MHz) - Verified",
3499
                              RadioSettingValueFloat(
3500
                                  0.000000, 999.999999,
3501
                                  (lim.rx8lim_stop / 100000.0),
3502
                                  0.000001, 6))
3503
            lmt_grp.append(rs)
3504
            rs = RadioSetting("limits.rx19lim_start",
3505
                              "70cm Area B SUPER RX Lower Limit (MHz)",
3506
                              RadioSettingValueFloat(
3507
                                  0.000000, 999.999999,
3508
                                  (lim.rx19lim_start / 100000.0),
3509
                                  0.000001, 6))
3510
            lmt_grp.append(rs)
3511
            rs = RadioSetting("limits.rx19lim_stop",
3512
                              "70cm Area B SUPER RX Upper Limit (MHz)",
3513
                              RadioSettingValueFloat(
3514
                                  0.000000, 999.999999,
3515
                                  (lim.rx19lim_stop / 100000.0),
3516
                                  0.000001, 6))
3517
            lmt_grp.append(rs)
3518
            rs = RadioSetting("limits.rx3lim_start",
3519
                              "1.25m RX Lower Limit (MHz)",
3520
                              RadioSettingValueFloat(
3521
                                  0.000000, 999.999999,
3522
                                  (lim.rx3lim_start / 100000.0),
3523
                                  0.000001, 6))
3524
            lmt_grp.append(rs)
3525
            rs = RadioSetting("limits.rx3lim_stop",
3526
                              "1.25m RX Upper Limit (MHz)",
3527
                              RadioSettingValueFloat(
3528
                                  0.000000, 999.999999,
3529
                                  (lim.rx3lim_stop / 100000.0),
3530
                                  0.000001, 6))
3531
            lmt_grp.append(rs)
3532
            rs = RadioSetting("limits.rx4lim_start",
3533
                              "6M RX Lower Limit (MHz)",
3534
                              RadioSettingValueFloat(
3535
                                  0.000000, 999.999999,
3536
                                  (lim.rx4lim_start / 100000.0),
3537
                                  0.000001, 6))
3538
            lmt_grp.append(rs)
3539
            rs = RadioSetting("limits.rx4lim_stop",
3540
                              "6M RX Upper Limit (MHz)",
3541
                              RadioSettingValueFloat(
3542
                                  0.000000, 999.999999,
3543
                                  (lim.rx4lim_stop / 100000.0),
3544
                                  0.000001, 6))
3545
            lmt_grp.append(rs)
3546
            rs = RadioSetting("limits.rx5lim_start",
3547
                              "800MHz Rz Lower Limit (MHz)",
3548
                              RadioSettingValueFloat(
3549
                                  0.000000, 999.999999,
3550
                                  (lim.rx5lim_start / 100000.0),
3551
                                  0.000001, 6))
3552
            lmt_grp.append(rs)
3553
            rs = RadioSetting("limits.rx5lim_stop",
3554
                              "800MHz Rz Upper Limit (MHz)",
3555
                              RadioSettingValueFloat(
3556
                                  0.000000, 999.999999,
3557
                                  (lim.rx5lim_stop / 100000.0),
3558
                                  0.000001, 6))
3559
            lmt_grp.append(rs)
3560
            rs = RadioSetting("limits.rx6lim_start",
3561
                              "rx6_start Lower Limit (MHz)",
3562
                              RadioSettingValueFloat(
3563
                                  0.000000, 999.999999,
3564
                                  (lim.rx6lim_start / 100000.0),
3565
                                  0.000001, 6))
3566
            lmt_grp.append(rs)
3567
            rs = RadioSetting("limits.rx6lim_stop",
3568
                              "rx6_stop Upper Limit (MHz)",
3569
                              RadioSettingValueFloat(
3570
                                  0.000000, 999.999999,
3571
                                  (lim.rx6lim_stop / 100000.0),
3572
                                  0.000001, 6))
3573
            lmt_grp.append(rs)
3574
            rs = RadioSetting("limits.rx10lim_start",
3575
                              "70cm Area B TX Lower Limit (MHz)",
3576
                              RadioSettingValueFloat(
3577
                                  0.000000, 999.999999,
3578
                                  (lim.rx10lim_start / 100000.0),
3579
                                  0.000001, 6))
3580
            lmt_grp[0].append(rs)
3581
            rs = RadioSetting("limits.rx10lim_stop",
3582
                              "70cm Area B TX Upper Limit (MHz)",
3583
                              RadioSettingValueFloat(
3584
                                  0.000000, 999.999999,
3585
                                  (lim.rx10lim_stop / 100000.0),
3586
                                  0.000001, 6))
3587
            lmt_grp[0].append(rs)
3588
            rs = RadioSetting("limits.rx14lim_start",
3589
                              "rx14lim_start Lower Limit (MHz)",
3590
                              RadioSettingValueFloat(
3591
                                  0.000000, 999.999999,
3592
                                  (lim.rx14lim_start / 100000.0),
3593
                                  0.000001, 6))
3594
            lmt_grp.append(rs)
3595
            rs = RadioSetting("limits.rx14lim_stop",
3596
                              "rx14lim_stop Upper Limit (MHz)",
3597
                              RadioSettingValueFloat(
3598
                                  0.000000, 999.999999,
3599
                                  (lim.rx14lim_stop / 100000.0),
3600
                                  0.000001, 6))
3601
            lmt_grp.append(rs)
3602
            rs = RadioSetting("limits.rx15lim_start",
3603
                              "rx15lim_start Lower Limit (MHz)",
3604
                              RadioSettingValueFloat(
3605
                                  0.000000, 999.999999,
3606
                                  (lim.rx15lim_start / 100000.0),
3607
                                  0.000001, 6))
3608
            lmt_grp.append(rs)
3609
            rs = RadioSetting("limits.rx15lim_stop",
3610
                              "rx15lim_stop Upper Limit (MHz)",
3611
                              RadioSettingValueFloat(
3612
                                  0.000000, 999.999999,
3613
                                  (lim.rx15lim_stop / 100000.0),
3614
                                  0.000001, 6))
3615
            lmt_grp.append(rs)
3616
            rs = RadioSetting("limits.rx16lim_start",
3617
                              "rx16lim_start Lower Limit (MHz)",
3618
                              RadioSettingValueFloat(
3619
                                  0.000000, 999.999999,
3620
                                  (lim.rx16lim_start / 100000.0),
3621
                                  0.000001, 6))
3622
            lmt_grp.append(rs)
3623
            rs = RadioSetting("limits.rx16lim_stop",
3624
                              "rx16lim_stop Upper Limit (MHz)",
3625
                              RadioSettingValueFloat(
3626
                                  0.000000, 999.999999,
3627
                                  (lim.rx16lim_stop / 100000.0),
3628
                                  0.000001, 6))
3629
            lmt_grp.append(rs)
3630
            rs = RadioSetting("limits.rx17lim_start",
3631
                              "rx17lim_start Lower Limit (MHz)",
3632
                              RadioSettingValueFloat(
3633
                                  0.000000, 999.999999,
3634
                                  (lim.rx17lim_start / 100000.0),
3635
                                  0.000001, 6))
3636
            lmt_grp.append(rs)
3637
            rs = RadioSetting("limits.rx17lim_stop",
3638
                              "rx17lim_stop Upper Limit (MHz)",
3639
                              RadioSettingValueFloat(
3640
                                  0.000000, 999.999999,
3641
                                  (lim.rx17lim_stop / 100000.0),
3642
                                  0.000001, 6))
3643
            lmt_grp.append(rs)
3644
            for i in range(0, 14):
3645
                s = self._memobj.limits.more_limits[i]
3646
                rs = RadioSetting("limits.more_limits[%i].lim_start" % i,
3647
                                  "More %i Lower Limit (MHz)" % i,
3648
                                  RadioSettingValueFloat(
3649
                                      0.000000, 999.999999,
3650
                                      (s.lim_start / 100000.0),
3651
                                      0.000001, 6))
3652
                lmt_grp.append(rs)
3653
                rs = RadioSetting("limits.more_limits[%i].lim_stop" % i,
3654
                                  "More %i Upper Limit (MHz)" % i,
3655
                                  RadioSettingValueFloat(
3656
                                      0.000000, 999.999999,
3657
                                      (s.lim_stop / 100000.0),
3658
                                      0.000001, 6))
3659
                lmt_grp.append(rs)
3660

    
3661
        # # OEM info
3662

    
3663
        def _decode(lst):
3664
            _str = ''.join([chr(int(c)) for c in lst
3665
                            if chr(int(c)) in chirp_common.CHARSET_ASCII])
3666
            return _str
3667

    
3668
        def do_nothing(setting, obj):
3669
            return
3670

    
3671
        _str = _decode(self._memobj.oem_info.oem1)
3672
        val = RadioSettingValueString(0, 15, _str)
3673
        val.set_mutable(False)
3674
        rs = RadioSetting("oem_info.oem1", "OEM String 1", val)
3675
        rs.set_apply_callback(do_nothing, _settings)
3676
        oem_grp.append(rs)
3677
        # if self.MODEL == "KG-Q10H" :
3678
        _str = _decode(self._memobj.oem_info.name)
3679
        val = RadioSettingValueString(0, 15, _str)
3680
        val.set_mutable(False)
3681
        rs = RadioSetting("oem_info.name", "Radio Model", val)
3682
        rs.set_apply_callback(do_nothing, _settings)
3683
        oem_grp.append(rs)
3684

    
3685
        _str = _decode(self._memobj.oem_info.firmware)
3686
        val = RadioSettingValueString(0, 15, _str)
3687
        val.set_mutable(False)
3688
        rs = RadioSetting("oem_info.firmware", "Firmware Version", val)
3689
        rs.set_apply_callback(do_nothing, _settings)
3690
        oem_grp.append(rs)
3691

    
3692
        _str = _decode(self._memobj.oem_info.date)
3693
        val = RadioSettingValueString(0, 15, _str)
3694
        val.set_mutable(False)
3695
        rs = RadioSetting("oem_info.date", "OEM Date", val)
3696
        rs.set_apply_callback(do_nothing, _settings)
3697
        oem_grp.append(rs)
3698
        if self.MODEL == "KG-Q10H":
3699
            rs = RadioSetting("oem_info.locked", "OEM Lock Mode -"
3700
                              " Tx/Rx Range Locked to factory settings",
3701
                              RadioSettingValueBoolean(
3702
                                  self._memobj.oem_info.locked))
3703
            oem_grp.append(rs)
3704

    
3705
        return group
3706

    
3707
    def get_settings(self):
3708
        try:
3709
            return self._get_settings()
3710
        except Exception:
3711
            import traceback
3712
            LOG.error("Failed to parse settings: %s", traceback.format_exc())
3713
            return None
3714

    
3715
    def set_settings(self, settings):
3716
        for element in settings:
3717
            if not isinstance(element, RadioSetting):
3718
                self.set_settings(element)
3719
                continue
3720
            else:
3721
                try:
3722
                    if "." in element.get_name():
3723
                        bits = element.get_name().split(".")
3724
                        obj = self._memobj
3725
                        for bit in bits[:-1]:
3726
                            if "[" in bit and "]" in bit:
3727
                                bit, index = bit.split("[", 1)
3728
                                index, junk = index.split("]", 1)
3729
                                index = int(index)
3730
                                obj = getattr(obj, bit)[index]
3731
                            else:
3732
                                obj = getattr(obj, bit)
3733
                        setting = bits[-1]
3734
                    else:
3735
                        obj = self._memobj.settings
3736
                        setting = element.get_name()
3737

    
3738
                    if element.has_apply_callback():
3739
                        element.run_apply_callback()
3740
                    else:
3741
                        LOG.debug("Setting %s = %s" % (setting, element.value))
3742
                        if self._is_freq(element):
3743
                            # MRT rescale freq values to match radio
3744
                            # expected values
3745
                            setattr(obj, setting,
3746
                                    int(element.values()[0]._current *
3747
                                        100000.0))
3748
                        elif self._is_fmradio(element):
3749
                            # MRT rescale FM Radio values to match radio
3750
                            # expected values
3751
                            setattr(obj, setting,
3752
                                    int(element.values()[0]._current * 10.0))
3753
                        elif self._is_color(element):
3754
                            setattr(obj, setting,
3755
                                    RadioSettingValueRGB.get_rgb16(
3756
                                        element.value))
3757
                        else:
3758
                            setattr(obj, setting, element.value)
3759
                except Exception:
3760
                    LOG.debug(element.get_name())
3761
                    raise
3762

    
3763
    def _is_freq(self, element):
3764
        return ("rxfreq" in element.get_name() or
3765
                "offset" in element.get_name() or
3766
                "rx_start" in element.get_name() or
3767
                "rx_stop" in element.get_name() or
3768
                "lim_start" in element.get_name() or
3769
                "lim_stop" in element.get_name() or
3770
                "tx_start" in element.get_name() or
3771
                "tx_stop" in element.get_name())
3772

    
3773
    def _is_color(self, element):
3774
        return (("custcol" in element.get_name()) & (self.use_color is True))
3775

    
3776
    def _is_fmradio(self, element):
3777
        return "FM_radio" in element.get_name()
3778

    
3779
    def callid2str(self, cid):
3780
        """Caller ID per MDC-1200 spec? Must be 3-6 digits (100 - 999999).
3781
        One digit (binary) per byte, terminated with '0xc'
3782
        """
3783

    
3784
        bin2ascii = "0123456789"
3785
        cidstr = ""
3786
        for i in range(0, 6):
3787
            b = cid[i].get_value()
3788
            # Handle fluky firmware 0x0a is sometimes used instead of 0x00
3789
            if b == 0x0a:
3790
                b = 0x00
3791
            if b == 0xc or b == 0xf:  # the cid EOL
3792
                break
3793
            if b > 0xa:
3794
                raise InvalidValueError(
3795
                    "Caller ID code has illegal byte 0x%x" % b)
3796
            cidstr += bin2ascii[b]
3797
        return cidstr
3798

    
3799
    def _checksum2(self, data):
3800
        cs = 0
3801
        cs_adj = 0
3802
        for byte in data:
3803
            cs += byte
3804
        cs %= 256
3805
        cs_adj = (data[3] & 0x0F) % 4
3806
        if cs_adj == 0:
3807
            cs += 3
3808
        elif cs_adj == 1:
3809
            cs += 1
3810
        elif cs_adj == 2:
3811
            cs -= 1
3812
        elif cs_adj == 3:
3813
            cs -= 3
3814
        return (cs & 0xFF)
3815

    
3816
    def _checksum_adjust(self, data):
3817
        cs_mod = 0
3818
        cs_adj = 0
3819
        cs_adj = (data & 0x0F) % 4
3820
        if cs_adj == 0:
3821
            cs_mod = 3
3822
        elif cs_adj == 1:
3823
            cs_mod = 1
3824
        elif cs_adj == 2:
3825
            cs_mod = -1
3826
        elif cs_adj == 3:
3827
            cs_mod = -3
3828
        return (cs_mod)
3829

    
3830
    def _write_record(self, cmd, payload=b''):
3831
        _packet = struct.pack('BBBB', self._record_start, cmd, 0xFF,
3832
                              len(payload))
3833
        LOG.debug("Sent: Unencrypt\n%s" % util.hexprint(_packet + payload))
3834
        checksum = bytes([self._checksum2(_packet[1:] + payload)])
3835
        _packet += self.encrypt(payload + checksum)
3836
        LOG.debug("Sent:\n%s" % util.hexprint(_packet))
3837
        self.pipe.write(_packet)
3838
        time.sleep(0.000005)
3839

    
3840
    def _identify(self):
3841
        """Wouxun CPS sends the same Read command 3 times to establish comms"""
3842
        """Read Resp and check radio model in prep for actual download"""
3843
        LOG.debug("Starting Radio Identifcation")
3844

    
3845
        for i in range(0, 3):
3846
            ident = struct.pack(
3847
                'BBBBBBBB', 0x7c, 0x82, 0xff, 0x03, 0x54, 0x14, 0x54, 0x53)
3848
            self.pipe.write(ident)
3849
        _chksum_err, _resp = self._read_record()
3850
        _radio_id = _resp[46:53]
3851
        self._RADIO_ID = _radio_id
3852
        LOG.debug("Radio Identified as Model %s" % _radio_id)
3853
        if _chksum_err:
3854
            LOG.debug(util.hexprint(_resp))
3855
            raise errors.RadioError("Checksum Error on Identify")
3856
        elif _radio_id != self._model:
3857
            self._finish()
3858
            raise errors.RadioError("Radio identified as Model: %s \n"
3859
                                    "You selected Model: %s.\n"
3860
                                    "Please select the correct radio model"
3861
                                    " to continue"
3862
                                    # "Your Model is not currently supported"
3863
                                    % (_radio_id.decode('UTF-8'),
3864
                                    self._model.decode('UTF-8')))
3865
        LOG.debug("Ending Radio Identifcation")
3866

    
3867
    def _download(self):
3868
        try:
3869
            self._identify()
3870
            return self._do_download()
3871
        except errors.RadioError:
3872
            raise
3873
        except Exception as e:
3874
            LOG.exception('Unknown error during download process')
3875
            raise errors.RadioError("Failed to communicate with radio: %s" % e)
3876

    
3877
    def _do_download(self):
3878
        LOG.debug("Starting Download")
3879
        # allocate & fill memory
3880
        image = b""
3881
        # Download full memory in 0x000 to 0x8000 address order
3882
        # rearrange later
3883
        cfgmap = Q10H_download_map_full
3884

    
3885
        for start, blocksize, count in cfgmap:
3886
            end = start + (blocksize * count)
3887
            LOG.debug("start = " + str(start))
3888
            LOG.debug("end = " + str(end))
3889
            LOG.debug("blksize = " + str(blocksize))
3890

    
3891
            for i in range(start, end, blocksize):
3892
                time.sleep(0.005)
3893
                req = struct.pack('>HB', i, blocksize)
3894
                self._write_record(CMD_RD, req)
3895
                cs_error, resp = self._read_record()
3896
                if cs_error:
3897
                    LOG.debug(util.hexprint(resp))
3898
                    raise Exception("Checksum error on read")
3899
                LOG.debug("Got:\n%s" % util.hexprint(resp))
3900
                image += resp[2:]
3901
                if self.status_fn:
3902
                    status = chirp_common.Status()
3903
                    status.cur = i
3904
                    status.max = 0x8000
3905
                    status.msg = "Cloning from radio"
3906
                    self.status_fn(status)
3907
        self._finish()
3908
        LOG.debug("Download Completed")
3909
        return memmap.MemoryMapBytes(image)
3910

    
3911
    def _read_record(self):
3912
        # read 4 chars for the header
3913
        _header = self.pipe.read(4)
3914

    
3915
        if len(_header) != 4:
3916
            raise errors.RadioError('Radio did not respond \n'
3917
                                    'Confirm proper radio selection \n'
3918
                                    'Confirm radio is Powered On and '
3919
                                    'programming cable is fully inserted')
3920
        _length = struct.unpack('xxxB', _header)[0]
3921
        _packet = self.pipe.read(_length)
3922

    
3923
        _rcs_xor = _packet[-1]
3924
        _packet = self.decrypt(_packet)
3925
        LOG.debug("Header =%a" % util.hexprint(_header + _packet[0:2]))
3926
        _cs = self._checksum(_header[1:])
3927
        _cs += self._checksum(_packet)
3928
        _csa = self._checksum_adjust(_packet[0])
3929
        LOG.debug("_cs (preadjusted)=%x", _cs & 0xff)
3930
        _cs += _csa
3931
        _cs = _cs & 0xFF
3932
        _rcs = self.strxor(self.pipe.read(1)[0], _rcs_xor)[0]
3933
        LOG.debug("_csa=%x", _csa)
3934
        LOG.debug("_cs (adjusted)=%x", _cs)
3935
        LOG.debug("_rcs=%x", _rcs)
3936
        return (_rcs != _cs, _packet)
3937

    
3938
    def _finish(self):
3939
        # this is the encrypted finish command sent by Q10H CPS
3940
        finish = struct.pack('BBBBB', 0x7c, 0x81, 0xff, 0x00, 0xd7)
3941
        self.pipe.write(finish)
3942
        return
3943

    
3944
    def decrypt(self, data):
3945
        result = b''
3946
        for i in range(len(data)-1, 0, -1):
3947
            result += self.strxor(data[i], data[i - 1])
3948
        result += self.strxor(data[0], self.cryptbyte)
3949
        return result[::-1]
3950

    
3951
    def encrypt(self, data):
3952
        result = self.strxor(self.cryptbyte, data[0])
3953
        for i in range(1, len(data), 1):
3954
            result += self.strxor(result[i - 1], data[i])
3955
        return result
3956

    
3957

    
3958
@directory.register
3959
class KGQ10GRadio(KGQ10HRadio):
3960

    
3961
    """Wouxun KG-Q10G"""
3962
    VENDOR = "Wouxun"
3963
    MODEL = "KG-Q10G"
3964
    NEEDS_COMPAT_SERIAL = False
3965
    _model = b"KG-Q10G"
3966
    cryptbyte = 0x54
3967
    am_mode_list = AM_MODE_2
3968
    am_mode_list_ch = AM_MODE_CH2
3969
    vfoa3_msg = "26M Settings"
3970
    _prog_key = PROG_KEY_LIST2
3971
    _vfoaband = VFOABAND_MAP2
3972
    _offset_dir_rpt = ONOFF_LIST
3973
    _offset_dir_rpt_label = "A Repeater"
3974
    _offset_dir_rpt_labelB = "B Repeater"
3975
    rpttonemenu = 40
3976
    timemenu = 41
3977
    tzmenu = 42
3978
    locmenu = 44
3979

    
3980
    def get_features(self):
3981
        rf = chirp_common.RadioFeatures()
3982
        rf.has_settings = True
3983
        rf.has_ctone = True
3984
        rf.has_rx_dtcs = True
3985
        rf.has_cross = True
3986
        rf.has_tuning_step = False
3987
        rf.has_bank = False
3988
        rf.can_odd_split = True
3989
        rf.valid_skips = ["", "S"]
3990
        rf.valid_tmodes = ["", "Tone", "TSQL", "DTCS", "Cross"]
3991
        rf.valid_cross_modes = [
3992
            "Tone->Tone",
3993
            "Tone->DTCS",
3994
            "DTCS->Tone",
3995
            "DTCS->",
3996
            "->Tone",
3997
            "->DTCS",
3998
            "DTCS->DTCS",
3999
        ]
4000
        rf.valid_modes = ["FM", "NFM", "AM"]
4001
        rf.valid_power_levels = self.POWER_LEVELS
4002
        rf.valid_name_length = 12
4003
        rf.valid_duplexes = ["", "-", "+", "split", "off"]
4004
        #   MRT - Open up channel memory freq range to support
4005
        #   RxFreq limit expansion
4006
        rf.valid_bands = [(26000000, 31997500),    # CB
4007
                          (108000000, 174997500),  # AM Airband and VHF
4008
                          (222000000, 225997500),  # 1.25M
4009
                          (320000000, 479997500),  # UHF
4010
                          (714000000, 999997500)]  # Fixed Land Mobile
4011

    
4012
        rf.valid_characters = chirp_common.CHARSET_ASCII
4013
        rf.memory_bounds = (1, 999)  # 999 memories
4014
        rf.valid_tuning_steps = STEPS2
4015
        return rf
4016

    
4017
    def _do_upload(self):
4018
        # self._identify()
4019
        if self._RADIO_ID == self._model:
4020
            LOG.debug("Starting Upload")
4021
            if self.show_limits:
4022
                cfgmap = Q10H_upload_map
4023
            else:
4024
                cfgmap = Q10G_upload_map_nolims
4025

    
4026
            for (radioaddress, radioend, start, memend,
4027
                 blocksize, count) in cfgmap:
4028
                end = start + (blocksize * count)
4029
                LOG.debug("start = " + str(start))
4030
                LOG.debug("end = " + str(end))
4031
                LOG.debug("blksize = " + str(blocksize))
4032
                ptr2 = radioaddress
4033

    
4034
                for addr in range(start, end, blocksize):
4035
                    ptr = addr
4036
                    LOG.debug("ptr = " + str(hex(ptr)))
4037
                    LOG.debug("ptr2 = " + str(hex(ptr2)))
4038
                    req = struct.pack('>H', ptr2)
4039
                    chunk = self.get_mmap()[ptr:ptr + blocksize]
4040
                    self._write_record(CMD_WR, req + chunk)
4041
                    LOG.debug(util.hexprint(req + chunk))
4042
                    cserr, ack = self._read_record()
4043
                    LOG.debug(util.hexprint(ack))
4044
                    j = struct.unpack('>H', ack)[0]
4045
                    if cserr or j != ptr2:
4046
                        LOG.debug(util.hexprint(ack))
4047
                        raise Exception("Checksum Error on Ack at %i" % ptr)
4048
                    ptr += blocksize
4049
                    ptr2 += blocksize
4050
                    if self.status_fn:
4051
                        status = chirp_common.Status()
4052
                        status.cur = ptr
4053
                        status.max = 0x8000
4054
                        status.msg = "Cloning to radio"
4055
                        self.status_fn(status)
4056
            LOG.debug("Upload Completed")
4057
        else:
4058
            raise errors.RadioError("Radio is not a KG-Q10G. Upload Canceled")
4059

    
4060
        self._finish()
(13-13/14)