Project

General

Profile

New Model #10692 » kgq10h b2p6.py

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

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

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

import struct
import time
import logging

from chirp import util, chirp_common, bitwise, memmap, errors, directory
from chirp.settings import RadioSetting, RadioSettingGroup, \
RadioSettingValueBoolean, RadioSettingValueList, \
RadioSettingValueInteger, RadioSettingValueString, \
RadioSettingValueFloat, RadioSettingValueMap, RadioSettings, \
InvalidValueError#, RadioSettingValueRGB


LOG = logging.getLogger(__name__)

CMD_ID = 128 # \x80
CMD_END = 129 # \x81
CMD_RD = 130 # \82
CMD_WR = 131 # \83

MEM_VALID = 158

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

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

Q10H_download_map_full = (
(0x00, 64, 512), # - Use for full Download testing
)
Q10H_mem_arrange_map = (
(0x0300, 0x0400),
(0x0200, 0x0300),
(0x0100, 0x0200),
(0x0000, 0x0100),

(0x0700, 0x0800),
(0x0600, 0x0700), # channel 1 data start
(0x0500, 0x0600),
(0x0400, 0x0500),

(0x0b00, 0x0c00),
(0x0a00, 0x0b00),
(0x0900, 0x0a00),
(0x0800, 0x0900),

(0x0f00, 0x1000),
(0x0e00, 0x0f00),
(0x0d00, 0x0e00),
(0x0c00, 0x0d00),

(0x1300, 0x1400),
(0x1200, 0x1300),
(0x1100, 0x1200),
(0x1000, 0x1100),

(0x1700, 0x1800),
(0x1600, 0x1700),
(0x1500, 0x1600),
(0x1400, 0x1500),

(0x1B00, 0x1c00),
(0x1a00, 0x1b00),
(0x1900, 0x1a00),
(0x1800, 0x1900),

(0x1f00, 0x2000),
(0x1e00, 0x1f00),
(0x1d00, 0x1e00),
(0x1c00, 0x1d00),

(0x2300, 0x2400),
(0x2200, 0x2300),
(0x2100, 0x2200),
(0x2000, 0x2100),

(0x2700, 0x2800),
(0x2600, 0x2700),
(0x2500, 0x2600),
(0x2400, 0x2500),

(0x2B00, 0x2C00),
(0x2a00, 0x2b00),
(0x2900, 0x2a00),
(0x2800, 0x2900),

(0x2f00, 0x3000),
(0x2e00, 0x2f00),
(0x2d00, 0x2e00),
(0x2c00, 0x2d00),

(0x3300, 0x3400),
(0x3200, 0x3300),
(0x3100, 0x3200),
(0x3000, 0x3100),

(0x3700, 0x3800),
(0x3600, 0x3700),
(0x3500, 0x3600),
(0x3400, 0x3500),

(0x3B00, 0x3C00),
(0x3a00, 0x3b00),
(0x3900, 0x3a00),
(0x3800, 0x3900),

(0x3f00, 0x4000),
(0x3e00, 0x3f00),
(0x3d00, 0x3e00),
(0x3c00, 0x3d00),

(0x4300, 0x4400),
(0x4200, 0x4300),
(0x4100, 0x4200),
(0x4000, 0x4100),

(0x4700, 0x4760),

(0x4760, 0x4800), # start of Ch names
(0x4600, 0x4700),
(0x4500, 0x4600),
(0x4400, 0x4500),
(0x4b00, 0x4c00),
(0x4a00, 0x4B00),
(0x4900, 0x4a00),
(0x4800, 0x4900),
(0x4f00, 0x5000),
(0x4E00, 0x4F00),
(0x4D00, 0x4E00),
(0x4C00, 0x4d00),
(0x5300, 0x5400),
(0x5200, 0x5300),
(0x5100, 0x5200),
(0x5000, 0x5100),
(0x5700, 0x5800),
(0x5600, 0x5700),
(0x5500, 0x5600),
(0x5400, 0x5500),
(0x5B00, 0x5C00),
(0x5A00, 0x5B00),
(0x5900, 0x5A00),
(0x5800, 0x5900),
(0x5F00, 0x6000),
(0x5E00, 0x5F00),
(0x5D00, 0x5E00),
(0x5C00, 0x5D00),
(0x6300, 0x6400),
(0x6200, 0x6300),
(0x6100, 0x6200),
(0x6000, 0x6100),
(0x6700, 0x6800),
(0x6600, 0x6700),
(0x6500, 0x6600),
(0x6400, 0x6500),
(0x6b00, 0x6c00),
(0x6a00, 0x6b00),
(0x6900, 0x6a00),
(0x6800, 0x6900),
(0x6F00, 0x7000),
(0x6e00, 0x6F00),
(0X6D00, 0X6E00),
(0X6C00, 0X6D00),
(0x7300, 0x7400),
(0x7200, 0x7300),
(0x7100, 0x7200),
(0x7000, 0x7040), # End of Ch Names

(0x7040, 0x7100), # start of ch valid
(0x7700, 0x7800),
(0x7600, 0x7700),
(0x7500, 0x7600),
(0x7400, 0x7440), # end of ch valid

(0x7440, 0x7500),
# (0x7800, 0x8000),
(0x7b00, 0x7c00),
(0x7a00, 0x7b00),
(0x7900, 0x7a00),
(0x7800, 0x7900),
(0x7f00, 0x9000),
(0x7e00, 0x7f00),
(0x7d00, 0x7e00),
(0x7c00, 0x7d00),
)


Q10H_mem_arrange_map_OLD = (
(0x0000, 0x0400),
(0x0600, 0x06E0),
(0x0700, 0x0800),

(0x06E0, 0x0700), # channel 1 data start
(0x0500, 0x0600),
(0x0400, 0x0500),

(0x0b00, 0x0c00),
(0x0a00, 0x0b00),
(0x0900, 0x0a00),
(0x0800, 0x0900),

(0x0f00, 0x1000),
(0x0e00, 0x0f00),
(0x0d00, 0x0e00),
(0x0c00, 0x0d00),

(0x1300, 0x1400),
(0x1200, 0x1300),
(0x1100, 0x1200),
(0x1000, 0x1100),

(0x1700, 0x1800),
(0x1600, 0x1700),
(0x1500, 0x1600),
(0x1400, 0x1500),

(0x1B00, 0x1c00),
(0x1a00, 0x1b00),
(0x1900, 0x1a00),
(0x1800, 0x1900),

(0x1f00, 0x2000),
(0x1e00, 0x1f00),
(0x1d00, 0x1e00),
(0x1c00, 0x1d00),

(0x2300, 0x2400),
(0x2200, 0x2300),
(0x2100, 0x2200),
(0x2000, 0x2100),

(0x2700, 0x2800),
(0x2600, 0x2700),
(0x2500, 0x2600),
(0x2400, 0x2500),

(0x2B00, 0x2C00),
(0x2a00, 0x2b00),
(0x2900, 0x2a00),
(0x2800, 0x2900),

(0x2f00, 0x3000),
(0x2e00, 0x2f00),
(0x2d00, 0x2e00),
(0x2c00, 0x2d00),

(0x3300, 0x3400),
(0x3200, 0x3300),
(0x3100, 0x3200),
(0x3000, 0x3100),

(0x3700, 0x3800),
(0x3600, 0x3700),
(0x3500, 0x3600),
(0x3400, 0x3500),

(0x3B00, 0x3C00),
(0x3a00, 0x3b00),
(0x3900, 0x3a00),
(0x3800, 0x3900),

(0x3f00, 0x4000),
(0x3e00, 0x3f00),
(0x3d00, 0x3e00),
(0x3c00, 0x3d00),

(0x4300, 0x4400),
(0x4200, 0x4300),
(0x4100, 0x4200),
(0x4000, 0x4100),

(0x4700, 0x4760),

(0x4760, 0x4800), # start of Ch names
(0x4600, 0x4700),
(0x4500, 0x4600),
(0x4400, 0x4500),
(0x4b00, 0x4c00),
(0x4a00, 0x4B00),
(0x4900, 0x4a00),
(0x4800, 0x4900),
(0x4f00, 0x5000),
(0x4E00, 0x4F00),
(0x4D00, 0x4E00),
(0x4C00, 0x4d00),
(0x5300, 0x5400),
(0x5200, 0x5300),
(0x5100, 0x5200),
(0x5000, 0x5100),
(0x5700, 0x5800),
(0x5600, 0x5700),
(0x5500, 0x5600),
(0x5400, 0x5500),
(0x5B00, 0x5C00),
(0x5A00, 0x5B00),
(0x5900, 0x5A00),
(0x5800, 0x5900),
(0x5F00, 0x6000),
(0x5E00, 0x5F00),
(0x5D00, 0x5E00),
(0x5C00, 0x5D00),
(0x6300, 0x6400),
(0x6200, 0x6300),
(0x6100, 0x6200),
(0x6000, 0x6100),
(0x6700, 0x6800),
(0x6600, 0x6700),
(0x6500, 0x6600),
(0x6400, 0x6500),
(0x6b00, 0x6c00),
(0x6a00, 0x6b00),
(0x6900, 0x6a00),
(0x6800, 0x6900),
(0x6F00, 0x7000),
(0x6e00, 0x6F00),
(0X6D00, 0X6E00),
(0X6C00, 0X6D00),
(0x7300, 0x7400),
(0x7200, 0x7300),
(0x7100, 0x7200),
(0x7000, 0x7040), # End of Ch Names

(0x7040, 0x7100), # start of ch valid
(0x7700, 0x7800),
(0x7600, 0x7700),
(0x7500, 0x7600),
(0x7400, 0x7440), # end of ch valid

(0x7440, 0x7500),
# (0x7800, 0x8000),
(0x7b00, 0x7c00),
(0x7a00, 0x7b00),
(0x7900, 0x7a00),
(0x7800, 0x7900),
(0x7f00, 0x9000),
(0x7e00, 0x7f00),
(0x7d00, 0x7e00),
(0x7c00, 0x7d00),
)

Q10H_upload_map = (
# This map serves 2 purposes-
# To limit the Upload to Radio Writes to known settings only
# And also to send the rearranged Chirp Memory data back to the radio
# using the proper radio addresses.
# Radio Radio Chirp Chirp Blk cnt
# start end start end sz
# (0x0000, 0x0400, 0x0000, 0x0400, 64, 16),
# (0x0600, 0x06E0, 0x0400, 0x04E0, 32, 7),
# (0x0002, 0x0022, 0x0302, 0x0322, 32, 1), # Tx Limits
# (0x00a6, 0x00fe, 0x00a6, 0x00fe, 8, 11), # Rx Limits
# (0x030a, 0x030a, 0x030a, 0x030a, 1, 1), # Factory Locked Mode
# (0x0640, 0x06c0, 0x0440, 0x04c0, 32, 7), # VFO settings
# (0x0700, 0x0800, 0x04E0, 0x05E0, 64, 4), # settings
# (0x06E0, 0x0700, 0x05E0, 0x0600, 32, 1), # channel 1 data start
(0x0300, 0x0400, 0x0000, 0x0100, 64, 4),
(0x0200, 0x0300, 0x0100, 0x0200, 64, 4),
(0x0100, 0x0200, 0x0200, 0x0300, 64, 4),
(0x0000, 0x0100, 0x0300, 0x0400, 64, 4),
(0x0700, 0x0800, 0x0400, 0x0500, 64, 4),
(0x0600, 0x0700, 0x0500, 0x0600, 64, 4),
(0x0500, 0x0600, 0x0600, 0x0700, 64, 4),
(0x0400, 0x0500, 0x0700, 0x0800, 64, 4),
(0x0b00, 0x0c00, 0x0800, 0x0900, 64, 4),
(0x0a00, 0x0b00, 0x0900, 0x0A00, 64, 4),
(0x0900, 0x0a00, 0x0A00, 0x0B00, 64, 4),
(0x0800, 0x0900, 0x0B00, 0x0C00, 64, 4),
(0x0f00, 0x1000, 0x0C00, 0x0D00, 64, 4),
(0x0e00, 0x0f00, 0x0D00, 0x0E00, 64, 4),
(0x0d00, 0x0e00, 0x0E00, 0x0F00, 64, 4),
(0x0c00, 0x0d00, 0x0F00, 0x1000, 64, 4),
(0x1300, 0x1400, 0x1000, 0x1100, 64, 4),
(0x1200, 0x1300, 0x1100, 0x1200, 64, 4),
(0x1100, 0x1200, 0x1200, 0x1300, 64, 4),
(0x1000, 0x1100, 0x1300, 0x1400, 64, 4),
(0x1700, 0x1800, 0x1400, 0x1500, 64, 4),
(0x1600, 0x1700, 0x1500, 0x1600, 64, 4),
(0x1500, 0x1600, 0x1600, 0x1700, 64, 4),
(0x1400, 0x1500, 0x1700, 0x1800, 64, 4),
(0x1B00, 0x1c00, 0x1800, 0x1900, 64, 4),
(0x1a00, 0x1b00, 0x1900, 0x1A00, 64, 4),
(0x1900, 0x1a00, 0x1A00, 0x1B00, 64, 4),
(0x1800, 0x1900, 0x1B00, 0x1C00, 64, 4),
(0x1f00, 0x2000, 0x1C00, 0x1D00, 64, 4),
(0x1e00, 0x1f00, 0x1D00, 0x1E00, 64, 4),
(0x1d00, 0x1e00, 0x1E00, 0x1F00, 64, 4),
(0x1c00, 0x1d00, 0x1F00, 0x2000, 64, 4),
(0x2300, 0x2400, 0x2000, 0x2100, 64, 4),
(0x2200, 0x2300, 0x2100, 0x2200, 64, 4),
(0x2100, 0x2200, 0x2200, 0x2300, 64, 4),
(0x2000, 0x2100, 0x2300, 0x2400, 64, 4),
(0x2700, 0x2800, 0x2400, 0x2500, 64, 4),
(0x2600, 0x2700, 0x2500, 0x2600, 64, 4),
(0x2500, 0x2600, 0x2600, 0x2700, 64, 4),
(0x2400, 0x2500, 0x2700, 0x2800, 64, 4),
(0x2B00, 0x2C00, 0x2800, 0x2900, 64, 4),
(0x2a00, 0x2b00, 0x2900, 0x2A00, 64, 4),
(0x2900, 0x2a00, 0x2A00, 0x2B00, 64, 4),
(0x2800, 0x2900, 0x2B00, 0x2C00, 64, 4),
(0x2f00, 0x3000, 0x2C00, 0x2D00, 64, 4),
(0x2e00, 0x2f00, 0x2D00, 0x2E00, 64, 4),
(0x2d00, 0x2e00, 0x2E00, 0x2F00, 64, 4),
(0x2c00, 0x2d00, 0x2F00, 0x3000, 64, 4),
(0x3300, 0x3400, 0x3000, 0x3100, 64, 4),
(0x3200, 0x3300, 0x3100, 0x3200, 64, 4),
(0x3100, 0x3200, 0x3200, 0x3300, 64, 4),
(0x3000, 0x3100, 0x3300, 0x3400, 64, 4),
(0x3700, 0x3800, 0x3400, 0x3500, 64, 4),
(0x3600, 0x3700, 0x3500, 0x3600, 64, 4),
(0x3500, 0x3600, 0x3600, 0x3700, 64, 4),
(0x3400, 0x3500, 0x3700, 0x3800, 64, 4),
(0x3B00, 0x3C00, 0x3800, 0x3900, 64, 4),
(0x3a00, 0x3b00, 0x3900, 0x3A00, 64, 4),
(0x3900, 0x3a00, 0x3A00, 0x3B00, 64, 4),
(0x3800, 0x3900, 0x3B00, 0x3C00, 64, 4),
(0x3f00, 0x4000, 0x3C00, 0x3D00, 64, 4),
(0x3e00, 0x3f00, 0x3D00, 0x3E00, 64, 4),
(0x3d00, 0x3e00, 0x3E00, 0x3F00, 64, 4),
(0x3c00, 0x3d00, 0x3F00, 0x4000, 64, 4),
(0x4300, 0x4400, 0x4000, 0x4100, 64, 4),
(0x4200, 0x4300, 0x4100, 0x4200, 64, 4),
(0x4100, 0x4200, 0x4200, 0x4300, 64, 4),
(0x4000, 0x4100, 0x4300, 0x4400, 64, 4),
(0x4700, 0x4760, 0x4400, 0x4460, 32, 3), # End of Ch Data
(0x4760, 0x4800, 0x4460, 0x4500, 32, 5), # start of Ch names
(0x4600, 0x4700, 0x4500, 0x4600, 64, 4),
(0x4500, 0x4600, 0x4600, 0x4700, 64, 4),
(0x4400, 0x4500, 0x4700, 0x4800, 64, 4),
(0x4b00, 0x4c00, 0x4800, 0x4900, 64, 4),
(0x4a00, 0x4B00, 0x4900, 0x4A00, 64, 4),
(0x4900, 0x4a00, 0x4A00, 0x4B00, 64, 4),
(0x4800, 0x4900, 0x4B00, 0x4C00, 64, 4),
(0x4f00, 0x5000, 0x4C00, 0x4D00, 64, 4),
(0x4E00, 0x4F00, 0x4D00, 0x4E00, 64, 4),
(0x4D00, 0x4E00, 0x4E00, 0x4F00, 64, 4),
(0x4C00, 0x4d00, 0x4F00, 0x5000, 64, 4),
(0x5300, 0x5400, 0x5000, 0x5100, 64, 4),
(0x5200, 0x5300, 0x5100, 0x5200, 64, 4),
(0x5100, 0x5200, 0x5200, 0x5300, 64, 4),
(0x5000, 0x5100, 0x5300, 0x5400, 64, 4),
(0x5700, 0x5800, 0x5400, 0x5500, 64, 4),
(0x5600, 0x5700, 0x5500, 0x5600, 64, 4),
(0x5500, 0x5600, 0x5600, 0x5700, 64, 4),
(0x5400, 0x5500, 0x5700, 0x5800, 64, 4),
(0x5B00, 0x5C00, 0x5800, 0x5900, 64, 4),
(0x5A00, 0x5B00, 0x5900, 0x5A00, 64, 4),
(0x5900, 0x5A00, 0x5A00, 0x5B00, 64, 4),
(0x5800, 0x5900, 0x5B00, 0x5C00, 64, 4),
(0x5F00, 0x6000, 0x5C00, 0x5D00, 64, 4),
(0x5E00, 0x5F00, 0x5D00, 0x5E00, 64, 4),
(0x5D00, 0x5E00, 0x5E00, 0x5F00, 64, 4),
(0x5C00, 0x5D00, 0x5F00, 0x6000, 64, 4),
(0x6300, 0x6400, 0x6000, 0x6100, 64, 4),
(0x6200, 0x6300, 0x6100, 0x6200, 64, 4),
(0x6100, 0x6200, 0x6200, 0x6300, 64, 4),
(0x6000, 0x6100, 0x6300, 0x6400, 64, 4),
(0x6700, 0x6800, 0x6400, 0x6500, 64, 4),
(0x6600, 0x6700, 0x6500, 0x6600, 64, 4),
(0x6500, 0x6600, 0x6600, 0x6700, 64, 4),
(0x6400, 0x6500, 0x6700, 0x6800, 64, 4),
(0x6b00, 0x6c00, 0x6800, 0x6900, 64, 4),
(0x6a00, 0x6b00, 0x6900, 0x6A00, 64, 4),
(0x6900, 0x6a00, 0x6A00, 0x6B00, 64, 4),
(0x6800, 0x6900, 0x6B00, 0x6C00, 64, 4),
(0x6F00, 0x7000, 0x6C00, 0x6D00, 64, 4),
(0x6e00, 0x6F00, 0x6D00, 0x6E00, 64, 4),
(0x6D00, 0x6E00, 0x6E00, 0x6F00, 64, 4),
(0x6C00, 0x6D00, 0x6F00, 0x7000, 64, 4),
(0x7300, 0x7400, 0x7000, 0x7100, 64, 4),
(0x7200, 0x7300, 0x7100, 0x7200, 64, 4),
(0x7100, 0x7200, 0x7200, 0x7300, 64, 4),
(0x7000, 0x7040, 0x7300, 0x7340, 64, 1), # End of Ch Names
(0x7040, 0x7100, 0x7340, 0x7400, 64, 3), # start of ch valid
(0x7700, 0x7800, 0x7400, 0x7500, 64, 4),
(0x7600, 0x7700, 0x7500, 0x7600, 64, 4),
(0x7500, 0x7600, 0x7600, 0x7700, 64, 4),
(0x7400, 0x7440, 0x7700, 0x7740, 64, 1), # end of ch valid
(0x7440, 0x74e0, 0x7740, 0x77e0, 32, 5), # scan groups
(0x74e0, 0x74e8, 0x77e0, 0x77e8, 8, 1), # VFO Scan range
(0x7bB0, 0x7c00, 0x78B0, 0x7900, 16, 5), # FM presets / Call ID Start
(0x7a00, 0x7b00, 0x7900, 0x7A00, 64, 4),
(0x7900, 0x7a00, 0x7A00, 0x7B00, 64, 4),
(0x7800, 0x7900, 0x7B00, 0x7C00, 64, 4), # Call ID end / Call Name Start
(0x7f00, 0x8000, 0x7C00, 0x7D00, 64, 4),
(0x7e00, 0x7f00, 0x7D00, 0x7E00, 64, 4),
(0x7d00, 0x7e00, 0x7E00, 0x7F00, 64, 4),
(0x7c00, 0x7d00, 0x7F00, 0x8000, 64, 4), # Call Name End
)

