# Wouxun KG-Q10H Driver # melvin.terechenok@gmail.com # # Based on the work of 2019 Pavel Milanes CO7WT # and Krystian Struzik # 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 . """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()