Q10H_upload_map_nolims = (
# This map serves 2 purposes-
# To limit the Upload to Radio Writes to known settings only
# And also to send the rearranged Chirp Memory data back to the radio
# using the proper radio addresses.
# Radio Radio Chirp Chirp Blk cnt
# start end start end sz
# (0x0300, 0x0400, 0x0000, 0x0100, 64, 4),
# (0x0200, 0x0300, 0x0100, 0x0200, 64, 4),
# (0x0100, 0x0200, 0x0200, 0x0300, 64, 4),
(0x030A, 0x030A, 0x000a, 0x000a, 1, 1), # Unlock
(0x0040, 0x0100, 0x0340, 0x0400, 64, 3), # settings
(0x0700, 0x0800, 0x0400, 0x0500, 64, 4), # channel data
(0x0600, 0x0700, 0x0500, 0x0600, 64, 4),
(0x0500, 0x0600, 0x0600, 0x0700, 64, 4),
(0x0400, 0x0500, 0x0700, 0x0800, 64, 4),
(0x0b00, 0x0c00, 0x0800, 0x0900, 64, 4),
(0x0a00, 0x0b00, 0x0900, 0x0A00, 64, 4),
(0x0900, 0x0a00, 0x0A00, 0x0B00, 64, 4),
(0x0800, 0x0900, 0x0B00, 0x0C00, 64, 4),
(0x0f00, 0x1000, 0x0C00, 0x0D00, 64, 4),
(0x0e00, 0x0f00, 0x0D00, 0x0E00, 64, 4),
(0x0d00, 0x0e00, 0x0E00, 0x0F00, 64, 4),
(0x0c00, 0x0d00, 0x0F00, 0x1000, 64, 4),
(0x1300, 0x1400, 0x1000, 0x1100, 64, 4),
(0x1200, 0x1300, 0x1100, 0x1200, 64, 4),
(0x1100, 0x1200, 0x1200, 0x1300, 64, 4),
(0x1000, 0x1100, 0x1300, 0x1400, 64, 4),
(0x1700, 0x1800, 0x1400, 0x1500, 64, 4),
(0x1600, 0x1700, 0x1500, 0x1600, 64, 4),
(0x1500, 0x1600, 0x1600, 0x1700, 64, 4),
(0x1400, 0x1500, 0x1700, 0x1800, 64, 4),
(0x1B00, 0x1c00, 0x1800, 0x1900, 64, 4),
(0x1a00, 0x1b00, 0x1900, 0x1A00, 64, 4),
(0x1900, 0x1a00, 0x1A00, 0x1B00, 64, 4),
(0x1800, 0x1900, 0x1B00, 0x1C00, 64, 4),
(0x1f00, 0x2000, 0x1C00, 0x1D00, 64, 4),
(0x1e00, 0x1f00, 0x1D00, 0x1E00, 64, 4),
(0x1d00, 0x1e00, 0x1E00, 0x1F00, 64, 4),
(0x1c00, 0x1d00, 0x1F00, 0x2000, 64, 4),
(0x2300, 0x2400, 0x2000, 0x2100, 64, 4),
(0x2200, 0x2300, 0x2100, 0x2200, 64, 4),
(0x2100, 0x2200, 0x2200, 0x2300, 64, 4),
(0x2000, 0x2100, 0x2300, 0x2400, 64, 4),
(0x2700, 0x2800, 0x2400, 0x2500, 64, 4),
(0x2600, 0x2700, 0x2500, 0x2600, 64, 4),
(0x2500, 0x2600, 0x2600, 0x2700, 64, 4),
(0x2400, 0x2500, 0x2700, 0x2800, 64, 4),
(0x2B00, 0x2C00, 0x2800, 0x2900, 64, 4),
(0x2a00, 0x2b00, 0x2900, 0x2A00, 64, 4),
(0x2900, 0x2a00, 0x2A00, 0x2B00, 64, 4),
(0x2800, 0x2900, 0x2B00, 0x2C00, 64, 4),
(0x2f00, 0x3000, 0x2C00, 0x2D00, 64, 4),
(0x2e00, 0x2f00, 0x2D00, 0x2E00, 64, 4),
(0x2d00, 0x2e00, 0x2E00, 0x2F00, 64, 4),
(0x2c00, 0x2d00, 0x2F00, 0x3000, 64, 4),
(0x3300, 0x3400, 0x3000, 0x3100, 64, 4),
(0x3200, 0x3300, 0x3100, 0x3200, 64, 4),
(0x3100, 0x3200, 0x3200, 0x3300, 64, 4),
(0x3000, 0x3100, 0x3300, 0x3400, 64, 4),
(0x3700, 0x3800, 0x3400, 0x3500, 64, 4),
(0x3600, 0x3700, 0x3500, 0x3600, 64, 4),
(0x3500, 0x3600, 0x3600, 0x3700, 64, 4),
(0x3400, 0x3500, 0x3700, 0x3800, 64, 4),
(0x3B00, 0x3C00, 0x3800, 0x3900, 64, 4),
(0x3a00, 0x3b00, 0x3900, 0x3A00, 64, 4),
(0x3900, 0x3a00, 0x3A00, 0x3B00, 64, 4),
(0x3800, 0x3900, 0x3B00, 0x3C00, 64, 4),
(0x3f00, 0x4000, 0x3C00, 0x3D00, 64, 4),
(0x3e00, 0x3f00, 0x3D00, 0x3E00, 64, 4),
(0x3d00, 0x3e00, 0x3E00, 0x3F00, 64, 4),
(0x3c00, 0x3d00, 0x3F00, 0x4000, 64, 4),
(0x4300, 0x4400, 0x4000, 0x4100, 64, 4),
(0x4200, 0x4300, 0x4100, 0x4200, 64, 4),
(0x4100, 0x4200, 0x4200, 0x4300, 64, 4),
(0x4000, 0x4100, 0x4300, 0x4400, 64, 4),
(0x4700, 0x4760, 0x4400, 0x4460, 32, 3), # End of Ch Data
(0x4760, 0x4800, 0x4460, 0x4500, 32, 5), # start of Ch names
(0x4600, 0x4700, 0x4500, 0x4600, 64, 4),
(0x4500, 0x4600, 0x4600, 0x4700, 64, 4),
(0x4400, 0x4500, 0x4700, 0x4800, 64, 4),
(0x4b00, 0x4c00, 0x4800, 0x4900, 64, 4),
(0x4a00, 0x4B00, 0x4900, 0x4A00, 64, 4),
(0x4900, 0x4a00, 0x4A00, 0x4B00, 64, 4),
(0x4800, 0x4900, 0x4B00, 0x4C00, 64, 4),
(0x4f00, 0x5000, 0x4C00, 0x4D00, 64, 4),
(0x4E00, 0x4F00, 0x4D00, 0x4E00, 64, 4),
(0x4D00, 0x4E00, 0x4E00, 0x4F00, 64, 4),
(0x4C00, 0x4d00, 0x4F00, 0x5000, 64, 4),
(0x5300, 0x5400, 0x5000, 0x5100, 64, 4),
(0x5200, 0x5300, 0x5100, 0x5200, 64, 4),
(0x5100, 0x5200, 0x5200, 0x5300, 64, 4),
(0x5000, 0x5100, 0x5300, 0x5400, 64, 4),
(0x5700, 0x5800, 0x5400, 0x5500, 64, 4),
(0x5600, 0x5700, 0x5500, 0x5600, 64, 4),
(0x5500, 0x5600, 0x5600, 0x5700, 64, 4),
(0x5400, 0x5500, 0x5700, 0x5800, 64, 4),
(0x5B00, 0x5C00, 0x5800, 0x5900, 64, 4),
(0x5A00, 0x5B00, 0x5900, 0x5A00, 64, 4),
(0x5900, 0x5A00, 0x5A00, 0x5B00, 64, 4),
(0x5800, 0x5900, 0x5B00, 0x5C00, 64, 4),
(0x5F00, 0x6000, 0x5C00, 0x5D00, 64, 4),
(0x5E00, 0x5F00, 0x5D00, 0x5E00, 64, 4),
(0x5D00, 0x5E00, 0x5E00, 0x5F00, 64, 4),
(0x5C00, 0x5D00, 0x5F00, 0x6000, 64, 4),
(0x6300, 0x6400, 0x6000, 0x6100, 64, 4),
(0x6200, 0x6300, 0x6100, 0x6200, 64, 4),
(0x6100, 0x6200, 0x6200, 0x6300, 64, 4),
(0x6000, 0x6100, 0x6300, 0x6400, 64, 4),
(0x6700, 0x6800, 0x6400, 0x6500, 64, 4),
(0x6600, 0x6700, 0x6500, 0x6600, 64, 4),
(0x6500, 0x6600, 0x6600, 0x6700, 64, 4),
(0x6400, 0x6500, 0x6700, 0x6800, 64, 4),
(0x6b00, 0x6c00, 0x6800, 0x6900, 64, 4),
(0x6a00, 0x6b00, 0x6900, 0x6A00, 64, 4),
(0x6900, 0x6a00, 0x6A00, 0x6B00, 64, 4),
(0x6800, 0x6900, 0x6B00, 0x6C00, 64, 4),
(0x6F00, 0x7000, 0x6C00, 0x6D00, 64, 4),
(0x6e00, 0x6F00, 0x6D00, 0x6E00, 64, 4),
(0x6D00, 0x6E00, 0x6E00, 0x6F00, 64, 4),
(0x6C00, 0x6D00, 0x6F00, 0x7000, 64, 4),
(0x7300, 0x7400, 0x7000, 0x7100, 64, 4),
(0x7200, 0x7300, 0x7100, 0x7200, 64, 4),
(0x7100, 0x7200, 0x7200, 0x7300, 64, 4),
(0x7000, 0x7040, 0x7300, 0x7340, 64, 1), # End of Ch Names
(0x7040, 0x7100, 0x7340, 0x7400, 64, 3), # start of ch valid
(0x7700, 0x7800, 0x7400, 0x7500, 64, 4),
(0x7600, 0x7700, 0x7500, 0x7600, 64, 4),
(0x7500, 0x7600, 0x7600, 0x7700, 64, 4),
(0x7400, 0x7440, 0x7700, 0x7740, 64, 1), # end of ch valid
(0x7440, 0x74e0, 0x7740, 0x77e0, 32, 5), # scan groups
(0x74e0, 0x74e8, 0x77e0, 0x77e8, 8, 1), # VFO Scan range
(0x7bB0, 0x7c00, 0x78B0, 0x7900, 16, 5), # FM presets / Call ID Start
(0x7a00, 0x7b00, 0x7900, 0x7A00, 64, 4),
(0x7900, 0x7a00, 0x7A00, 0x7B00, 64, 4),
(0x7800, 0x7900, 0x7B00, 0x7C00, 64, 4), # Call ID end / Call Name Start
(0x7f00, 0x8000, 0x7C00, 0x7D00, 64, 4),
(0x7e00, 0x7f00, 0x7D00, 0x7E00, 64, 4),
(0x7d00, 0x7e00, 0x7E00, 0x7F00, 64, 4),
(0x7c00, 0x7d00, 0x7F00, 0x8000, 64, 4), # Call Name End
)

Q10G_upload_map_nolims = (
# This map serves 2 purposes-
# To limit the Upload to Radio Writes to known settings only
# And also to send the rearranged Chirp Memory data back to the radio
# using the proper radio addresses.
# Radio Radio Chirp Chirp Blk cnt
# start end start end sz
# (0x0300, 0x0400, 0x0000, 0x0100, 64, 4),
# (0x0200, 0x0300, 0x0100, 0x0200, 64, 4),
# (0x0100, 0x0200, 0x0200, 0x0300, 64, 4),
# (0x030A, 0x030A, 0x000a, 0x000a, 1, 1), # Unlock
(0x0040, 0x0100, 0x0340, 0x0400, 64, 3), # settings
(0x0700, 0x0800, 0x0400, 0x0500, 64, 4), # channel data
(0x0600, 0x0700, 0x0500, 0x0600, 64, 4),
(0x0500, 0x0600, 0x0600, 0x0700, 64, 4),
(0x0400, 0x0500, 0x0700, 0x0800, 64, 4),
(0x0b00, 0x0c00, 0x0800, 0x0900, 64, 4),
(0x0a00, 0x0b00, 0x0900, 0x0A00, 64, 4),
(0x0900, 0x0a00, 0x0A00, 0x0B00, 64, 4),
(0x0800, 0x0900, 0x0B00, 0x0C00, 64, 4),
(0x0f00, 0x1000, 0x0C00, 0x0D00, 64, 4),
(0x0e00, 0x0f00, 0x0D00, 0x0E00, 64, 4),
(0x0d00, 0x0e00, 0x0E00, 0x0F00, 64, 4),
(0x0c00, 0x0d00, 0x0F00, 0x1000, 64, 4),
(0x1300, 0x1400, 0x1000, 0x1100, 64, 4),
(0x1200, 0x1300, 0x1100, 0x1200, 64, 4),
(0x1100, 0x1200, 0x1200, 0x1300, 64, 4),
(0x1000, 0x1100, 0x1300, 0x1400, 64, 4),
(0x1700, 0x1800, 0x1400, 0x1500, 64, 4),
(0x1600, 0x1700, 0x1500, 0x1600, 64, 4),
(0x1500, 0x1600, 0x1600, 0x1700, 64, 4),
(0x1400, 0x1500, 0x1700, 0x1800, 64, 4),
(0x1B00, 0x1c00, 0x1800, 0x1900, 64, 4),
(0x1a00, 0x1b00, 0x1900, 0x1A00, 64, 4),
(0x1900, 0x1a00, 0x1A00, 0x1B00, 64, 4),
(0x1800, 0x1900, 0x1B00, 0x1C00, 64, 4),
(0x1f00, 0x2000, 0x1C00, 0x1D00, 64, 4),
(0x1e00, 0x1f00, 0x1D00, 0x1E00, 64, 4),
(0x1d00, 0x1e00, 0x1E00, 0x1F00, 64, 4),
(0x1c00, 0x1d00, 0x1F00, 0x2000, 64, 4),
(0x2300, 0x2400, 0x2000, 0x2100, 64, 4),
(0x2200, 0x2300, 0x2100, 0x2200, 64, 4),
(0x2100, 0x2200, 0x2200, 0x2300, 64, 4),
(0x2000, 0x2100, 0x2300, 0x2400, 64, 4),
(0x2700, 0x2800, 0x2400, 0x2500, 64, 4),
(0x2600, 0x2700, 0x2500, 0x2600, 64, 4),
(0x2500, 0x2600, 0x2600, 0x2700, 64, 4),
(0x2400, 0x2500, 0x2700, 0x2800, 64, 4),
(0x2B00, 0x2C00, 0x2800, 0x2900, 64, 4),
(0x2a00, 0x2b00, 0x2900, 0x2A00, 64, 4),
(0x2900, 0x2a00, 0x2A00, 0x2B00, 64, 4),
(0x2800, 0x2900, 0x2B00, 0x2C00, 64, 4),
(0x2f00, 0x3000, 0x2C00, 0x2D00, 64, 4),
(0x2e00, 0x2f00, 0x2D00, 0x2E00, 64, 4),
(0x2d00, 0x2e00, 0x2E00, 0x2F00, 64, 4),
(0x2c00, 0x2d00, 0x2F00, 0x3000, 64, 4),
(0x3300, 0x3400, 0x3000, 0x3100, 64, 4),
(0x3200, 0x3300, 0x3100, 0x3200, 64, 4),
(0x3100, 0x3200, 0x3200, 0x3300, 64, 4),
(0x3000, 0x3100, 0x3300, 0x3400, 64, 4),
(0x3700, 0x3800, 0x3400, 0x3500, 64, 4),
(0x3600, 0x3700, 0x3500, 0x3600, 64, 4),
(0x3500, 0x3600, 0x3600, 0x3700, 64, 4),
(0x3400, 0x3500, 0x3700, 0x3800, 64, 4),
(0x3B00, 0x3C00, 0x3800, 0x3900, 64, 4),
(0x3a00, 0x3b00, 0x3900, 0x3A00, 64, 4),
(0x3900, 0x3a00, 0x3A00, 0x3B00, 64, 4),
(0x3800, 0x3900, 0x3B00, 0x3C00, 64, 4),
(0x3f00, 0x4000, 0x3C00, 0x3D00, 64, 4),
(0x3e00, 0x3f00, 0x3D00, 0x3E00, 64, 4),
(0x3d00, 0x3e00, 0x3E00, 0x3F00, 64, 4),
(0x3c00, 0x3d00, 0x3F00, 0x4000, 64, 4),
(0x4300, 0x4400, 0x4000, 0x4100, 64, 4),
(0x4200, 0x4300, 0x4100, 0x4200, 64, 4),
(0x4100, 0x4200, 0x4200, 0x4300, 64, 4),
(0x4000, 0x4100, 0x4300, 0x4400, 64, 4),
(0x4700, 0x4760, 0x4400, 0x4460, 32, 3), # End of Ch Data
(0x4760, 0x4800, 0x4460, 0x4500, 32, 5), # start of Ch names
(0x4600, 0x4700, 0x4500, 0x4600, 64, 4),
(0x4500, 0x4600, 0x4600, 0x4700, 64, 4),
(0x4400, 0x4500, 0x4700, 0x4800, 64, 4),
(0x4b00, 0x4c00, 0x4800, 0x4900, 64, 4),
(0x4a00, 0x4B00, 0x4900, 0x4A00, 64, 4),
(0x4900, 0x4a00, 0x4A00, 0x4B00, 64, 4),
(0x4800, 0x4900, 0x4B00, 0x4C00, 64, 4),
(0x4f00, 0x5000, 0x4C00, 0x4D00, 64, 4),
(0x4E00, 0x4F00, 0x4D00, 0x4E00, 64, 4),
(0x4D00, 0x4E00, 0x4E00, 0x4F00, 64, 4),
(0x4C00, 0x4d00, 0x4F00, 0x5000, 64, 4),
(0x5300, 0x5400, 0x5000, 0x5100, 64, 4),
(0x5200, 0x5300, 0x5100, 0x5200, 64, 4),
(0x5100, 0x5200, 0x5200, 0x5300, 64, 4),
(0x5000, 0x5100, 0x5300, 0x5400, 64, 4),
(0x5700, 0x5800, 0x5400, 0x5500, 64, 4),
(0x5600, 0x5700, 0x5500, 0x5600, 64, 4),
(0x5500, 0x5600, 0x5600, 0x5700, 64, 4),
(0x5400, 0x5500, 0x5700, 0x5800, 64, 4),
(0x5B00, 0x5C00, 0x5800, 0x5900, 64, 4),
(0x5A00, 0x5B00, 0x5900, 0x5A00, 64, 4),
(0x5900, 0x5A00, 0x5A00, 0x5B00, 64, 4),
(0x5800, 0x5900, 0x5B00, 0x5C00, 64, 4),
(0x5F00, 0x6000, 0x5C00, 0x5D00, 64, 4),
(0x5E00, 0x5F00, 0x5D00, 0x5E00, 64, 4),
(0x5D00, 0x5E00, 0x5E00, 0x5F00, 64, 4),
(0x5C00, 0x5D00, 0x5F00, 0x6000, 64, 4),
(0x6300, 0x6400, 0x6000, 0x6100, 64, 4),
(0x6200, 0x6300, 0x6100, 0x6200, 64, 4),
(0x6100, 0x6200, 0x6200, 0x6300, 64, 4),
(0x6000, 0x6100, 0x6300, 0x6400, 64, 4),
(0x6700, 0x6800, 0x6400, 0x6500, 64, 4),
(0x6600, 0x6700, 0x6500, 0x6600, 64, 4),
(0x6500, 0x6600, 0x6600, 0x6700, 64, 4),
(0x6400, 0x6500, 0x6700, 0x6800, 64, 4),
(0x6b00, 0x6c00, 0x6800, 0x6900, 64, 4),
(0x6a00, 0x6b00, 0x6900, 0x6A00, 64, 4),
(0x6900, 0x6a00, 0x6A00, 0x6B00, 64, 4),
(0x6800, 0x6900, 0x6B00, 0x6C00, 64, 4),
(0x6F00, 0x7000, 0x6C00, 0x6D00, 64, 4),
(0x6e00, 0x6F00, 0x6D00, 0x6E00, 64, 4),
(0x6D00, 0x6E00, 0x6E00, 0x6F00, 64, 4),
(0x6C00, 0x6D00, 0x6F00, 0x7000, 64, 4),
(0x7300, 0x7400, 0x7000, 0x7100, 64, 4),
(0x7200, 0x7300, 0x7100, 0x7200, 64, 4),
(0x7100, 0x7200, 0x7200, 0x7300, 64, 4),
(0x7000, 0x7040, 0x7300, 0x7340, 64, 1), # End of Ch Names
(0x7040, 0x7100, 0x7340, 0x7400, 64, 3), # start of ch valid
(0x7700, 0x7800, 0x7400, 0x7500, 64, 4),
(0x7600, 0x7700, 0x7500, 0x7600, 64, 4),
(0x7500, 0x7600, 0x7600, 0x7700, 64, 4),
(0x7400, 0x7440, 0x7700, 0x7740, 64, 1), # end of ch valid
(0x7440, 0x74e0, 0x7740, 0x77e0, 32, 5), # scan groups
(0x74e0, 0x74e8, 0x77e0, 0x77e8, 8, 1), # VFO Scan range
(0x7bB0, 0x7c00, 0x78B0, 0x7900, 16, 5), # FM presets / Call ID Start
(0x7a00, 0x7b00, 0x7900, 0x7A00, 64, 4),
(0x7900, 0x7a00, 0x7A00, 0x7B00, 64, 4),
(0x7800, 0x7900, 0x7B00, 0x7C00, 64, 4), # Call ID end / Call Name Start
(0x7f00, 0x8000, 0x7C00, 0x7D00, 64, 4),
(0x7e00, 0x7f00, 0x7D00, 0x7E00, 64, 4),
(0x7d00, 0x7e00, 0x7E00, 0x7F00, 64, 4),
(0x7c00, 0x7d00, 0x7F00, 0x8000, 64, 4), # Call Name End
)


Q10H_upload_map_OLD = (
# OLD MAP before rearranging 0-400 - EVENTUALLY DELETE
# This map serves 2 purposes-
# To limit the Upload to Radio Writes to known settings only
# And also to send the rearranged Chirp Memory data back to the radio
# using the proper radio addresses.
# Radio Radio Chirp Chirp Blk cnt
# start end start end sz
# (0x0000, 0x0400, 0x0000, 0x0400, 64, 16),
# (0x0600, 0x06E0, 0x0400, 0x04E0, 32, 7),
(0x0002, 0x0022, 0x0002, 0x0022, 32, 1), # Tx Limits
(0x00a6, 0x00fe, 0x00a6, 0x00fe, 8, 11), # Rx Limits
(0x030a, 0x030a, 0x030a, 0x030a, 1, 1), # Factory Locked Mode
(0x0640, 0x06c0, 0x0440, 0x04c0, 32, 7), # VFO settings
(0x0700, 0x0800, 0x04E0, 0x05E0, 64, 4), # settings
(0x06E0, 0x0700, 0x05E0, 0x0600, 32, 1), # channel 1 data start
(0x0500, 0x0600, 0x0600, 0x0700, 64, 4),
(0x0400, 0x0500, 0x0700, 0x0800, 64, 4),
(0x0b00, 0x0c00, 0x0800, 0x0900, 64, 4),
(0x0a00, 0x0b00, 0x0900, 0x0A00, 64, 4),
(0x0900, 0x0a00, 0x0A00, 0x0B00, 64, 4),
(0x0800, 0x0900, 0x0B00, 0x0C00, 64, 4),
(0x0f00, 0x1000, 0x0C00, 0x0D00, 64, 4),
(0x0e00, 0x0f00, 0x0D00, 0x0E00, 64, 4),
(0x0d00, 0x0e00, 0x0E00, 0x0F00, 64, 4),
(0x0c00, 0x0d00, 0x0F00, 0x1000, 64, 4),
(0x1300, 0x1400, 0x1000, 0x1100, 64, 4),
(0x1200, 0x1300, 0x1100, 0x1200, 64, 4),
(0x1100, 0x1200, 0x1200, 0x1300, 64, 4),
(0x1000, 0x1100, 0x1300, 0x1400, 64, 4),
(0x1700, 0x1800, 0x1400, 0x1500, 64, 4),
(0x1600, 0x1700, 0x1500, 0x1600, 64, 4),
(0x1500, 0x1600, 0x1600, 0x1700, 64, 4),
(0x1400, 0x1500, 0x1700, 0x1800, 64, 4),
(0x1B00, 0x1c00, 0x1800, 0x1900, 64, 4),
(0x1a00, 0x1b00, 0x1900, 0x1A00, 64, 4),
(0x1900, 0x1a00, 0x1A00, 0x1B00, 64, 4),
(0x1800, 0x1900, 0x1B00, 0x1C00, 64, 4),
(0x1f00, 0x2000, 0x1C00, 0x1D00, 64, 4),
(0x1e00, 0x1f00, 0x1D00, 0x1E00, 64, 4),
(0x1d00, 0x1e00, 0x1E00, 0x1F00, 64, 4),
(0x1c00, 0x1d00, 0x1F00, 0x2000, 64, 4),
(0x2300, 0x2400, 0x2000, 0x2100, 64, 4),
(0x2200, 0x2300, 0x2100, 0x2200, 64, 4),
(0x2100, 0x2200, 0x2200, 0x2300, 64, 4),
(0x2000, 0x2100, 0x2300, 0x2400, 64, 4),
(0x2700, 0x2800, 0x2400, 0x2500, 64, 4),
(0x2600, 0x2700, 0x2500, 0x2600, 64, 4),
(0x2500, 0x2600, 0x2600, 0x2700, 64, 4),
(0x2400, 0x2500, 0x2700, 0x2800, 64, 4),
(0x2B00, 0x2C00, 0x2800, 0x2900, 64, 4),
(0x2a00, 0x2b00, 0x2900, 0x2A00, 64, 4),
(0x2900, 0x2a00, 0x2A00, 0x2B00, 64, 4),
(0x2800, 0x2900, 0x2B00, 0x2C00, 64, 4),
(0x2f00, 0x3000, 0x2C00, 0x2D00, 64, 4),
(0x2e00, 0x2f00, 0x2D00, 0x2E00, 64, 4),
(0x2d00, 0x2e00, 0x2E00, 0x2F00, 64, 4),
(0x2c00, 0x2d00, 0x2F00, 0x3000, 64, 4),
(0x3300, 0x3400, 0x3000, 0x3100, 64, 4),
(0x3200, 0x3300, 0x3100, 0x3200, 64, 4),
(0x3100, 0x3200, 0x3200, 0x3300, 64, 4),
(0x3000, 0x3100, 0x3300, 0x3400, 64, 4),
(0x3700, 0x3800, 0x3400, 0x3500, 64, 4),
(0x3600, 0x3700, 0x3500, 0x3600, 64, 4),
(0x3500, 0x3600, 0x3600, 0x3700, 64, 4),
(0x3400, 0x3500, 0x3700, 0x3800, 64, 4),
(0x3B00, 0x3C00, 0x3800, 0x3900, 64, 4),
(0x3a00, 0x3b00, 0x3900, 0x3A00, 64, 4),
(0x3900, 0x3a00, 0x3A00, 0x3B00, 64, 4),
(0x3800, 0x3900, 0x3B00, 0x3C00, 64, 4),
(0x3f00, 0x4000, 0x3C00, 0x3D00, 64, 4),
(0x3e00, 0x3f00, 0x3D00, 0x3E00, 64, 4),
(0x3d00, 0x3e00, 0x3E00, 0x3F00, 64, 4),
(0x3c00, 0x3d00, 0x3F00, 0x4000, 64, 4),
(0x4300, 0x4400, 0x4000, 0x4100, 64, 4),
(0x4200, 0x4300, 0x4100, 0x4200, 64, 4),
(0x4100, 0x4200, 0x4200, 0x4300, 64, 4),
(0x4000, 0x4100, 0x4300, 0x4400, 64, 4),
(0x4700, 0x4760, 0x4400, 0x4460, 32, 3), # End of Ch Data
(0x4760, 0x4800, 0x4460, 0x4500, 32, 5), # start of Ch names
(0x4600, 0x4700, 0x4500, 0x4600, 64, 4),
(0x4500, 0x4600, 0x4600, 0x4700, 64, 4),
(0x4400, 0x4500, 0x4700, 0x4800, 64, 4),
(0x4b00, 0x4c00, 0x4800, 0x4900, 64, 4),
(0x4a00, 0x4B00, 0x4900, 0x4A00, 64, 4),
(0x4900, 0x4a00, 0x4A00, 0x4B00, 64, 4),
(0x4800, 0x4900, 0x4B00, 0x4C00, 64, 4),
(0x4f00, 0x5000, 0x4C00, 0x4D00, 64, 4),
(0x4E00, 0x4F00, 0x4D00, 0x4E00, 64, 4),
(0x4D00, 0x4E00, 0x4E00, 0x4F00, 64, 4),
(0x4C00, 0x4d00, 0x4F00, 0x5000, 64, 4),
(0x5300, 0x5400, 0x5000, 0x5100, 64, 4),
(0x5200, 0x5300, 0x5100, 0x5200, 64, 4),
(0x5100, 0x5200, 0x5200, 0x5300, 64, 4),
(0x5000, 0x5100, 0x5300, 0x5400, 64, 4),
(0x5700, 0x5800, 0x5400, 0x5500, 64, 4),
(0x5600, 0x5700, 0x5500, 0x5600, 64, 4),
(0x5500, 0x5600, 0x5600, 0x5700, 64, 4),
(0x5400, 0x5500, 0x5700, 0x5800, 64, 4),
(0x5B00, 0x5C00, 0x5800, 0x5900, 64, 4),
(0x5A00, 0x5B00, 0x5900, 0x5A00, 64, 4),
(0x5900, 0x5A00, 0x5A00, 0x5B00, 64, 4),
(0x5800, 0x5900, 0x5B00, 0x5C00, 64, 4),
(0x5F00, 0x6000, 0x5C00, 0x5D00, 64, 4),
(0x5E00, 0x5F00, 0x5D00, 0x5E00, 64, 4),
(0x5D00, 0x5E00, 0x5E00, 0x5F00, 64, 4),
(0x5C00, 0x5D00, 0x5F00, 0x6000, 64, 4),
(0x6300, 0x6400, 0x6000, 0x6100, 64, 4),
(0x6200, 0x6300, 0x6100, 0x6200, 64, 4),
(0x6100, 0x6200, 0x6200, 0x6300, 64, 4),
(0x6000, 0x6100, 0x6300, 0x6400, 64, 4),
(0x6700, 0x6800, 0x6400, 0x6500, 64, 4),
(0x6600, 0x6700, 0x6500, 0x6600, 64, 4),
(0x6500, 0x6600, 0x6600, 0x6700, 64, 4),
(0x6400, 0x6500, 0x6700, 0x6800, 64, 4),
(0x6b00, 0x6c00, 0x6800, 0x6900, 64, 4),
(0x6a00, 0x6b00, 0x6900, 0x6A00, 64, 4),
(0x6900, 0x6a00, 0x6A00, 0x6B00, 64, 4),
(0x6800, 0x6900, 0x6B00, 0x6C00, 64, 4),
(0x6F00, 0x7000, 0x6C00, 0x6D00, 64, 4),
(0x6e00, 0x6F00, 0x6D00, 0x6E00, 64, 4),
(0x6D00, 0x6E00, 0x6E00, 0x6F00, 64, 4),
(0x6C00, 0x6D00, 0x6F00, 0x7000, 64, 4),
(0x7300, 0x7400, 0x7000, 0x7100, 64, 4),
(0x7200, 0x7300, 0x7100, 0x7200, 64, 4),
(0x7100, 0x7200, 0x7200, 0x7300, 64, 4),
(0x7000, 0x7040, 0x7300, 0x7340, 64, 1), # End of Ch Names
(0x7040, 0x7100, 0x7340, 0x7400, 64, 3), # start of ch valid
(0x7700, 0x7800, 0x7400, 0x7500, 64, 4),
(0x7600, 0x7700, 0x7500, 0x7600, 64, 4),
(0x7500, 0x7600, 0x7600, 0x7700, 64, 4),
(0x7400, 0x7440, 0x7700, 0x7740, 64, 1), # end of ch valid
# (0x7440, 0x7500, 0x7740, 0x7800, 64, 3),
(0x7440, 0x74e0, 0x7740, 0x77e0, 32, 5), # scan groups
(0x74e0, 0x74e8, 0x77e0, 0x77e8, 8, 1), # VFO Scan range
# (0x7800, 0x8000, 0x7800, 0x8000, 64, 32),
(0x7bB0, 0x7c00, 0x78B0, 0x7900, 16, 5), # FM presets / Call ID Start
(0x7a00, 0x7b00, 0x7900, 0x7A00, 64, 4),
(0x7900, 0x7a00, 0x7A00, 0x7B00, 64, 4),
(0x7800, 0x7900, 0x7B00, 0x7C00, 64, 4), # Call ID end / Call Name Start
(0x7f00, 0x8000, 0x7C00, 0x7D00, 64, 4),
(0x7e00, 0x7f00, 0x7D00, 0x7E00, 64, 4),
(0x7d00, 0x7e00, 0x7E00, 0x7F00, 64, 4),
(0x7c00, 0x7d00, 0x7F00, 0x8000, 64, 4), # Call Name End
# (0x7bb0, 0x7bf0, 0x7bb0, 0x7bf0, 16, 3) # FM Radio Presets
)

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

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

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

# PFKEYLONG_LIST = ["undef", "FRQ2-PTT", "Selec Call", "Favorite",
# "Bright+", "Scan", "Flashlight", "Alarm", "SOS",
# "FM Radio", "Moni", "Strobe", "Weather", "Tlk A",
# "Reverse", "CTC Scan", "DCS Scan", "Backlight"]
# PFKEYSHORT_LIST = ["undef", "Favorite", "Bright+", "Scan",
# "Flashlight", "Alarm", "SOS", "FM Radio",
# "Moni", "Strobe", "Weather", "Tlk A", "Reverse",
# "CTC Scan", "DCS Scan", "Backlight"]
WORKMODE_LIST = ["VFO", "Ch.Number.", "Ch.Freq.", "Ch.Name"]
BACKLIGHT_LIST = ["Always On"] + [str(x) + "s" for x in range(1, 21)] + \
["Always Off"]
OFFSET_LIST = ["OFF", "Plus Shift", "Minus Shift"]
PONMSG_LIST = ["Startup Display", "Battery Volts"]
SPMUTE_LIST = ["QT", "QT+DTMF", "QT*DTMF"]
DTMFST_LIST = ["OFF", "DTMF", "ANI", "DTMF+ANI"]
DTMF_TIMES = [('%dms' % dtmf, (dtmf // 10)) for dtmf in range(50, 501, 10)]
ALERTS = [1750, 2100, 1000, 1450]
ALERTS_LIST = [str(x) + " Hz" for x in ALERTS]
PTTID_LIST = ["OFF", "BOT", "EOT", "Both"]
MAP_1_99 = [(str(x), x) for x in range(1, 100)]
LIST_10 = ["OFF"] + ["%s" % x for x in range(1, 11)]
LIST_10S = ["OFF"] + ["%s" % x + "s" for x in range(1, 11)]
LIST_TOA = ["OFF"] + ["%s" % x + "s" for x in range(1, 11)]
SCANGRP_LIST = ["All"] + ["%s" % x for x in range(1, 11)]
SMUTESET_LIST = ["OFF", "Rx", "Tx", "Rx+Tx"]
POWER_LIST = ["Lo", "Mid", "Hi", "UltraHigh"]
HOLD_TIMES = ["OFF"] + ["%s" % x + "s" for x in range(100, 5001, 100)]
RPTTYPE_MAP = [("X-DIRPT", 1), ("X-TWRPT", 2)]
THEME_LIST = ["White-1", "White-2", "Black-1", "Black-2",
"Cool", "Rain", "NotARubi", "Sky", "BTWR", "Candy",
"Custom 1", "Custom 2", "Custom 3", "Custom 4"]
DSPBRTSBY_LIST = ["OFF", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
DSPBRTACT_MAP = [("1", 1), ("2", 2), ("3", 3), ("4", 4), ("5", 5),
("6", 6), ("7", 7), ("8", 8), ("9", 9), ("10", 10)]
TONESCANSAVELIST = ["Rx", "Tx", "Tx/Rx"]
PTTDELAY_TIMES = [('%dms' % pttdelay,
(pttdelay // 100)) for pttdelay in range(100, 3001, 100)]
SCRAMBLE_LIST = ["OFF"] + [str(x) for x in range(1, 9)]
ONOFF_LIST = ["OFF", "ON"]
TONE_MAP = [('OFF - No Tone', 0x0000)] + \
[('%.1f' % tone,
int(0x8000 + tone * 10)) for tone in chirp_common.TONES] + \
[('D%03dn' % tone, int(0x4000 + int(str(tone), 8)))
for tone in chirp_common.DTCS_CODES] + \
[('D%03di' % tone, int(0x6000 + int(str(tone), 8)))
for tone in chirp_common.DTCS_CODES]
BATT_DISP_LIST = ["Icon", "Voltage", "Percent"]
WX_TYPE = ["Weather", "Icon-Only", "Tone", "Flash", "Tone-Flash"]
AM_MODE = ["OFF", "AM Rx", "AM Rx+Tx"]
AM_MODE_2 = ["OFF", "AM Rx"]
AM_MODE_CH = [("",0), ("AM Rx", 1), ("AM Rx+Tx", 2)]
AM_MODE_CH2 = [("",0), ("AM Rx", 1)]

TIME_ZONE = ["GMT-12", "GMT-11", "GMT-10", "GMT-9", "GMT-8",
"GMT-7", "GMT-6", "GMT-5", "GMT-4", "GMT-3",
"GMT-2", "GMT-1", "GMT", "GMT+1", "GMT+2",
"GMT+3", "GMT+4", "GMT+5", "GMT+6", "GMT+7",
"GMT+8", "GMT+9", "GMT+10", "GMT+11", "GMT+12"]
GPS_SEND_FREQ = ["OFF", "PTT SEND", "1 min", "2 min", "3 min",
"4 min", "5 min", "6 min", "7 min", "8 min",
"9 min", "10 min"]
VFOABAND_MAP = [("150M", 0),
("400M", 1),
("200M", 2),
("66M", 3),
("800M", 4),
("300M", 5)]
VFOABAND_MAP2 = [("150M", 0),
("400M", 1),
("200M", 2),
("26M", 3),
("800M", 4),
("300M", 5)]

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

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

_MEM_FORMAT_Q10H_oem_read = """
#seekto 0x0002;
struct {
ul32 tworx_start;
ul32 tworx_stop;
ul32 cm70_tx_start; //70cm Tx
ul32 cm70_tx_stop; //70cm Tx
ul32 m125_tx_start; //1.25m Tx
ul32 m125_tx_stop; //1.25m Tx
ul32 m6_tx_start; //6m Tx
ul32 m6_tx_stop; //6m Tx
#seekto 0x00a6;
ul32 rx1lim_start;
ul32 rx1lim_stop;
ul32 rx2lim_start;
ul32 rx2lim_stop;
ul32 rx3lim_start;
ul32 rx3lim_stop;
ul32 rx4lim_start;
ul32 rx4lim_stop;
ul32 rx5lim_start;
ul32 rx5lim_stop;
ul32 rx6lim_start;
ul32 rx6lim_stop;
ul32 rx7lim_start;
ul32 rx7lim_stop;
ul32 rx8lim_start;
ul32 rx8lim_stop;
ul32 m2tx_start; // 2m Tx
ul32 m2tx_stop; // 2m tx
ul32 rx10lim_start;
ul32 rx10lim_stop;
ul32 rx11lim_start;
ul32 rx11lim_stop;
} limits;

#seekto 0x0040;
struct {
char oem1[8];
#seekto 0x006c; //0x002c;
char name[8];
#seekto 0x0092; //0x0052;
char firmware[6];
#seekto 0x0078; //0x0038;
char date[10];
#seekto 0x030a;
u8 locked;
} oem_info;

#seekto 0x7740;
struct {
struct {
ul16 scan_st;
ul16 scan_end;
} addrs[10];
struct {
char name[12];
} names[10];
} scn_grps;

#seekto 0x78e0;
struct {
u8 cid[6];
} call_ids[100];

#seekto 0x7B40;
struct {
char call_name[12];
} call_names[100];


#seekto 0x0520;
struct {
u8 channel_menu;
u8 power_save;
u8 roger_beep;
u8 timeout;
u8 toalarm;
u8 wxalert;
u8 wxalert_type;
u8 vox;
u8 unk_xp8;
u8 voice;
u8 beep;
u8 scan_rev;
u8 backlight;
u8 DspBrtAct;
u8 DspBrtSby;
u8 ponmsg;
u8 ptt_id; //0x530
u8 ptt_delay;
u8 dtmf_st;
u8 dtmf_tx_time;
u8 dtmf_interval;
u8 ring_time;
u8 alert;
u8 autolock;
ul16 pri_ch;
u8 prich_sw;
u8 rpttype;
u8 rpt_spk;
u8 rpt_ptt;
u8 rpt_tone;
u8 rpt_hold;
u8 scan_det;
u8 smuteset; //0x540
u8 batt_ind;
u8 ToneScnSave;
#seekto 0x0544;
u8 theme;
u8 unkx545;
u8 disp_time;
u8 time_zone;
u8 GPS_send_freq;
u8 GPS;
u8 GPS_rcv;
ul16 custcol1_text;
ul16 custcol1_bg;
ul16 custcol1_icon;
ul16 custcol1_line;
ul16 custcol2_text;
ul16 custcol2_bg;
ul16 custcol2_icon;
ul16 custcol2_line;
ul16 custcol3_text;
ul16 custcol3_bg;
ul16 custcol3_icon;
ul16 custcol3_line;
ul16 custcol4_text;
ul16 custcol4_bg;
ul16 custcol4_icon;
ul16 custcol4_line;
// #seekto 0x056b;
char mode_sw_pwd[6];
char reset_pwd[6];
u8 work_mode_a;
u8 work_mode_b;
ul16 work_ch_a;
ul16 work_ch_b;
u8 vfostepA;
u8 vfostepB;
u8 squelchA;
u8 squelchB;
u8 BCL_A;
u8 BCL_B;
u8 vfobandA;
u8 vfobandB;
#seekto 0x0587;
u8 top_short;
u8 top_long;
u8 ptt1;
u8 ptt2;
u8 pf1_short;
u8 pf1_long;
u8 pf2_short;
u8 pf2_long;
u8 ScnGrpA_Act;
u8 ScnGrpB_Act;
u8 vfo_scanmodea;
u8 vfo_scanmodeb; //x592
u8 ani_id[6];
u8 scc[6];
#seekto 0x05A1;
u8 act_area;
u8 tdr;
u8 keylock;
#seekto 0x05A9;
char dispstr[12];
#seekto 0x05BD;
char areamsg[12];
u8 xunk_1;
u8 xunk_2;
u8 xunk_ani_sw;
u8 xani_code[6];
u8 xpf1_shrt;
u8 xpf1_long;
u8 xpf2_shrt;
u8 xpf2_long;
u8 main_band;
u8 xTDR_single_mode;
u8 xunk1;
u8 xunk2;
u8 cur_call_grp;
u8 VFO_repeater_a;
u8 VFO_repeater_b;
u8 sim_rec;
} settings;

#seekto 0x78B0;
struct {
ul16 FM_radio;
} fm[20];

#seekto 0x0440;
struct {
ul32 rxfreq;
ul32 offset;
ul16 rxtone;
ul16 txtone;
u8 scrambler:4,
am_mode:2,
power:2;
u8 ofst_dir:3,
unknown:1,
compander:1,
mute_mode:2,
iswide:1;
u8 call_group;
u8 unknown6;
} vfoa[6];

#seekto 0x04a0;
struct {
ul32 rxfreq;
ul32 offset;
ul16 rxtone;
ul16 txtone;
u8 scrambler:4,
am_mode:2,
power:2;
u8 ofst_dir:3,
unknown:1,
compander:1,
mute_mode:2,
iswide:1;
u8 call_group;
u8 unknown6;
} vfob[2];

#seekto 0x05E0;
struct {
ul32 rxfreq;
ul32 txfreq;
ul16 rxtone;
ul16 txtone;
u8 scrambler:4,
am_mode:2,
power:2;
u8 unknown3:1,
send_loc:1,
scan_add:1,
favorite:1,
compander:1,
mute_mode:2,
iswide:1;
u8 call_group;
u8 unknown6;
} memory[1000];

#seekto 0x4460;
struct {
u8 name[12];
} names[1000];

#seekto 0x7340;
u8 valid[1000];

#seekto 0x77E0;
struct {
ul16 vfo_scan_start_A;
ul16 vfo_scan_end_A;
ul16 vfo_scan_start_B;
ul16 vfo_scan_end_B;
} vfo_scan;

"""

_MEM_FORMAT_Q10H_oem_read2 = """
#seekto 0x02c2;
struct {
ul32 rx12lim_start;
ul32 rx12lim_stop;
ul32 rx13lim_start;
ul32 rx13lim_stop;
ul32 rx14lim_start;
ul32 rx14lim_stop;
ul32 rx15lim_start;
ul32 rx15lim_stop;
ul32 rx16lim_start;
ul32 rx16lim_stop;
ul32 rx17lim_start;
ul32 rx17lim_stop;
ul32 rx18lim_start;
ul32 rx18lim_stop;
ul32 rx19lim_start;
ul32 rx19lim_stop;
#seekto 0x0302;
ul32 tworx_start;
ul32 tworx_stop;
ul32 cm70_tx_start; //70cm Tx
ul32 cm70_tx_stop; //70cm Tx
ul32 m125_tx_start; //1.25m Tx
ul32 m125_tx_stop; //1.25m Tx
ul32 m6_tx_start; //6m Tx
ul32 m6_tx_stop; //6m Tx
#seekto 0x03a6;
ul32 rx1lim_start;
ul32 rx1lim_stop;
ul32 rx2lim_start;
ul32 rx2lim_stop;
ul32 rx3lim_start;
ul32 rx3lim_stop;
ul32 rx4lim_start;
ul32 rx4lim_stop;
ul32 rx5lim_start;
ul32 rx5lim_stop;
ul32 rx6lim_start;
ul32 rx6lim_stop;
ul32 rx7lim_start;
ul32 rx7lim_stop;
ul32 rx8lim_start;
ul32 rx8lim_stop;
ul32 m2tx_start; // 2m Tx
ul32 m2tx_stop; // 2m tx
ul32 rx10lim_start;
ul32 rx10lim_stop;
ul32 rx11lim_start;
ul32 rx11lim_stop;
#seekto 0x3a6;
struct {
ul32 lim_start;
ul32 lim_stop;
} more_limits[14];
} limits;

#seekto 0x0340;
struct {
char oem1[8];
#seekto 0x036c; //0x002c;
char name[8];
#seekto 0x0392; //0x0052;
char firmware[6];
#seekto 0x0378; //0x0038;
char date[10];
#seekto 0x000a;
u8 locked;
} oem_info;

#seekto 0x7740;
struct {
struct {
ul16 scan_st;
ul16 scan_end;
} addrs[10];
struct {
char name[12];
} names[10];
} scn_grps;

#seekto 0x78e0;
struct {
u8 cid[6];
} call_ids[100];

#seekto 0x7B40;
struct {
char call_name[12];
} call_names[100];


#seekto 0x0440;
struct {
u8 channel_menu;
u8 power_save;
u8 roger_beep;
u8 timeout;
u8 toalarm;
u8 wxalert;
u8 wxalert_type;
u8 vox;
u8 unk_xp8;
u8 voice;
u8 beep;
u8 scan_rev;
u8 backlight;
u8 DspBrtAct;
u8 DspBrtSby;
u8 ponmsg;
u8 ptt_id; //0x530
u8 ptt_delay;
u8 dtmf_st;
u8 dtmf_tx_time;
u8 dtmf_interval;
u8 ring_time;
u8 alert;
u8 autolock;
ul16 pri_ch;
u8 prich_sw;
u8 rpttype;
u8 rpt_spk;
u8 rpt_ptt;
u8 rpt_tone;
u8 rpt_hold;
u8 scan_det;
u8 smuteset; //0x540
u8 batt_ind;
u8 ToneScnSave;
#seekto 0x0464;
u8 theme;
u8 unkx545;
u8 disp_time;
u8 time_zone;
u8 GPS_send_freq;
u8 GPS;
u8 GPS_rcv;
ul16 custcol1_text;
ul16 custcol1_bg;
ul16 custcol1_icon;
ul16 custcol1_line;
ul16 custcol2_text;
ul16 custcol2_bg;
ul16 custcol2_icon;
ul16 custcol2_line;
ul16 custcol3_text;
ul16 custcol3_bg;
ul16 custcol3_icon;
ul16 custcol3_line;
ul16 custcol4_text;
ul16 custcol4_bg;
ul16 custcol4_icon;
ul16 custcol4_line;
// #seekto 0x048b;
char mode_sw_pwd[6];
char reset_pwd[6];
u8 work_mode_a;
u8 work_mode_b;
ul16 work_ch_a;
ul16 work_ch_b;
u8 vfostepA;
u8 vfostepB;
u8 squelchA;
u8 squelchB;
u8 BCL_A;
u8 BCL_B;
u8 vfobandA;
u8 vfobandB;
#seekto 0x04a7;
u8 top_short;
u8 top_long;
u8 ptt1;
u8 ptt2;
u8 pf1_short;
u8 pf1_long;
u8 pf2_short;
u8 pf2_long;
u8 ScnGrpA_Act;
u8 ScnGrpB_Act;
u8 vfo_scanmodea;
u8 vfo_scanmodeb; //x592
u8 ani_id[6];
u8 scc[6];
#seekto 0x04c1;
u8 act_area;
u8 tdr;
u8 keylock;
#seekto 0x04c7;
u8 stopwatch; //0x04c7
u8 x0x04c8;
char dispstr[12];
#seekto 0x04dD;
char areamsg[12];
u8 xUnk_1;
u8 xunk_2;
u8 xunk_ani_sw;
u8 xani_code[6];
u8 xpf1_shrt;
u8 xpf1_long;
u8 xpf2_shrt;
u8 xpf2_long;
u8 main_band;
u8 xTDR_single_mode;
u8 xunk1;
u8 xunk2;
u8 cur_call_grp;
u8 VFO_repeater_a;
u8 VFO_repeater_b;
u8 sim_rec;
} settings;

#seekto 0x78B0;
struct {
ul16 FM_radio;
} fm[20];

#seekto 0x0540;
struct {
ul32 rxfreq;
ul32 offset;
ul16 rxtone;
ul16 txtone;
u8 scrambler:4,
am_mode:2,
power:2;
u8 ofst_dir:3,
unknown:1,
compander:1,
mute_mode:2,
iswide:1;
u8 call_group;
u8 unknown6;
} vfoa[6];

#seekto 0x05a0;
struct {
ul32 rxfreq;
ul32 offset;
ul16 rxtone;
ul16 txtone;
u8 scrambler:4,
am_mode:2,
power:2;
u8 ofst_dir:3,
unknown:1,
compander:1,
mute_mode:2,
iswide:1;
u8 call_group;
u8 unknown6;
} vfob[2];

#seekto 0x05E0;
struct {
ul32 rxfreq;
ul32 txfreq;
ul16 rxtone;
ul16 txtone;
u8 scrambler:4,
am_mode:2,
power:2;
u8 unknown3:1,
send_loc:1,
scan_add:1,
favorite:1,
compander:1,
mute_mode:2,
iswide:1;
u8 call_group;
u8 unknown6;
} memory[1000];

#seekto 0x4460;
struct {
u8 name[12];
} names[1000];

#seekto 0x7340;
u8 valid[1000];

#seekto 0x77E0;
struct {
ul16 vfo_scan_start_A;
ul16 vfo_scan_end_A;
ul16 vfo_scan_start_B;
ul16 vfo_scan_end_B;
} vfo_scan;

"""

_MEM_FORMAT_Q10H_oem_read_nolims = """

#seekto 0x0340;
struct {
char oem1[8];
#seekto 0x036c; //0x002c;
char name[8];
#seekto 0x0392; //0x0052;
char firmware[6];
#seekto 0x0378; //0x0038;
char date[10];
#seekto 0x000a;
u8 locked;
} oem_info;

#seekto 0x7740;
struct {
struct {
ul16 scan_st;
ul16 scan_end;
} addrs[10];
struct {
char name[12];
} names[10];
} scn_grps;

#seekto 0x78e0;
struct {
u8 cid[6];
} call_ids[100];

#seekto 0x7B40;
struct {
char call_name[12];
} call_names[100];


#seekto 0x0440;
struct {
u8 channel_menu;
u8 power_save;
u8 roger_beep;
u8 timeout;
u8 toalarm;
u8 wxalert;
u8 wxalert_type;
u8 vox;
u8 unk_xp8;
u8 voice;
u8 beep;
u8 scan_rev;
u8 backlight;
u8 DspBrtAct;
u8 DspBrtSby;
u8 ponmsg;
u8 ptt_id; //0x530
u8 ptt_delay;
u8 dtmf_st;
u8 dtmf_tx_time;
u8 dtmf_interval;
u8 ring_time;
u8 alert;
u8 autolock;
ul16 pri_ch;
u8 prich_sw;
u8 rpttype;
u8 rpt_spk;
u8 rpt_ptt;
u8 rpt_tone;
u8 rpt_hold;
u8 scan_det;
u8 smuteset; //0x540
u8 batt_ind;
u8 ToneScnSave;
#seekto 0x0464;
u8 theme;
u8 unkx545;
u8 disp_time;
u8 time_zone;
u8 GPS_send_freq;
u8 GPS;
u8 GPS_rcv;
ul16 custcol1_text;
ul16 custcol1_bg;
ul16 custcol1_icon;
ul16 custcol1_line;
ul16 custcol2_text;
ul16 custcol2_bg;
ul16 custcol2_icon;
ul16 custcol2_line;
ul16 custcol3_text;
ul16 custcol3_bg;
ul16 custcol3_icon;
ul16 custcol3_line;
ul16 custcol4_text;
ul16 custcol4_bg;
ul16 custcol4_icon;
ul16 custcol4_line;
// #seekto 0x048b;
char mode_sw_pwd[6];
char reset_pwd[6];
u8 work_mode_a;
u8 work_mode_b;
ul16 work_ch_a;
ul16 work_ch_b;
u8 vfostepA;
u8 vfostepB;
u8 squelchA;
u8 squelchB;
u8 BCL_A;
u8 BCL_B;
u8 vfobandA;
u8 vfobandB;
#seekto 0x04a7;
u8 top_short;
u8 top_long;
u8 ptt1;
u8 ptt2;
u8 pf1_short;
u8 pf1_long;
u8 pf2_short;
u8 pf2_long;
u8 ScnGrpA_Act;
u8 ScnGrpB_Act;
u8 vfo_scanmodea;
u8 vfo_scanmodeb; //x592
u8 ani_id[6];
u8 scc[6];
#seekto 0x04c1;
u8 act_area;
u8 tdr;
u8 keylock;
#seekto 0x04c7;
u8 stopwatch; //0x04c7
u8 x0x04c8;
char dispstr[12];
#seekto 0x04dD;
char areamsg[12];
u8 xunk_1;
u8 xunk_2;
u8 xunk_ani_sw;
u8 xani_code[6];
u8 xpf1_shrt;
u8 xpf1_long;
u8 xpf2_shrt;
u8 xpf2_long;
u8 main_band;
u8 xTDR_single_mode;
u8 xunk1;
u8 xunk2;
u8 cur_call_grp;
u8 VFO_repeater_a;
u8 VFO_repeater_b;
u8 sim_rec;
} settings;

#seekto 0x78B0;
struct {
ul16 FM_radio;
} fm[20];

#seekto 0x0540;
struct {
ul32 rxfreq;
ul32 offset;
ul16 rxtone;
ul16 txtone;
u8 scrambler:4,
am_mode:2,
power:2;
u8 ofst_dir:3,
unknown:1,
compander:1,
mute_mode:2,
iswide:1;
u8 call_group;
u8 unknown6;
} vfoa[6];

#seekto 0x05a0;
struct {
ul32 rxfreq;
ul32 offset;
ul16 rxtone;
ul16 txtone;
u8 scrambler:4,
am_mode:2,
power:2;
u8 ofst_dir:3,
unknown:1,
compander:1,
mute_mode:2,
iswide:1;
u8 call_group;
u8 unknown6;
} vfob[2];

#seekto 0x05E0;
struct {
ul32 rxfreq;
ul32 txfreq;
ul16 rxtone;
ul16 txtone;
u8 scrambler:4,
am_mode:2,
power:2;
u8 unknown3:1,
send_loc:1,
scan_add:1,
favorite:1,
compander:1,
mute_mode:2,
iswide:1;
u8 call_group;
u8 unknown6;
} memory[1000];

#seekto 0x4460;
struct {
u8 name[12];
} names[1000];

#seekto 0x7340;
u8 valid[1000];

#seekto 0x77E0;
struct {
ul16 vfo_scan_start_A;
ul16 vfo_scan_end_A;
ul16 vfo_scan_start_B;
ul16 vfo_scan_end_B;
} vfo_scan;

"""

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


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

namestr = ""
for i in range(0, len(name)):
b = ord(name[i].get_value())
if b != 0 and b != 0xff:
namestr += chr(b)
return namestr


def str2name(val, size=6, fillchar='\0', emptyfill='\0'):
""" Convert a string to a name. A name is a 6 element bytearray
with ascii chars.
"""
val = str(val).rstrip(' \t\r\n\0\xff')
if len(val) == 0:
name = "".ljust(size, emptyfill)
else:
name = val.ljust(size, fillchar)
return name


def str2callid(val):
""" Convert caller id strings from callid2str.
"""
ascii2bin = "0123456789"
s = str(val).strip()
LOG.debug("val = %s" % val)
LOG.debug("s = %s" % s)
if len(s) < 3 or len(s) > 6:
raise InvalidValueError(
"Caller ID must be at least 3 and no more than 6 digits")
if s[0] == '0':
raise InvalidValueError(
"First digit of a Caller ID cannot be a zero '0'")
blk = bytearray()
for c in s:
if c not in ascii2bin:
raise InvalidValueError(
"Caller ID must be all digits 0x%x" % c)
b = ascii2bin.index(c)
blk.append(b)
if len(blk) < 6:
blk.append(0x0F) # EOL a short ID
if len(blk) < 6:
for i in range(0, (6 - len(blk))):
blk.append(0xf0)
LOG.debug("blk = %s" % blk)
return blk


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

bin2ascii = "0123456789"
digitsstr = ""
for i in range(0, 6):
b = digits[i].get_value()
if b == 0x0F: # the digits EOL
break
if b >= 0xa:
raise InvalidValueError(
"Value has illegal byte 0x%x" % ord(b))
digitsstr += bin2ascii[b]
digitsstr = digitsstr.ljust(width, padding)
return digitsstr


def str2digits(val):
""" Callback for edited strings from digits2str.
"""
ascii2bin = " 0123456789"
s = str(val).strip()
if len(s) < 3 or len(s) > 6:
raise InvalidValueError(
"Value must be at least 3 and no more than 6 digits")
blk = bytearray()
for c in s:
if c not in ascii2bin:
raise InvalidValueError("Value must be all digits 0x%x" % c)
blk.append(int(c))
for i in range(len(blk), 6):
blk.append(0x0f) # EOL a short ID
return blk


def apply_scc(setting, obj):
c = str2digits(setting.value)
obj.scc = c


@directory.register
class KGQ10HRadio(chirp_common.CloneModeRadio,
chirp_common.ExperimentalRadio):

"""Wouxun KG-Q10H"""
VENDOR = "Wouxun"
MODEL = "KG-Q10H"
NEEDS_COMPAT_SERIAL = False
_model = b"KG-Q10H"
BAUD_RATE = 115200
POWER_LEVELS = [chirp_common.PowerLevel("L", watts=0.5),
chirp_common.PowerLevel("M", watts=4.5),
chirp_common.PowerLevel("H", watts=5.5),
chirp_common.PowerLevel("U", watts=6.0)]
_record_start = 0x7C
_RADIO_ID = ""
cryptbyte = 0x54
am_mode_list = AM_MODE
am_mode_list_ch = AM_MODE_CH
themelist = THEME_LIST
vfoa_grp_label = "VFO A Settings"
vfob_grp_label = "VFO B Settings"
workmodelist = WORKMODE_LIST
# pfkeyshort = PFKEYSHORT_LIST
# pfkeylong = PFKEYLONG_LIST
dispmesg = "Top Message"
areamsglabel = "Area Message"
vfo_area = "VFO "
# ani_msg = "ANI-ID Switch (ANI-SW)"
pttdly_msg = "PTT-DLY - menu 34"
idtx_msg = "PTT-ID - menu 33"
vfoa3_msg = "66M Settings"
_prog_key = PROG_KEY_LIST
_vfoaband = VFOABAND_MAP
_offset_dir_rpt = OFFSET_LIST
_offset_dir_rpt_label = "A Shift Dir"
_offset_dir_rpt_labelB = "B Shift Dir"
rpttonemenu = 43
timemenu = 44
tzmenu = 45
locmenu = 47

Beta_release = True

if Beta_release:
use_color = False
show_limits = False
else:
use_color = True
show_limits = True

def check_for_beta1_file(self):
check1 = self.get_mmap()[0x0000:0x0005]
check2 = self.get_mmap()[0x0340:0x0346]
if ((check1 == b'\xdd\xdd\xdd\xdd\xdd') &
(check2 == b'\x57\x4F\x55\x58\x55\x4E')):
beta1 = False
else:
beta1 = True
return beta1

def process_mmap(self):
if self.show_limits:
self._memobj = bitwise.parse(_MEM_FORMAT_Q10H_oem_read2,
self._mmap)
else:
self._memobj = bitwise.parse(_MEM_FORMAT_Q10H_oem_read_nolims,
self._mmap)

def _checksum(self, data):
cs = 0
for byte in data:
cs += byte
return cs % 256

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

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

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

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

return image_out

def sync_in(self):
try:
self._mmap_addrorder = self._download()
self._mmap = memmap.MemoryMapBytes(self._rearrange_image
(self._mmap_addrorder))
# self._mmap = self._download()
except errors.RadioError:
raise
except Exception as e:
raise errors.RadioError("Failed to communicate with radio: %s" % e)
self.process_mmap()

def sync_out(self):
self._upload()

def _upload(self):
# Beta 1.x files had a different memory map arrangement
# Use of Beta 1.x files with Beta 2.x and beyond driver
# will send settings
# to incorrect locations on the radio casuing issues-
# Detect and Prevent!!
# Check for specific data (static) at specific locations
# to confirm Beta2 vs Beta1 memory layout.
beta1 = self.check_for_beta1_file()
if beta1:
LOG.debug("beta1 file detected = %s" % beta1)
raise errors.RadioError("Beta 1 img detected!!!\n"
"Upload Canceled!\n"
"Select a Beta 2.x img or\n"
"Download from radio to get a Beta2 img\n"
"Then Retry the Upload")
try:
self._identify()
self._do_upload()
except errors.RadioError:
raise
except Exception as e:
raise errors.RadioError("Failed to communicate with radio: %s" % e)
return

def _do_upload(self):
if self._RADIO_ID == self._model:
LOG.debug("Starting Upload")
if self.show_limits:
cfgmap = Q10H_upload_map
else:
cfgmap = Q10H_upload_map_nolims

for (radioaddress, radioend, start, memend,
blocksize, count) in cfgmap:
end = start + (blocksize * count)
LOG.debug("start = " + str(start))
LOG.debug("end = " + str(end))
LOG.debug("blksize = " + str(blocksize))
ptr2 = radioaddress

for addr in range(start, end, blocksize):
ptr = addr
LOG.debug("ptr = " + str(hex(ptr)))
LOG.debug("ptr2 = " + str(hex(ptr2)))
req = struct.pack('>H', ptr2)
chunk = self.get_mmap()[ptr:ptr + blocksize]
self._write_record(CMD_WR, req + chunk)
LOG.debug(util.hexprint(req + chunk))
cserr, ack = self._read_record()
LOG.debug(util.hexprint(ack))
j = struct.unpack('>H', ack)[0]
if cserr or j != ptr2:
LOG.debug(util.hexprint(ack))
raise Exception("Checksum Error on Ack at %i" % ptr)
ptr += blocksize
ptr2 += blocksize
if self.status_fn:
status = chirp_common.Status()
status.cur = ptr
status.max = 0x8000
status.msg = "Cloning to radio"
self.status_fn(status)
# fix for errant upload to radio address 0x100 in beta 2.0 driver
# this writes the correct data back to the radio
# consider removing for production
# if self._RADIO_ID == b"KG-Q10H":
# fix = struct.pack('>H64B', 0x0100, 0x00, 0x00, 0x00, 0x00,
# 0x00, 0x00,
# 0x00, 0x00, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
# 0xDD, 0xDD, 0xDD,
# 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
# 0xDD, 0x28, 0x32,
# 0x3D, 0x49, 0x57, 0x00, 0x00, 0x00, 0x00,
# 0x00, 0x00, 0x00,
# 0x00, 0x00, 0x00, 0x00, 0xDD, 0xDD, 0xDD,
# 0xDD, 0xDD, 0xDD,
# 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
# 0xDD, 0xDD, 0xDD,
# 0x40, 0x7A, 0x41, 0x04, 0x13, 0x17, 0x20,
# 0x31)
# self._write_record(CMD_WR, fix)
# time.sleep(0.02)
LOG.debug("Upload Completed")
else:
raise errors.RadioError("Radio is not a KG-Q10H. Upload Canceled")

self._finish()

def get_features(self):
rf = chirp_common.RadioFeatures()
rf.has_settings = True
rf.has_ctone = True
rf.has_rx_dtcs = True
rf.has_cross = True
rf.has_tuning_step = False
rf.has_bank = False
rf.can_odd_split = True
rf.valid_skips = ["", "S"]
rf.valid_tmodes = ["", "Tone", "TSQL", "DTCS", "Cross"]
rf.valid_cross_modes = [
"Tone->Tone",
"Tone->DTCS",
"DTCS->Tone",
"DTCS->",
"->Tone",
"->DTCS",
"DTCS->DTCS",
]
rf.valid_modes = ["FM", "NFM", "AM"]
rf.valid_power_levels = self.POWER_LEVELS
rf.valid_name_length = 12
rf.valid_duplexes = ["", "-", "+", "split", "off"]
rf.valid_bands = [(50000000, 54997500), # 6m
(108000000, 174997500), # AM Airband and VHF
(222000000, 225997500), # 1.25M
(320000000, 479997500), # UHF
(714000000, 999997500)] # Fixed Land Mobile

rf.valid_characters = chirp_common.CHARSET_ASCII
rf.memory_bounds = (1, 999) # 999 memories
rf.valid_tuning_steps = STEPS2
return rf

@classmethod
def get_prompts(cls):
rp = chirp_common.RadioPrompts()
rp.experimental = \
('THIS DRIVER IS BETA 2.x - ''\n'
'DO NOT USE SAVED IMG FILES FROM''\n'
'BETA 1.x DRIVER WITH BETA 2.x TO UPLOAD TO RADIO''\n'
'DOWNLOAD FROM RADIO WITH BETA 2.x FIRST THEN MODIFY'
' AND UPLOAD''\n'
'This driver is experimental. USE AT YOUR OWN RISK\n'
'\n'
'Please save a copy of the image from your radio with Chirp '
'before modifying any values.\n'
'\n'
'Please keep a copy of your memories with the original Wouxon'
'CPS software if you treasure them, this driver is new and '
'may contain bugs.\n'
)
# rp.pre_download = _(
# "Please ensure you have selected the correct radio driver\n")
rp.pre_upload = (
"WARNING: THIS DRIVER IS BETA 2.x\n"
"\n"
"UPLOADS REQUIRE the use of Beta 2.x Radio img files. \n"
"DO NOT USE Radio Image files from Beta 1.x"
" to upload to radio. \n"
"It will cause incorrect settings on the radio.\n"
"\n"
"Please DOWNLOAD FROM RADIO with this driver"
" to get a Beta 2.x img file\n"
"for use BEFORE UPLOADING anything with this driver.\n"
"CANCEL the Upload if you are using a Beta 1.x img \n"
"Continue if you are using a Beta 2.x img file. \n"
"\n"
"If you don't know the img version...\n"
"The driver will try a check to confirm.\n"
"If it fails the check - Do a DOWNLOAD FROM RADIO then try again.")
return rp

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

def _get_tone(self, _mem, mem):
# MRT - Chirp Uses N for n DCS Tones and R for i DCS Tones
def _get_dcs(val):
code = int("%03o" % (val & 0x07FF))
pol = (val & 0x2000) and "R" or "N"
return code, pol
tpol = False
if _mem.txtone != 0xFFFF and (_mem.txtone & 0x4000) == 0x4000:
tcode, tpol = _get_dcs(_mem.txtone)
mem.dtcs = tcode
txmode = "DTCS"
elif _mem.txtone != 0xFFFF and _mem.txtone != 0x0:
mem.rtone = (_mem.txtone & 0x7fff) / 10.0
txmode = "Tone"
else:
txmode = ""
rpol = False
if _mem.rxtone != 0xFFFF and (_mem.rxtone & 0x4000) == 0x4000:
rcode, rpol = _get_dcs(_mem.rxtone)
mem.rx_dtcs = rcode
rxmode = "DTCS"
elif _mem.rxtone != 0xFFFF and _mem.rxtone != 0x0:
mem.ctone = (_mem.rxtone & 0x7fff) / 10.0
rxmode = "Tone"
else:
rxmode = ""

if txmode == "Tone" and not rxmode:
mem.tmode = "Tone"
elif txmode == rxmode and txmode == "Tone" and mem.rtone == mem.ctone:
mem.tmode = "TSQL"
elif txmode == rxmode and txmode == "DTCS" and mem.dtcs == mem.rx_dtcs:
mem.tmode = "DTCS"
elif rxmode or txmode:
mem.tmode = "Cross"
mem.cross_mode = "%s->%s" % (txmode, rxmode)

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

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

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

mem = chirp_common.Memory()
mem.number = number
_valid = self._memobj.valid[mem.number]
LOG.debug("Channel %d Valid = %s", number, _valid == MEM_VALID)
if _valid != MEM_VALID:
mem.empty = True
return mem
else:
mem.empty = False

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

if (_mem.txfreq == 0xFFFFFFFF or _mem.txfreq == 0x00000000):
# TX freq not set
mem.duplex = "off"
mem.offset = 0
elif int(_mem.rxfreq) == int(_mem.txfreq):
mem.duplex = ""
mem.offset = 0
elif abs(int(_mem.rxfreq) * 10 - int(_mem.txfreq) * 10) > 70000000:
mem.duplex = "split"
mem.offset = int(_mem.txfreq) * 10
else:
mem.duplex = int(_mem.rxfreq) > int(_mem.txfreq) and "-" or "+"
mem.offset = abs(int(_mem.rxfreq) - int(_mem.txfreq)) * 10

for char in _nam.name:
if char != 0:
mem.name += chr(char)
else:
# 0x00 in name indicates the end of the name.
# stop looking at next chars as Wouxun does not
# always clear the remaining bytes
break
mem.name = mem.name.rstrip()

mem.extra = RadioSettingGroup("Extra", "Extra")
rs = RadioSetting("mute_mode", "Mute Mode",
RadioSettingValueList(
SPMUTE_LIST, SPMUTE_LIST[_mem.mute_mode]))
mem.extra.append(rs)
rs = RadioSetting("scrambler", "Scramble Descramble",
RadioSettingValueList(
SCRAMBLE_LIST, SCRAMBLE_LIST[_mem.scrambler]))
mem.extra.append(rs)
rs = RadioSetting("compander", "Compander",
RadioSettingValueList(
ONOFF_LIST, ONOFF_LIST[_mem.compander]))
mem.extra.append(rs)
# if _mem.am_mode != 0:
rs = RadioSetting("am_mode", "AM Mode",
RadioSettingValueMap(
self.am_mode_list_ch, _mem.am_mode))
mem.extra.append(rs)
rs = RadioSetting("favorite", "Favorite",
RadioSettingValueList(
ONOFF_LIST, ONOFF_LIST[_mem.favorite]))
mem.extra.append(rs)
rs = RadioSetting("send_loc", "Send Location",
RadioSettingValueList(
ONOFF_LIST, ONOFF_LIST[_mem.send_loc]))
mem.extra.append(rs)

if _mem.call_group == 0:
_mem.call_group = 1
rs = RadioSetting("call_group", "Call Group",
RadioSettingValueMap(
MAP_1_99, _mem.call_group))
mem.extra.append(rs)

self._get_tone(_mem, mem)

mem.skip = "" if bool(_mem.scan_add) else "S"
_mem.power = _mem.power & 0x3
if _mem.power > 3:
_mem.power = 3
mem.power = self.POWER_LEVELS[_mem.power]
if _mem.am_mode != 0:
mem.mode = "AM"
elif _mem.iswide:
mem.mode = "FM"
else:
mem.mode = "NFM"
return mem

def _scan_grp(self):
"""Scan groups
"""
_settings = self._memobj.settings

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

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

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

sgrp = self._memobj.scn_grps
scan = RadioSettingGroup("scn_grps", "Channel Scan Groups")
rs = RadioSetting("ScnGrpA_Act", "Scan Group A Active",
RadioSettingValueList(SCANGRP_LIST,
SCANGRP_LIST[_settings.
ScnGrpA_Act]))
scan.append(rs)
rs = RadioSetting("ScnGrpB_Act", "Scan Group B Active",
RadioSettingValueList(SCANGRP_LIST,
SCANGRP_LIST[_settings.
ScnGrpB_Act]))
scan.append(rs)
for i in range(0, 10):
s_grp = sgrp.addrs[i]
s_name = sgrp.names[i]
rs_name = RadioSettingValueString(0, 12,
name2str(s_name.name))
rs = RadioSetting("scn_grps.names[%i].name" % i,
"Group %i Name" % (i + 1), rs_name)
rs.set_apply_callback(apply_name, s_name)
scan.append(rs)
rs_st = RadioSettingValueInteger(1, 999, s_grp.scan_st)
rs = RadioSetting("scn_grps.addrs[%i].scan_st" % i,
" Group %i Start Channel" % (i + 1), rs_st)
rs.set_apply_callback(apply_start, s_grp)
scan.append(rs)
rs_end = RadioSettingValueInteger(1, 999, s_grp.scan_end)
rs = RadioSetting("scn_grps.addrs[%i].scan_end" % i,
" Group %i End Channel" % (i + 1), rs_end)
rs.set_apply_callback(apply_end, s_grp)
scan.append(rs)
return scan

def _set_tone(self, mem, _mem):
def _set_dcs(code, pol):
val = int("%i" % code, 8) | 0x4000
if pol == "R":
val += 0x2000
return val

rx_mode = tx_mode = None
rxtone = txtone = 0x0000

if mem.tmode == "Tone":
tx_mode = "Tone"
rx_mode = None
txtone = int(mem.rtone * 10) + 0x8000
elif mem.tmode == "TSQL":
rx_mode = tx_mode = "Tone"
rxtone = txtone = int(mem.ctone * 10) + 0x8000
elif mem.tmode == "DTCS":
tx_mode = rx_mode = "DTCS"
txtone = _set_dcs(mem.dtcs, mem.dtcs_polarity[0])
rxtone = _set_dcs(mem.dtcs, mem.dtcs_polarity[1])
elif mem.tmode == "Cross":
tx_mode, rx_mode = mem.cross_mode.split("->")
if tx_mode == "DTCS":
txtone = _set_dcs(mem.dtcs, mem.dtcs_polarity[0])
elif tx_mode == "Tone":
txtone = int(mem.rtone * 10) + 0x8000
if rx_mode == "DTCS":
rxtone = _set_dcs(mem.rx_dtcs, mem.dtcs_polarity[1])
elif rx_mode == "Tone":
rxtone = int(mem.ctone * 10) + 0x8000

_mem.rxtone = rxtone
_mem.txtone = txtone

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

def set_memory(self, mem):
number = mem.number

_mem = self._memobj.memory[number]
_nam = self._memobj.names[number]

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

_mem.rxfreq = int(mem.freq / 10)
if mem.duplex == "off":
# _mem.txfreq = 0xFFFFFFFF
_mem.txfreq = 0x00000000
elif mem.duplex == "split":
_mem.txfreq = int(mem.offset / 10)
elif mem.duplex == "off":
for i in range(0, 4):
_mem.txfreq[i].set_raw("\xFF")
elif mem.duplex == "+":
_mem.txfreq = int(mem.freq / 10) + int(mem.offset / 10)
elif mem.duplex == "-":
_mem.txfreq = int(mem.freq / 10) - int(mem.offset / 10)
else:
_mem.txfreq = int(mem.freq / 10)
_mem.scan_add = int(mem.skip != "S")
if ((mem.mode == "FM") or (mem.mode == "NFM")):
_mem.iswide = int((mem.mode == "FM"))
_mem.am_mode = 0
elif mem.mode == "AM":
_mem.am_mode = 1
# Q10H radio only supports wide AM mode
_mem.iswide = 1
# set the tone
self._set_tone(mem, _mem)

# set the power
_mem.power = _mem.power & 0x3
if mem.power:
if _mem.power > 3:
_mem.power = 3
_mem.power = self.POWER_LEVELS.index(mem.power)
else:
_mem.power = True

for setting in mem.extra:
if setting.get_name() != "am_mode":
setattr(_mem, setting.get_name(), setting.value)
else:
if mem.mode != "AM":
setattr(_mem, setting.get_name(), 0)
elif int(setting.value) == 2:
setattr(_mem, setting.get_name(), 2)
elif int(setting.value) == 1:
setattr(_mem, setting.get_name(), 1)

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

def _get_settings(self):
if self.use_color:
from chirp.settings import RadioSettingValueRGB

_settings = self._memobj.settings
_vfoa = self._memobj.vfoa
_vfob = self._memobj.vfob
_vfo_scan = self._memobj.vfo_scan
# _callname = self._memobj.call_names
_fm = self._memobj.fm
scan_grp = self._scan_grp()
_oem = self._memobj.oem_info
firmware_rev = str(_oem.firmware)
# release of Q10H Firmware VC1.02 includes 20K Step
LOG.debug("Firmware revision %s detected" % firmware_rev)
if firmware_rev not in (NO_20K_STEP_FIRMWARE):
steps = STEP2_LIST
LOG.debug("20K Step Included")
else:
steps = STEP_LIST
LOG.debug("20K Step NOT Included")

cfg_grp = RadioSettingGroup("cfg_grp", "Config Settings")
if self.use_color:
cfg_grp[0] = RadioSettingGroup("color_grp", "Custom Theme Colors")
else:
cfg_grp[0] = RadioSettingGroup("color_grp",
"Custom Theme Colors (RGB565)")
cfg_grp[0][1] = RadioSettingGroup("color_grp",
"Integer value of RGB565 Color")
cfg_grp[0][2] = RadioSettingGroup("color_grp",
"Search- RGB565 Color Picker")
vfoa_grp = RadioSettingGroup("vfoa_grp", self.vfoa_grp_label)
vfoa_grp[0] = RadioSettingGroup("vfoa150_grp", "150M Settings")
vfoa_grp[1] = RadioSettingGroup("vfoa400_grp", "400M Settings")
vfoa_grp[2] = RadioSettingGroup("vfoa200_grp", "200M Settings")
vfoa_grp[3] = RadioSettingGroup("vfoa3_grp", self.vfoa3_msg)
vfoa_grp[4] = RadioSettingGroup("vfoa800_grp", "800M Settings")
vfoa_grp[5] = RadioSettingGroup("vfoa300_grp", "300M Settings")
vfob_grp = RadioSettingGroup("vfob_grp", self.vfob_grp_label)
vfob_grp[0] = RadioSettingGroup("vfob150_grp", "150M Settings")
vfob_grp[1] = RadioSettingGroup("vfob400_grp", "400M Settings")
key_grp = RadioSettingGroup("key_grp", "Key Settings")
fmradio_grp = RadioSettingGroup("fmradio_grp", "FM Broadcast Memory")
lmt_grp = RadioSettingGroup("lmt_grp", "Frequency Limits")
lmt_grp[0] = RadioSettingGroup("lmt_grp", "TX Limits")
lmt_grp[1] = RadioSettingGroup("lmt_grp", "RX Limits")
oem_grp = RadioSettingGroup("oem_grp", "OEM Info")
scanv_grp = RadioSettingGroup("scnv_grp", "VFO Scan Mode")
call_grp = RadioSettingGroup("call_grp", "Call Group Settings")

if self.show_limits:
group = RadioSettings(cfg_grp, vfoa_grp, vfob_grp,
fmradio_grp, key_grp, scan_grp, scanv_grp,
call_grp, lmt_grp, oem_grp)
else:
group = RadioSettings(cfg_grp, vfoa_grp, vfob_grp,
fmradio_grp, key_grp, scan_grp, scanv_grp,
call_grp, oem_grp)

# # Call Settings

def apply_callid(setting, obj):
c = str2callid(setting.value)
obj.cid = c

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

callid = self._memobj.call_ids[i]
c_id = RadioSettingValueString(0, 6,
self.callid2str(callid.cid),
False)
rs = RadioSetting("call_ids[%i].cid" % i,
" Call Code %s" % str(i), c_id)
rs.set_apply_callback(apply_callid, callid)
call_grp.append(rs)

# Configuration Settings
#
rs = RadioSetting("channel_menu", "Menu available in channel mode",
RadioSettingValueBoolean(_settings.channel_menu))
cfg_grp.append(rs)
rs = RadioSetting("power_save", "Battery Saver - menu 4",
RadioSettingValueBoolean(_settings.power_save))
cfg_grp.append(rs)
rs = RadioSetting("wxalert", "Weather Alert - menu 5",
RadioSettingValueBoolean(_settings.wxalert))
cfg_grp.append(rs)
rs = RadioSetting("wxalert_type",
"Weather Alert Notification - menu 6",
RadioSettingValueList(WX_TYPE,
WX_TYPE[_settings.
wxalert_type]))
cfg_grp.append(rs)
rs = RadioSetting("roger_beep", "Roger Beep - menu 13",
RadioSettingValueList(ROGER_LIST,
ROGER_LIST[_settings.
roger_beep]))
cfg_grp.append(rs)
rs = RadioSetting("timeout", "Timeout Timer (TOT) - menu 14",
RadioSettingValueList(
TIMEOUT_LIST, TIMEOUT_LIST[_settings.timeout]))
cfg_grp.append(rs)
rs = RadioSetting("toalarm", "Timeout Pre-Alert (TOA) - menu 15",
RadioSettingValueList(LIST_10S,
LIST_10S[_settings.toalarm]))
cfg_grp.append(rs)
rs = RadioSetting("vox", "VOX - menu 16",
RadioSettingValueList(LIST_10,
LIST_10[_settings.vox]))
cfg_grp.append(rs)
rs = RadioSetting("voice", "Voice Guide - menu 17",
RadioSettingValueBoolean(_settings.voice))
cfg_grp.append(rs)
rs = RadioSetting("beep", "Keypad Beep - menu 18",
RadioSettingValueBoolean(_settings.beep))
cfg_grp.append(rs)
rs = RadioSetting("scan_rev", "Scan Mode - menu 8",
RadioSettingValueList(SCANMODE_LIST,
SCANMODE_LIST[_settings.
scan_rev]))
cfg_grp.append(rs)
rs = RadioSetting("backlight", "Backlight Active Time - menu 3",
RadioSettingValueList(BACKLIGHT_LIST,
BACKLIGHT_LIST[_settings.
backlight]))
cfg_grp.append(rs)

rs = RadioSetting("DspBrtAct", "Display Brightness ACTIVE - menu 1",
RadioSettingValueMap(DSPBRTACT_MAP,
_settings.DspBrtAct))
cfg_grp.append(rs)
rs = RadioSetting("DspBrtSby", "Display Brightness STANDBY - menu 2",
RadioSettingValueList(
DSPBRTSBY_LIST, DSPBRTSBY_LIST[
_settings.DspBrtSby]))
cfg_grp.append(rs)

rs = RadioSetting("theme", "Theme - menu 7",
RadioSettingValueList(
self.themelist,
self.themelist[_settings.theme]))
cfg_grp.append(rs)
rs = RadioSetting("ponmsg", "Startup Display - menu 27",
RadioSettingValueList(
PONMSG_LIST, PONMSG_LIST[_settings.ponmsg]))
cfg_grp.append(rs)
rs = RadioSetting("batt_ind", "Battery Indicator - menu 39",
RadioSettingValueList(
BATT_DISP_LIST,
BATT_DISP_LIST[_settings.batt_ind]))
cfg_grp.append(rs)
rs = RadioSetting("ptt_id", self.idtx_msg,
RadioSettingValueList(PTTID_LIST,
PTTID_LIST[_settings.ptt_id]))
cfg_grp.append(rs)
rs = RadioSetting("ptt_delay", self.pttdly_msg,
RadioSettingValueMap(PTTDELAY_TIMES,
_settings.ptt_delay))
cfg_grp.append(rs)

rs = RadioSetting("dtmf_st", "DTMF Sidetone - menu 31",
RadioSettingValueList(DTMFST_LIST,
DTMFST_LIST[_settings.
dtmf_st]))
cfg_grp.append(rs)
rs = RadioSetting("dtmf_tx_time", "DTMF Transmit Time",
RadioSettingValueMap(DTMF_TIMES,
_settings.dtmf_tx_time))
cfg_grp.append(rs)
rs = RadioSetting("dtmf_interval", "DTMF Interval Time",
RadioSettingValueMap(DTMF_TIMES,
_settings.dtmf_interval))
cfg_grp.append(rs)
rs = RadioSetting("ring_time", "Ring Time - menu 35",
RadioSettingValueList(LIST_10S,
LIST_10S[_settings.ring_time]))
cfg_grp.append(rs)
rs = RadioSetting("alert", "Alert Tone - menu 36",
RadioSettingValueList(ALERTS_LIST,
ALERTS_LIST[_settings.alert]))
cfg_grp.append(rs)

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

rs = RadioSetting("prich_sw", "Priority Channel Scan - menu 11",
RadioSettingValueList(PRICHAN_LIST,
PRICHAN_LIST[
_settings.prich_sw]))
cfg_grp.append(rs)
rs = RadioSetting("pri_ch",
"Priority Channel - Can not be empty Channel",
RadioSettingValueInteger(1, 999, _settings.pri_ch))
cfg_grp.append(rs)

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

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

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

rs = RadioSetting("rpt_tone",
"Repeater Tone - menu %i" % self.rpttonemenu,
RadioSettingValueBoolean(_settings.rpt_tone))
cfg_grp.append(rs)
rs = RadioSetting("rpt_hold", "RPT Hold Time",
RadioSettingValueList(
HOLD_TIMES, HOLD_TIMES[_settings.rpt_hold]))
cfg_grp.append(rs)
rs = RadioSetting("scan_det", "Scan Mode Tone Detect - menu 9",
RadioSettingValueBoolean(_settings.scan_det))
cfg_grp.append(rs)
rs = RadioSetting("ToneScnSave", "Tone Scan Save - menu 12",
RadioSettingValueList(TONESCANSAVELIST,
TONESCANSAVELIST[_settings.
ToneScnSave]))
cfg_grp.append(rs)
rs = RadioSetting("smuteset", "Sub-Freq Mute (SMUTESET) - menu 38",
RadioSettingValueList(SMUTESET_LIST,
SMUTESET_LIST[_settings.
smuteset]))
cfg_grp.append(rs)
# rs = RadioSetting("ani_sw", ani_msg,
# RadioSettingValueBoolean(_settings.ani_sw))
# cfg_grp.append(rs)

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

rs = RadioSetting("disp_time",
"Display Time - menu %i" % self.timemenu,
RadioSettingValueBoolean(_settings.disp_time))
cfg_grp.append(rs)
rs = RadioSetting("time_zone", "Time Zone - menu %i" % self.tzmenu,
RadioSettingValueList(
TIME_ZONE,
TIME_ZONE[_settings.time_zone]))
cfg_grp.append(rs)
rs = RadioSetting("GPS", "GPS - menu %i.1" % self.locmenu,
RadioSettingValueBoolean(_settings.GPS))
cfg_grp.append(rs)
rs = RadioSetting("GPS_send_freq",
"GPS Send Frequency - menu %i.2" % self.locmenu,
RadioSettingValueList(
GPS_SEND_FREQ,
GPS_SEND_FREQ[_settings.GPS_send_freq]))
cfg_grp.append(rs)
rs = RadioSetting("GPS_rcv", "GPS Receive - menu %i.3" % self.locmenu,
RadioSettingValueBoolean(_settings.GPS_rcv))
cfg_grp.append(rs)

rs = RadioSetting("stopwatch", "Timer / Stopwatch Enabled - menu 37",
RadioSettingValueBoolean(_settings.stopwatch))
cfg_grp.append(rs)
rs = RadioSetting("keylock", "Keypad Locked",
RadioSettingValueBoolean(_settings.keylock))
cfg_grp.append(rs)

rs = RadioSetting("act_area", "Active Area",
RadioSettingValueList(
ACTIVE_AREA_LIST,
ACTIVE_AREA_LIST[_settings.act_area]))
cfg_grp.append(rs)
rs = RadioSetting("tdr", "TDR",
RadioSettingValueList(
TDR_LIST,
TDR_LIST[_settings.tdr]))
cfg_grp.append(rs)

pswdchars = "0123456789"
_msg = str(_settings.mode_sw_pwd).split("\0")[0]
val = RadioSettingValueString(0, 6, _msg, False)
val.set_mutable(True)
val.set_charset(pswdchars)
rs = RadioSetting("mode_sw_pwd", "Mode SW Pwd", val)
cfg_grp.append(rs)

_msg = str(_settings.reset_pwd).split("\0")[0]
val = RadioSettingValueString(0, 6, _msg, False)
val.set_charset(pswdchars)
val.set_mutable(True)
rs = RadioSetting("reset_pwd", "Reset Pwd", val)
cfg_grp.append(rs)
# Custom Color Settings
if self.use_color:
val = RadioSettingValueRGB.from_rgb16(_settings.custcol1_text)
rs = RadioSetting("settings.custcol1_text", "Custom 1 - Text",
val)
cfg_grp[0].append(rs)
val = RadioSettingValueRGB.from_rgb16(_settings.custcol1_bg)
rs = RadioSetting("settings.custcol1_bg", "Custom 1 - Background",
val)
cfg_grp[0].append(rs)
val = RadioSettingValueRGB.from_rgb16(_settings.custcol1_icon)
rs = RadioSetting("settings.custcol1_icon", "Custom 1 - Icon",
val)
cfg_grp[0].append(rs)
val = RadioSettingValueRGB.from_rgb16(_settings.custcol1_line)
rs = RadioSetting("settings.custcol1_line", "Custom 1 - Line",
val)
cfg_grp[0].append(rs)

val = RadioSettingValueRGB.from_rgb16(_settings.custcol2_text)
rs = RadioSetting("settings.custcol2_text", " Custom 2 - Text",
val)
cfg_grp[0].append(rs)
val = RadioSettingValueRGB.from_rgb16(_settings.custcol2_bg)
rs = RadioSetting("settings.custcol2_bg",
" Custom 2 - Background",
val)
cfg_grp[0].append(rs)
val = RadioSettingValueRGB.from_rgb16(_settings.custcol2_icon)
rs = RadioSetting("settings.custcol2_icon", " Custom 2 - Icon",
val)
cfg_grp[0].append(rs)
val = RadioSettingValueRGB.from_rgb16(_settings.custcol2_line)
rs = RadioSetting("settings.custcol2_line", " Custom 2 - Line",
val)
cfg_grp[0].append(rs)
val = RadioSettingValueRGB.from_rgb16(_settings.custcol3_text)
rs = RadioSetting("settings.custcol3_text", "Custom 3 - Text",
val)
cfg_grp[0].append(rs)
val = RadioSettingValueRGB.from_rgb16(_settings.custcol3_bg)
rs = RadioSetting("settings.custcol3_bg", "Custom 3 - Background",
val)
cfg_grp[0].append(rs)
val = RadioSettingValueRGB.from_rgb16(_settings.custcol3_icon)
rs = RadioSetting("settings.custcol3_icon", "Custom 3 - Icon",
val)
cfg_grp[0].append(rs)
val = RadioSettingValueRGB.from_rgb16(_settings.custcol3_line)
rs = RadioSetting("settings.custcol3_line", "Custom 3 - Line",
val)
cfg_grp[0].append(rs)
val = RadioSettingValueRGB.from_rgb16(_settings.custcol4_text)
rs = RadioSetting("settings.custcol4_text",
" Custom 4 - Text",
val)
cfg_grp[0].append(rs)
val = RadioSettingValueRGB.from_rgb16(_settings.custcol4_bg)
rs = RadioSetting("settings.custcol4_bg",
" Custom 4 - Background",
val)
cfg_grp[0].append(rs)
val = RadioSettingValueRGB.from_rgb16(_settings.custcol4_icon)
rs = RadioSetting("settings.custcol4_icon",
" Custom 4 - Icon",
val)
cfg_grp[0].append(rs)
val = RadioSettingValueRGB.from_rgb16(_settings.custcol4_line)
rs = RadioSetting("settings.custcol4_line",
" Custom 4 - Line",
val)
cfg_grp[0].append(rs)
else:
rs = RadioSetting("settings.custcol1_text", "Custom 1 - Text",
RadioSettingValueInteger(
0, 65535, _settings.custcol1_text))
cfg_grp[0].append(rs)
rs = RadioSetting("settings.custcol1_bg", "Custom 1 - Background",
RadioSettingValueInteger(
0, 65535, _settings.custcol1_bg))
cfg_grp[0].append(rs)
rs = RadioSetting("settings.custcol1_icon", "Custom 1 - Icon",
RadioSettingValueInteger(
0, 65535, _settings.custcol1_icon))
cfg_grp[0].append(rs)
rs = RadioSetting("settings.custcol1_line", "Custom 1 - Line",
RadioSettingValueInteger(
0, 65535, _settings.custcol1_line))
cfg_grp[0].append(rs)
rs = RadioSetting("settings.custcol2_text", "Custom 2 - Text",
RadioSettingValueInteger(
0, 65535, _settings.custcol2_text))
cfg_grp[0].append(rs)
rs = RadioSetting("settings.custcol2_bg", "Custom 2 - Background",
RadioSettingValueInteger(
0, 65535, _settings.custcol1_bg))
cfg_grp[0].append(rs)
rs = RadioSetting("settings.custcol2_icon", "Custom 2 - Icon",
RadioSettingValueInteger(
0, 65535, _settings.custcol1_icon))
cfg_grp[0].append(rs)
rs = RadioSetting("settings.custcol2_line", "Custom 2 - Line",
RadioSettingValueInteger(
0, 65535, _settings.custcol2_line))
cfg_grp[0].append(rs)
rs = RadioSetting("settings.custcol3_text", "Custom 3 - Text",
RadioSettingValueInteger(
0, 65535, _settings.custcol3_text))
cfg_grp[0].append(rs)
rs = RadioSetting("settings.custcol3_bg", "Custom 3 - Background",
RadioSettingValueInteger(
0, 65535, _settings.custcol3_bg))
cfg_grp[0].append(rs)
rs = RadioSetting("settings.custcol3_icon", "Custom 3 - Icon",
RadioSettingValueInteger(
0, 65535, _settings.custcol3_icon))
cfg_grp[0].append(rs)
rs = RadioSetting("settings.custcol3_line", "Custom 3 - Line",
RadioSettingValueInteger(
0, 65535, _settings.custcol3_line))
cfg_grp[0].append(rs)
rs = RadioSetting("settings.custcol4_text", "Custom 4 - Text",
RadioSettingValueInteger(
0, 65535, _settings.custcol4_text))
cfg_grp[0].append(rs)
rs = RadioSetting("settings.custcol4_bg", "Custom 4 - Background",
RadioSettingValueInteger(
0, 65535, _settings.custcol4_bg))
cfg_grp[0].append(rs)
rs = RadioSetting("settings.custcol4_icon", "Custom 4 - Icon",
RadioSettingValueInteger(
0, 65535, _settings.custcol4_icon))
cfg_grp[0].append(rs)
rs = RadioSetting("settings.custcol4_line", "Custom 4 - Line",
RadioSettingValueInteger(
0, 65535, _settings.custcol4_line))
cfg_grp[0].append(rs)


# # Key Settings
# #
_msg = str(_settings.dispstr).split("\0")[0]
val = RadioSettingValueString(0, 12, _msg)
val.set_mutable(True)
rs = RadioSetting("dispstr",
self.dispmesg, val)
key_grp.append(rs)

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

_str = _decode(self._memobj.settings.areamsg)
val = RadioSettingValueString(0, 12, _str)
val.set_mutable(True)
rs = RadioSetting("settings.areamsg", self.areamsglabel, val)
key_grp.append(rs)

def apply_ani_id(setting, obj):
c = str2callid(setting.value)
obj.ani_id = c

cid = self._memobj.settings
my_callid = RadioSettingValueString(3, 6,
self.callid2str(cid.ani_id),
False)
rs = RadioSetting("ani_id", "Radio ID", my_callid)
rs.set_apply_callback(apply_ani_id, cid)
key_grp.append(rs)

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

rs = RadioSetting("ptt1", "PTT1 Key function",
RadioSettingValueList(
PTT_LIST,
PTT_LIST[_settings.ptt1]))
key_grp.append(rs)
rs = RadioSetting("ptt2", "PTT2 Key function",
RadioSettingValueList(
PTT_LIST,
PTT_LIST[_settings.ptt2]))
key_grp.append(rs)
rs = RadioSetting("top_short", "TOP SHORT Key function",
RadioSettingValueList(
self._prog_key,
self._prog_key[_settings.top_short]))
key_grp.append(rs)
rs = RadioSetting("top_long", "TOP LONG Key function",
RadioSettingValueList(
self._prog_key,
self._prog_key[_settings.top_long]))
key_grp.append(rs)

rs = RadioSetting("pf1_short", "PF1 SHORT Key function",
RadioSettingValueList(
self._prog_key,
self._prog_key[_settings.pf1_short]))
key_grp.append(rs)
rs = RadioSetting("pf1_long", "PF1 LONG Key function",
RadioSettingValueList(
self._prog_key,
self._prog_key[_settings.pf1_long]))
key_grp.append(rs)
rs = RadioSetting("pf2_short", "PF2 SHORT Key function",
RadioSettingValueList(
self._prog_key,
self._prog_key[_settings.pf2_short]))
key_grp.append(rs)
rs = RadioSetting("pf2_long", "PF2 LONG Key function",
RadioSettingValueList(
self._prog_key,
self._prog_key[_settings.pf2_long]))
key_grp.append(rs)

# # SCAN GROUP settings
rs = RadioSetting("settings.vfo_scanmodea", "VFO A Scan Mode",
RadioSettingValueList(
VFO_SCANMODE_LIST,
VFO_SCANMODE_LIST[_settings.vfo_scanmodea]))
scanv_grp.append(rs)
rs = RadioSetting("vfo_scan.vfo_scan_start_A",
" VFO A Scan Start (MHz)",
RadioSettingValueInteger(
1, 999, _vfo_scan.vfo_scan_start_A))
scanv_grp.append(rs)
rs = RadioSetting("vfo_scan.vfo_scan_end_A",
" VFO A Scan End (MHz)",
RadioSettingValueInteger(
1, 999, _vfo_scan.vfo_scan_end_A))
scanv_grp.append(rs)
rs = RadioSetting("settings.vfo_scanmodeb", "VFO B Scan Mode",
RadioSettingValueList(
VFO_SCANMODE_LIST,
VFO_SCANMODE_LIST[_settings.vfo_scanmodeb]))
scanv_grp.append(rs)
rs = RadioSetting("vfo_scan.vfo_scan_start_B",
" VFO B Scan Start (MHz)",
RadioSettingValueInteger(
1, 999, _vfo_scan.vfo_scan_start_B))
scanv_grp.append(rs)
rs = RadioSetting("vfo_scan.vfo_scan_end_B",
" VFO B Scan End (MHz)",
RadioSettingValueInteger(
1, 999, _vfo_scan.vfo_scan_end_B))
scanv_grp.append(rs)

# VFO A Settings
#
wml = self.workmodelist
rs = RadioSetting("work_mode_a", self.vfo_area + "A Workmode",
RadioSettingValueList(wml,
wml[_settings.work_mode_a]))
vfoa_grp.append(rs)
rs = RadioSetting("work_ch_a", self.vfo_area + "A Work Channel",
RadioSettingValueInteger(1, 999,
_settings.work_ch_a))
vfoa_grp.append(rs)
for i in range(0, 6):
rs = RadioSetting("vfoa[%i].rxfreq" % i,
self.vfo_area + "A Rx Frequency (MHz)",
RadioSettingValueFloat(
0.00000, 999.999999,
(_vfoa[i].rxfreq / 100000.0),
0.000001, 6))
vfoa_grp[i].append(rs)
if self.MODEL == "KG-Q10H":
rs = RadioSetting("vfoa[%i].offset" % i,
self.vfo_area + "A Offset (MHz)",
RadioSettingValueFloat(
0.00000, 599.999999,
(_vfoa[i].offset / 100000.0),
0.000001, 6))
vfoa_grp[i].append(rs)

rs = RadioSetting("vfoa[%i].rxtone" % i,
self.vfo_area + "A Rx tone",
RadioSettingValueMap(
TONE_MAP, _vfoa[i].rxtone))
vfoa_grp[i].append(rs)
rs = RadioSetting("vfoa[%i].txtone" % i,
self.vfo_area + "A Tx tone",
RadioSettingValueMap(
TONE_MAP, _vfoa[i].txtone))
vfoa_grp[i].append(rs)

# # MRT - AND power with 0x03 to display only the lower 2 bits for
# # power level and to clear the upper bits
# # MRT - any bits set in the upper 2 bits will cause radio to show
# # invalid values for power level and a display glitch
# # MRT - when PTT is pushed
_vfoa[i].power = _vfoa[i].power & 0x3
if _vfoa[i].power > 3:
_vfoa[i].power = 3
rs = RadioSetting("vfoa[%i].power" % i, self.vfo_area + "A Power",
RadioSettingValueList(
POWER_LIST, POWER_LIST[_vfoa[i].power]))
vfoa_grp[i].append(rs)
rs = RadioSetting("vfoa[%i].iswide" % i,
self.vfo_area + "A Wide/Narrow",
RadioSettingValueList(
BANDWIDTH_LIST,
BANDWIDTH_LIST[_vfoa[i].iswide]))
vfoa_grp[i].append(rs)
rs = RadioSetting("vfoa[%i].mute_mode" % i,
self.vfo_area + "A Mute (SP Mute)",
RadioSettingValueList(
SPMUTE_LIST,
SPMUTE_LIST[_vfoa[i].mute_mode]))
vfoa_grp[i].append(rs)
rs = RadioSetting("vfoa[%i].ofst_dir" % i,
self.vfo_area + self._offset_dir_rpt_label,
RadioSettingValueList(
self._offset_dir_rpt,
self._offset_dir_rpt[_vfoa[i].ofst_dir]))
vfoa_grp[i].append(rs)
rs = RadioSetting("vfoa[%i].scrambler" % i,
self.vfo_area + "A Scramble/Descramble",
RadioSettingValueList(
SCRAMBLE_LIST,
SCRAMBLE_LIST[_vfoa[i].scrambler]))
vfoa_grp[i].append(rs)

rs = RadioSetting("vfoa[%i].compander" % i,
self.vfo_area + "A Compander",
RadioSettingValueList(
ONOFF_LIST, ONOFF_LIST[_vfoa[i].compander]))
vfoa_grp[i].append(rs)
rs = RadioSetting("vfoa[%i].call_group" % i,
self.vfo_area + "A Call Group",
RadioSettingValueInteger(
1, 99, _vfoa[i].call_group))
vfoa_grp[i].append(rs)
rs = RadioSetting("vfoa[%i].am_mode" % i,
self.vfo_area + "A AM Mode",
RadioSettingValueList(
self.am_mode_list,
self.am_mode_list[_vfoa[i].am_mode]))
vfoa_grp[i].append(rs)

rs = RadioSetting("settings.vfostepA", self.vfo_area + "A Step (kHz)",
RadioSettingValueList(
steps, steps[_settings.vfostepA]))
vfoa_grp.append(rs)
rs = RadioSetting("settings.squelchA", self.vfo_area + "A Squelch",
RadioSettingValueList(
LIST_10, LIST_10[_settings.squelchA]))
vfoa_grp.append(rs)
rs = RadioSetting("BCL_A", "Busy Channel Lock-out A",
RadioSettingValueBoolean(_settings.BCL_A))
vfoa_grp.append(rs)
rs = RadioSetting("settings.vfobandA", "VFO A Current Band",
RadioSettingValueMap(self._vfoaband,
_settings.vfobandA))
vfoa_grp.append(rs)

# # VFO B Settings
wml = self.workmodelist
rs = RadioSetting("work_mode_b", self.vfo_area + "B Workmode",
RadioSettingValueList(wml,
wml[_settings.work_mode_b]))
vfob_grp.append(rs)
rs = RadioSetting("work_ch_b", self.vfo_area + "B Work Channel",
RadioSettingValueInteger(1, 999,
_settings.work_ch_b))
vfob_grp.append(rs)
for i in range(0, 2):
rs = RadioSetting("vfob[%i].rxfreq" % i,
self.vfo_area + "B Rx Frequency (MHz)",
RadioSettingValueFloat(
0.00000, 999.999999,
(_vfob[i].rxfreq / 100000.0),
0.000001, 6))
vfob_grp[i].append(rs)
if self.MODEL == "KG-Q10H":
rs = RadioSetting("vfob[%i].offset" % i,
self.vfo_area + "B Offset (MHz)",
RadioSettingValueFloat(
0.00000, 599.999999,
(_vfob[i].offset / 100000.0),
0.000001, 6))
vfob_grp[i].append(rs)

rs = RadioSetting("vfob[%i].rxtone" % i,
self.vfo_area + "B Rx tone",
RadioSettingValueMap(
TONE_MAP, _vfob[i].rxtone))
vfob_grp[i].append(rs)
rs = RadioSetting("vfob[%i].txtone" % i,
self.vfo_area + "B Tx tone",
RadioSettingValueMap(
TONE_MAP, _vfob[i].txtone))
vfob_grp[i].append(rs)

# # MRT - AND power with 0x03 to display only the lower 2 bits for
# # power level and to clear the upper bits
# # MRT - any bits set in the upper 2 bits will cause radio to show
# # invalid values for power level and a display glitch
# # MRT - when PTT is pushed
_vfob[i].power = _vfob[i].power & 0x3
if _vfob[i].power > 3:
_vfob[i].power = 3
rs = RadioSetting("vfob[%i].power" % i,
self.vfo_area + "B Power",
RadioSettingValueList(
POWER_LIST, POWER_LIST[_vfob[i].power]))
vfob_grp[i].append(rs)
rs = RadioSetting("vfob[%i].iswide" % i,
self.vfo_area + "B Wide/Narrow",
RadioSettingValueList(
BANDWIDTH_LIST,
BANDWIDTH_LIST[_vfob[i].iswide]))
vfob_grp[i].append(rs)
rs = RadioSetting("vfob[%i].mute_mode" % i,
self.vfo_area + "B Mute (SP Mute)",
RadioSettingValueList(
SPMUTE_LIST,
SPMUTE_LIST[_vfob[i].mute_mode]))
vfob_grp[i].append(rs)
rs = RadioSetting("vfob[%i].ofst_dir" % i,
self.vfo_area + self._offset_dir_rpt_labelB,
RadioSettingValueList(
self._offset_dir_rpt,
self._offset_dir_rpt[_vfob[i].ofst_dir]))
vfob_grp[i].append(rs)
rs = RadioSetting("vfob[%i].scrambler" % i,
self.vfo_area + "B Scramble/Descramble",
RadioSettingValueList(
SCRAMBLE_LIST,
SCRAMBLE_LIST[_vfob[i].scrambler]))
vfob_grp[i].append(rs)

rs = RadioSetting("vfob[%i].compander" % i,
self.vfo_area + "B Compander",
RadioSettingValueList(
ONOFF_LIST, ONOFF_LIST[_vfob[i].compander]))
vfob_grp[i].append(rs)
rs = RadioSetting("vfob[%i].call_group" % i,
self.vfo_area + "B Call Group",
RadioSettingValueInteger(
1, 99, _vfob[i].call_group))
vfob_grp[i].append(rs)

rs = RadioSetting("settings.vfostepB", self.vfo_area + "B Step (kHz)",
RadioSettingValueList(
steps, steps[_settings.vfostepB]))
vfob_grp.append(rs)
rs = RadioSetting("settings.squelchB", self.vfo_area + "B Squelch",
RadioSettingValueList(
LIST_10, LIST_10[_settings.squelchB]))
vfob_grp.append(rs)
rs = RadioSetting("BCL_B", "Busy Channel Lock-out B",
RadioSettingValueBoolean(_settings.BCL_B))
vfob_grp.append(rs)
rs = RadioSetting("settings.vfobandB", "VFO B Current Band",
RadioSettingValueMap(VFOBBAND_MAP,
_settings.vfobandB))
vfob_grp.append(rs)

# FM RADIO PRESETS

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

if self.show_limits:
lim = self._memobj.limits
rs = RadioSetting("limits.m2tx_start",
"2M TX Lower Limit (MHz)",
RadioSettingValueFloat(
118.000000, 299.999999,
(lim.m2tx_start / 100000.0),
0.000001, 6))

lmt_grp[0].append(rs)
rs = RadioSetting("limits.m2tx_stop",
"2M TX Upper Limit (MHz)",
RadioSettingValueFloat(
118.000000, 299.999999,
(lim.m2tx_stop / 100000.0),
0.000001, 6))
lmt_grp[0].append(rs)
rs = RadioSetting("limits.tworx_start",
"2M TX SUPER Lower Limit (MHz)",
RadioSettingValueFloat(
108.000000, 299.999999,
(lim.tworx_start / 100000.0),
0.000001, 6))
lmt_grp[0].append(rs)
rs = RadioSetting("limits.tworx_stop",
"2M TX SUPER Upper Limit (MHz)",
RadioSettingValueFloat(
108.000000, 299.999999,
(lim.tworx_stop / 100000.0),
0.000001, 6))
lmt_grp[0].append(rs)

rs = RadioSetting("limits.cm70_tx_start",
"70cm TX Lower Limit (MHz)",
RadioSettingValueFloat(
300.000000, 999.999999,
(lim.cm70_tx_start / 100000.0),
0.000001, 6))
lmt_grp[0].append(rs)
rs = RadioSetting("limits.cm70_tx_stop",
"70cm TX Upper Limit (MHz)",
RadioSettingValueFloat(
300.000000, 999.999999,
(lim.cm70_tx_stop / 100000.0),
0.000001, 6))
lmt_grp[0].append(rs)
rs = RadioSetting("limits.m125_tx_start",
"1.25M TX Lower Limit (MHz)",
RadioSettingValueFloat(
200.000000, 299.999999,
(lim.m125_tx_start / 100000.0),
0.000001, 6))
lmt_grp[0].append(rs)
rs = RadioSetting("limits.m125_tx_stop",
"1.25M TX Upper Limit (MHz)",
RadioSettingValueFloat(
200.000000, 299.999999,
(lim.m125_tx_stop / 100000.0),
0.000001, 6))
lmt_grp[0].append(rs)
rs = RadioSetting("limits.m6_tx_start",
"6M TX Lower Limit (MHz)",
RadioSettingValueFloat(
26.000000, 99.999999,
(lim.m6_tx_start / 100000.0),
0.000001, 6))
lmt_grp[0].append(rs)
rs = RadioSetting("limits.m6_tx_stop",
"6M TX Upper Limit (MHz)",
RadioSettingValueFloat(
26.000000, 99.999999,
(lim.m6_tx_stop / 100000.0),
0.000001, 6))
lmt_grp[0].append(rs)
rs = RadioSetting("limits.rx1lim_start",
"2M Area A RX Lower Limit (MHz) - Verified",
RadioSettingValueFloat(
108.000000, 299.999999,
(lim.rx1lim_start / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx1lim_stop",
"2M Area A RX Upper Limit (MHz) - Verified",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx1lim_stop / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx7lim_start",
"2M Area B RX Lower Limit (MHz) - Verified",
RadioSettingValueFloat(
136.000000, 999.999999,
(lim.rx7lim_start / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx7lim_stop",
"2M Area B RX Upper Limit (MHz) - Verified",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx7lim_stop / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx12lim_start",
"2m Area A SUPER Rx Lower Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx12lim_start / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx12lim_stop",
"2m Area A SUPER Rx Upper Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx12lim_stop / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx18lim_start",
"2m Area B SUPER Rx Lower Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx18lim_start / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx18lim_stop",
"2m Area B SUPER Rx Upper Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx18lim_stop / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx13lim_start",
"70cm Area A SUPER Rx Lower Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx13lim_start / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx13lim_stop",
"70cm Area A SUPER Rx Upper Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx13lim_stop / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx2lim_start",
"70cm Area A RX Lower Limit (MHz) - Verified",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx2lim_start / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx2lim_stop",
"70cm Area A RX Upper Limit (MHz) - Verified",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx2lim_stop / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx8lim_start",
"70cm Area B RX Lower Limit (MHz) - Verified",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx8lim_start / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx8lim_stop",
"70cm Area B RX Upper Limit (MHz) - Verified",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx8lim_stop / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx19lim_start",
"70cm Area B SUPER RX Lower Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx19lim_start / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx19lim_stop",
"70cm Area B SUPER RX Upper Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx19lim_stop / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx3lim_start",
"1.25m RX Lower Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx3lim_start / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx3lim_stop",
"1.25m RX Upper Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx3lim_stop / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx4lim_start",
"6M RX Lower Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx4lim_start / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx4lim_stop",
"6M RX Upper Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx4lim_stop / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx5lim_start",
"800MHz Rz Lower Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx5lim_start / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx5lim_stop",
"800MHz Rz Upper Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx5lim_stop / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx6lim_start",
"rx6_start Lower Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx6lim_start / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx6lim_stop",
"rx6_stop Upper Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx6lim_stop / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx10lim_start",
"70cm Area B TX Lower Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx10lim_start / 100000.0),
0.000001, 6))
lmt_grp[0].append(rs)
rs = RadioSetting("limits.rx10lim_stop",
"70cm Area B TX Upper Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx10lim_stop / 100000.0),
0.000001, 6))
lmt_grp[0].append(rs)
rs = RadioSetting("limits.rx14lim_start",
"rx14lim_start Lower Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx14lim_start / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx14lim_stop",
"rx14lim_stop Upper Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx14lim_stop / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx15lim_start",
"rx15lim_start Lower Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx15lim_start / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx15lim_stop",
"rx15lim_stop Upper Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx15lim_stop / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx16lim_start",
"rx16lim_start Lower Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx16lim_start / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx16lim_stop",
"rx16lim_stop Upper Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx16lim_stop / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx17lim_start",
"rx17lim_start Lower Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx17lim_start / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.rx17lim_stop",
"rx17lim_stop Upper Limit (MHz)",
RadioSettingValueFloat(
0.000000, 999.999999,
(lim.rx17lim_stop / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
for i in range(0, 14):
s = self._memobj.limits.more_limits[i]
rs = RadioSetting("limits.more_limits[%i].lim_start" % i,
"More %i Lower Limit (MHz)" % i,
RadioSettingValueFloat(
0.000000, 999.999999,
(s.lim_start / 100000.0),
0.000001, 6))
lmt_grp.append(rs)
rs = RadioSetting("limits.more_limits[%i].lim_stop" % i,
"More %i Upper Limit (MHz)" % i,
RadioSettingValueFloat(
0.000000, 999.999999,
(s.lim_stop / 100000.0),
0.000001, 6))
lmt_grp.append(rs)

# # OEM info

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

def do_nothing(setting, obj):
return

_str = _decode(self._memobj.oem_info.oem1)
val = RadioSettingValueString(0, 15, _str)
val.set_mutable(False)
rs = RadioSetting("oem_info.oem1", "OEM String 1", val)
rs.set_apply_callback(do_nothing, _settings)
oem_grp.append(rs)
# if self.MODEL == "KG-Q10H" :
_str = _decode(self._memobj.oem_info.name)
val = RadioSettingValueString(0, 15, _str)
val.set_mutable(False)
rs = RadioSetting("oem_info.name", "Radio Model", val)
rs.set_apply_callback(do_nothing, _settings)
oem_grp.append(rs)

_str = _decode(self._memobj.oem_info.firmware)
val = RadioSettingValueString(0, 15, _str)
val.set_mutable(False)
rs = RadioSetting("oem_info.firmware", "Firmware Version", val)
rs.set_apply_callback(do_nothing, _settings)
oem_grp.append(rs)

_str = _decode(self._memobj.oem_info.date)
val = RadioSettingValueString(0, 15, _str)
val.set_mutable(False)
rs = RadioSetting("oem_info.date", "OEM Date", val)
rs.set_apply_callback(do_nothing, _settings)
oem_grp.append(rs)
if self.MODEL == "KG-Q10H":
rs = RadioSetting("oem_info.locked", "OEM Lock Mode -"
" Tx/Rx Range Locked to factory settings",
RadioSettingValueBoolean(
self._memobj.oem_info.locked))
oem_grp.append(rs)

return group

def get_settings(self):
try:
return self._get_settings()
except Exception:
import traceback
LOG.error("Failed to parse settings: %s", traceback.format_exc())
return None

def set_settings(self, settings):
for element in settings:
if not isinstance(element, RadioSetting):
self.set_settings(element)
continue
else:
try:
if "." in element.get_name():
bits = element.get_name().split(".")
obj = self._memobj
for bit in bits[:-1]:
if "[" in bit and "]" in bit:
bit, index = bit.split("[", 1)
index, junk = index.split("]", 1)
index = int(index)
obj = getattr(obj, bit)[index]
else:
obj = getattr(obj, bit)
setting = bits[-1]
else:
obj = self._memobj.settings
setting = element.get_name()

if element.has_apply_callback():
element.run_apply_callback()
else:
LOG.debug("Setting %s = %s" % (setting, element.value))
if self._is_freq(element):
# MRT rescale freq values to match radio
# expected values
setattr(obj, setting,
int(element.values()[0]._current *
100000.0))
elif self._is_fmradio(element):
# MRT rescale FM Radio values to match radio
# expected values
setattr(obj, setting,
int(element.values()[0]._current * 10.0))
elif self._is_color(element):
setattr(obj, setting,
RadioSettingValueRGB.get_rgb16(
element.value))
else:
setattr(obj, setting, element.value)
except Exception:
LOG.debug(element.get_name())
raise

def _is_freq(self, element):
return ("rxfreq" in element.get_name() or
"offset" in element.get_name() or
"rx_start" in element.get_name() or
"rx_stop" in element.get_name() or
"lim_start" in element.get_name() or
"lim_stop" in element.get_name() or
"tx_start" in element.get_name() or
"tx_stop" in element.get_name())

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

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

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

bin2ascii = "0123456789"
cidstr = ""
for i in range(0, 6):
b = cid[i].get_value()
# Handle fluky firmware 0x0a is sometimes used instead of 0x00
if b == 0x0a:
b = 0x00
if b == 0xc or b == 0xf: # the cid EOL
break
if b > 0xa:
raise InvalidValueError(
"Caller ID code has illegal byte 0x%x" % b)
cidstr += bin2ascii[b]
return cidstr

def _checksum2(self, data):
cs = 0
cs_adj = 0
for byte in data:
cs += byte
cs %= 256
cs_adj = (data[3] & 0x0F) % 4
if cs_adj == 0:
cs += 3
elif cs_adj == 1:
cs += 1
elif cs_adj == 2:
cs -= 1
elif cs_adj == 3:
cs -= 3
return (cs & 0xFF)

def _checksum_adjust(self, data):
cs_mod = 0
cs_adj = 0
cs_adj = (data & 0x0F) % 4
if cs_adj == 0:
cs_mod = 3
elif cs_adj == 1:
cs_mod = 1
elif cs_adj == 2:
cs_mod = -1
elif cs_adj == 3:
cs_mod = -3
return (cs_mod)

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

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

for i in range(0, 3):
ident = struct.pack(
'BBBBBBBB', 0x7c, 0x82, 0xff, 0x03, 0x54, 0x14, 0x54, 0x53)
self.pipe.write(ident)
_chksum_err, _resp = self._read_record()
_radio_id = _resp[46:53]
self._RADIO_ID = _radio_id
LOG.debug("Radio Identified as Model %s" % _radio_id)
if _chksum_err:
LOG.debug(util.hexprint(_resp))
raise errors.RadioError("Checksum Error on Identify")
elif _radio_id != self._model:
self._finish()
raise errors.RadioError("Radio identified as Model: %s \n"
"You selected Model: %s.\n"
"Please select the correct radio model"
" to continue"
# "Your Model is not currently supported"
% (_radio_id.decode('UTF-8'),
self._model.decode('UTF-8')))
LOG.debug("Ending Radio Identifcation")

def _download(self):
try:
self._identify()
return self._do_download()
except errors.RadioError:
raise
except Exception as e:
LOG.exception('Unknown error during download process')
raise errors.RadioError("Failed to communicate with radio: %s" % e)

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

for start, blocksize, count in cfgmap:
end = start + (blocksize * count)
LOG.debug("start = " + str(start))
LOG.debug("end = " + str(end))
LOG.debug("blksize = " + str(blocksize))

for i in range(start, end, blocksize):
time.sleep(0.005)
req = struct.pack('>HB', i, blocksize)
self._write_record(CMD_RD, req)
cs_error, resp = self._read_record()
if cs_error:
LOG.debug(util.hexprint(resp))
raise Exception("Checksum error on read")
LOG.debug("Got:\n%s" % util.hexprint(resp))
image += resp[2:]
if self.status_fn:
status = chirp_common.Status()
status.cur = i
status.max = 0x8000
status.msg = "Cloning from radio"
self.status_fn(status)
self._finish()
LOG.debug("Download Completed")
return memmap.MemoryMapBytes(image)

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

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

_rcs_xor = _packet[-1]
_packet = self.decrypt(_packet)
LOG.debug("Header =%a" % util.hexprint(_header + _packet[0:2]))
_cs = self._checksum(_header[1:])
_cs += self._checksum(_packet)
_csa = self._checksum_adjust(_packet[0])
LOG.debug("_cs (preadjusted)=%x", _cs & 0xff)
_cs += _csa
_cs = _cs & 0xFF
_rcs = self.strxor(self.pipe.read(1)[0], _rcs_xor)[0]
LOG.debug("_csa=%x", _csa)
LOG.debug("_cs (adjusted)=%x", _cs)
LOG.debug("_rcs=%x", _rcs)
return (_rcs != _cs, _packet)

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

def decrypt(self, data):
result = b''
for i in range(len(data)-1, 0, -1):
result += self.strxor(data[i], data[i - 1])
result += self.strxor(data[0], self.cryptbyte)
return result[::-1]

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


@directory.register
class KGQ10GRadio(KGQ10HRadio):

"""Wouxun KG-Q10G"""
VENDOR = "Wouxun"
MODEL = "KG-Q10G"
NEEDS_COMPAT_SERIAL = False
_model = b"KG-Q10G"
cryptbyte = 0x54
am_mode_list = AM_MODE_2
am_mode_list_ch = AM_MODE_CH2
vfoa3_msg = "26M Settings"
_prog_key = PROG_KEY_LIST2
_vfoaband = VFOABAND_MAP2
_offset_dir_rpt = ONOFF_LIST
_offset_dir_rpt_label = "A Repeater"
_offset_dir_rpt_labelB = "B Repeater"
rpttonemenu = 40
timemenu = 41
tzmenu = 42
locmenu = 44

def get_features(self):
rf = chirp_common.RadioFeatures()
rf.has_settings = True
rf.has_ctone = True
rf.has_rx_dtcs = True
rf.has_cross = True
rf.has_tuning_step = False
rf.has_bank = False
rf.can_odd_split = True
rf.valid_skips = ["", "S"]
rf.valid_tmodes = ["", "Tone", "TSQL", "DTCS", "Cross"]
rf.valid_cross_modes = [
"Tone->Tone",
"Tone->DTCS",
"DTCS->Tone",
"DTCS->",
"->Tone",
"->DTCS",
"DTCS->DTCS",
]
rf.valid_modes = ["FM", "NFM", "AM"]
rf.valid_power_levels = self.POWER_LEVELS
rf.valid_name_length = 12
rf.valid_duplexes = ["", "-", "+", "split", "off"]
# MRT - Open up channel memory freq range to support
# RxFreq limit expansion
rf.valid_bands = [(26000000, 31997500), # CB
(108000000, 174997500), # AM Airband and VHF
(222000000, 225997500), # 1.25M
(320000000, 479997500), # UHF
(714000000, 999997500)] # Fixed Land Mobile

rf.valid_characters = chirp_common.CHARSET_ASCII
rf.memory_bounds = (1, 999) # 999 memories
rf.valid_tuning_steps = STEPS2
return rf

def _do_upload(self):
# self._identify()
if self._RADIO_ID == self._model:
LOG.debug("Starting Upload")
if self.show_limits:
cfgmap = Q10H_upload_map
else:
cfgmap = Q10G_upload_map_nolims

for (radioaddress, radioend, start, memend,
blocksize, count) in cfgmap:
end = start + (blocksize * count)
LOG.debug("start = " + str(start))
LOG.debug("end = " + str(end))
LOG.debug("blksize = " + str(blocksize))
ptr2 = radioaddress

for addr in range(start, end, blocksize):
ptr = addr
LOG.debug("ptr = " + str(hex(ptr)))
LOG.debug("ptr2 = " + str(hex(ptr2)))
req = struct.pack('>H', ptr2)
chunk = self.get_mmap()[ptr:ptr + blocksize]
self._write_record(CMD_WR, req + chunk)
LOG.debug(util.hexprint(req + chunk))
cserr, ack = self._read_record()
LOG.debug(util.hexprint(ack))
j = struct.unpack('>H', ack)[0]
if cserr or j != ptr2:
LOG.debug(util.hexprint(ack))
raise Exception("Checksum Error on Ack at %i" % ptr)
ptr += blocksize
ptr2 += blocksize
if self.status_fn:
status = chirp_common.Status()
status.cur = ptr
status.max = 0x8000
status.msg = "Cloning to radio"
self.status_fn(status)
LOG.debug("Upload Completed")
else:
raise errors.RadioError("Radio is not a KG-Q10G. Upload Canceled")

self._finish()
(13-13/16)