# Copyright 2016 Jim Unroe # # 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 2 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 . import time import os import struct import re import logging from chirp import chirp_common, directory, memmap from chirp import bitwise, errors, util from chirp.settings import RadioSetting, RadioSettingGroup, \ RadioSettingValueInteger, RadioSettingValueList, \ RadioSettingValueBoolean, RadioSettingValueString, \ RadioSettings LOG = logging.getLogger(__name__) MEM_FORMAT = """ struct memory { lbcd rxfreq[4]; lbcd txfreq[4]; lbcd rxtone[2]; lbcd txtone[2]; u8 unknown1; u8 pttid:2, // PTT-ID unknown2:1, signaling:1, // Signaling(ANI) unknown3:1, bcl:1, // Busy Channel Lockout unknown4:2; u8 unknown5:3, highpower:1, // Power Level isnarrow:1, // Bandwidth scan:1, // Scan Add unknown6:2; u8 unknown7; }; #seekto 0x0010; struct memory channels[128]; #seekto 0x0810; struct memory vfo_a; struct memory vfo_b; #seekto 0x0830; struct { u8 unknown_0830_1:4, // 0x0830 color:2, // Background Color dst:1, // DTMF Side Tone txsel:1; // Priority TX Channel Select u8 scans:2, // Scan Mode - 0x0831 unknown_0831:1, autolk:1, // Auto Key Lock save:1, // Battery Save beep:1, // Key Beep voice:2; // Voice Prompt u8 vfomr_fm:1, // FM Radio Display Mode - 0x0832 led:2, // Background Light unknown_0832_2:1, dw:1, // FM Radio Dual Watch name:1, // Display Names vfomr_a:2; // Display Mode A u8 opnset:2, // Power On Message - 0x0833 unknown_0833_1:3, dwait:1, // Dual Standby vfomr_b:2; // Display Mode B u8 mrcha; // mr a ch num - 0x0834 u8 mrchb; // mr b ch num - 0x0835 u8 fmch; // fm radio ch num - 0x0836 u8 unknown_0837_1:1, // 0x0837 ste:1, // Squelch Tail Eliminate roger:1, // Roger Beep unknown_0837_2:1, vox:4; // VOX u8 step:4, // Step - 0x0838 unknown_0838_1:4; u8 squelch; // Squelch - 0x0839 u8 tot; // Time Out Timer - 0x083A u8 rptmod:1, // Repeater Mode - 0x083B volmod:2, // Volume Mode rptptt:1, // Repeater PTT Switch rptspk:1, // Repeater Speaker relay:3; // Cross Band Repeater Enable u8 unknown_083C:4, // 0x083C rptrl:4; // Repeater TX Delay u8 pf1:4, // Function Key 1 - 0x083D pf2:4; // Function Key 2 u8 vot; // VOX Delay Time - 0x083E } settings; #seekto 0x0848; struct { char line1[7]; } poweron_msg; struct limit { bbcd lower[2]; bbcd upper[2]; }; #seekto 0x0850; struct { struct limit vhf; struct limit uhf; } limits; struct fmmemory { lbcd fmfreq[4]; }; #seekto 0x085E; struct fmmemory fmchannels[25]; struct fmmemory fmvfo; #seekto 0x08D0; struct { char name[7]; // Channel Names u8 unknown2[1]; } names[128]; #seekto 0x0D20; u8 usedflags[16]; u8 scanflags[16]; #seekto 0x0E50; struct memory rpt_vfo; struct memory rpt_1; struct memory rpt_2; struct memory rpt_3; struct memory rpt_4; struct memory rpt_5; #seekto 0x0EB0; struct { u8 unknown:2, rpt_5_enable:1, rpt_4_enable:1, rpt_3_enable:1, rpt_2_enable:1, rpt_1_enable:1, rpt_vfo_enable:1; } special_enables; #seekto 0x0FA0; struct { u8 unknown_0FA0_1:4, dispab:1, // select a/b unknown_0FA0_2:3; } settings2; """ CMD_ACK = "\x06" BLOCK_SIZE = 0x10 RT23_POWER_LEVELS = [chirp_common.PowerLevel("Low", watts=1.00), chirp_common.PowerLevel("High", watts=2.50)] RT23_DTCS = sorted(chirp_common.DTCS_CODES + [17, 50, 55, 135, 217, 254, 305, 645, 765]) RT23_CHARSET = chirp_common.CHARSET_UPPER_NUMERIC + \ ":;<=>?@ !\"#$%&'()*+,-./" LIST_SIGNALING = ["No", "DTMF"] LIST_STEP = ["2.50K", "5.00K", "6.25K", "10.00K", "12,50K", "20.00K", "25.00K", "50.00K"] ####LIST_OFFON = ["OFF", "ON"] LIST_VOX = ["OFF"] + ["%s" % x for x in range(1, 6)] LIST_TOT = ["OFF"] + ["%s seconds" % x for x in range(30, 300, 30)] LIST_COLOR = ["Blue", "Orange", "Purple"] LIST_VOT = ["0.5S", "1.0S", "1.5S", "2.0S", "3.0S"] LIST_LED = ["Off", "On", "Auto"] LIST_VOICE = ["Off", "Chinese", "English"] LIST_OPNSET = ["Full", "Voltage", "Message"] LIST_SCANS = ["Time Operated", "Carrier Operated", "Search"] LIST_RPTRL = ["0.5S", "1.0S", "1.5S", "2.0S", "2.5S", "3.0S", "3.5S", "4.0S", "4.5S"] LIST_RPTMOD = ["Single", "Double"] LIST_VOLMOD = ["Off", "Sub", "Main"] LIST_TXSEL = ["Edit", "Busy"] LIST_VFOMR = ["VFO", "MR(Frequency)", "MR(Channel #/Name)"] LIST_VFOMRFM = ["VFO", "Channel"] LIST_PTTID = ["Off", "BOT", "EOT", "Both"] LIST_PFKEY = [ "Radio", "Sub-channel Sent", "Scan", "Alarm", "DTMF", "Squelch Off Momentarily", "Battery Power Indicator", "Tone 1750", "Tone 2100", "Tone 1000", "Tone 1450"] RT23_SPECIAL = ["rpt_vfo", "rpt_1", "rpt_2", "rpt_3", "rpt_4", "rpt_5", "vfo_a", "vfo_b"] def _rt23_enter_programming_mode(radio): serial = radio.pipe #magic = "PROIUAM" try: serial.write("PROIUAM") #for j in range(0, len(magic)): # time.sleep(0.002) # serial.write(magic[j]) ack = serial.read(1) except: raise errors.RadioError("Error communicating with radio") if not ack: raise errors.RadioError("No response from radio") elif ack != CMD_ACK: raise errors.RadioError("Radio refused to enter programming mode") try: serial.write("\x02") ident = serial.read(8) except: raise errors.RadioError("Error communicating with radio") if not ident.startswith("P31183"): LOG.debug(util.hexprint(ident)) raise errors.RadioError("Radio returned unknown identification string") try: serial.write(CMD_ACK) ack = serial.read(1) except: raise errors.RadioError("Error communicating with radio") if ack != CMD_ACK: raise errors.RadioError("Radio refused to enter programming mode") def _rt23_exit_programming_mode(radio): serial = radio.pipe try: serial.write("E") except: raise errors.RadioError("Radio refused to exit programming mode") def _rt23_read_block(radio, block_addr, block_size): serial = radio.pipe cmd = struct.pack(">cHb", 'R', block_addr, BLOCK_SIZE) expectedresponse = "W" + cmd[1:] LOG.debug("Reading block %04x..." % (block_addr)) try: serial.write(cmd) response = serial.read(4 + BLOCK_SIZE + 1) if response[:4] != expectedresponse: raise Exception("Error reading block %04x." % (block_addr)) chunk = response[4:] cs = 0 for byte in chunk[:-1]: cs += ord(byte) if ord(chunk[-1]) != (cs & 0xFF): raise Exception("Block failed checksum!") block_data = chunk[:-1] except: raise errors.RadioError("Failed to read block at %04x" % block_addr) return block_data def _rt23_write_block(radio, block_addr, block_size): serial = radio.pipe cmd = struct.pack(">cHb", 'W', block_addr, BLOCK_SIZE) data = radio.get_mmap()[block_addr:block_addr + BLOCK_SIZE] cs = 0 for byte in data: cs += ord(byte) data += chr(cs & 0xFF) LOG.debug("Writing Data:") LOG.debug(util.hexprint(cmd + data)) try: #serial.write(cmd + data) for j in range(0, len(cmd)): time.sleep(0.002) serial.write(cmd[j]) for j in range(0, len(data)): time.sleep(0.002) serial.write(data[j]) if serial.read(1) != CMD_ACK: raise Exception("No ACK") except: raise errors.RadioError("Failed to send block " "to radio at %04x" % block_addr) def do_download(radio): LOG.debug("download") _rt23_enter_programming_mode(radio) data = "" status = chirp_common.Status() status.msg = "Cloning from radio" status.cur = 0 status.max = radio._memsize for addr in range(0, radio._memsize, BLOCK_SIZE): status.cur = addr + BLOCK_SIZE radio.status_fn(status) ####print "Address: %s" % addr block = _rt23_read_block(radio, addr, BLOCK_SIZE) if addr == 0 and block.startswith("\xFF" * 6): block = "P31183" + "\xFF" * 10 data += block LOG.debug("Address: %04x" % addr) LOG.debug(util.hexprint(block)) ####data += radio.MODEL.ljust(8) _rt23_exit_programming_mode(radio) return memmap.MemoryMap(data) def do_upload(radio): status = chirp_common.Status() status.msg = "Uploading to radio" _rt23_enter_programming_mode(radio) status.cur = 0 status.max = radio._memsize for start_addr, end_addr in radio._ranges: for addr in range(start_addr, end_addr, BLOCK_SIZE): status.cur = addr + BLOCK_SIZE radio.status_fn(status) _rt23_write_block(radio, addr, BLOCK_SIZE) ####_rt23_exit_programming_mode(radio) def model_match(cls, data): """Match the opened/downloaded image to the correct version""" if len(data) == 0x1000: rid = data[0x0000:0x0006] return rid == "P31183" else: return False @directory.register class RT23Radio(chirp_common.CloneModeRadio): """RETEVIS RT23""" VENDOR = "Retevis" MODEL = "RT23" BAUD_RATE = 9600 _ranges = [ (0x0000, 0x0EC0), ] _memsize = 0x1000 def get_features(self): rf = chirp_common.RadioFeatures() rf.has_settings = True rf.has_bank = False rf.has_ctone = True rf.has_cross = True rf.has_rx_dtcs = True rf.has_tuning_step = False rf.can_odd_split = True rf.valid_name_length = 7 rf.valid_characters = RT23_CHARSET rf.has_name = True rf.valid_skips = ["", "S"] rf.valid_tmodes = ["", "Tone", "TSQL", "DTCS", "Cross"] rf.valid_cross_modes = ["Tone->Tone", "Tone->DTCS", "DTCS->Tone", "->Tone", "->DTCS", "DTCS->", "DTCS->DTCS"] rf.valid_power_levels = RT23_POWER_LEVELS rf.valid_duplexes = ["", "-", "+", "split", "off"] rf.valid_modes = ["FM", "NFM"] # 25 KHz, 12.5 KHz. rf.memory_bounds = (1, 128) rf.valid_bands = [ (136000000, 174000000), (400000000, 480000000)] rf.valid_special_chans = RT23_SPECIAL return rf def process_mmap(self): self._memobj = bitwise.parse(MEM_FORMAT, self._mmap) def sync_in(self): self._mmap = do_download(self) self.process_mmap() def sync_out(self): do_upload(self) def get_raw_memory(self, number): return repr(self._memobj.memory[number - 1]) def decode_tone(self, val): """Parse the tone data to decode from mem, it returns: Mode (''|DTCS|Tone), Value (None|###), Polarity (None,N,R)""" if val.get_raw() == "\xFF\xFF": return '', None, None val = int(val) if val >= 12000: a = val - 12000 return 'DTCS', a, 'R' elif val >= 8000: a = val - 8000 return 'DTCS', a, 'N' else: a = val / 10.0 return 'Tone', a, None def encode_tone(self, memval, mode, value, pol): """Parse the tone data to encode from UI to mem""" if mode == '': memval[0].set_raw(0xFF) memval[1].set_raw(0xFF) elif mode == 'Tone': memval.set_value(int(value * 10)) elif mode == 'DTCS': flag = 0x80 if pol == 'N' else 0xC0 memval.set_value(value) memval[1].set_bits(flag) else: raise Exception("Internal error: invalid mode `%s'" % mode) def get_memory(self, number): mem = chirp_common.Memory() if isinstance(number, str): # special channel _mem = getattr(self._memobj, number) _nam = None mem.number = - len(RT23_SPECIAL) + RT23_SPECIAL.index(number) mem.extd_number = number _scn = None _usd = None if re.match('^rpt', mem.extd_number): _special_enables = self._memobj.special_enables isused = getattr(_special_enables, mem.extd_number + "_enable") else: isused = True isscan = True else: # regular memory _mem = self._memobj.channels[number-1] _nam = self._memobj.names[number - 1] mem.number = number bitpos = (1 << ((number - 1) % 8)) bytepos = ((number - 1) / 8) _scn = self._memobj.scanflags[bytepos] _usd = self._memobj.usedflags[bytepos] isused = bitpos & int(_usd) isscan = bitpos & int(_scn) if not isused: mem.empty = True return mem mem.freq = int(_mem.rxfreq) * 10 # We'll consider any blank (i.e. 0MHz frequency) to be empty if mem.freq == 0: mem.empty = True return mem if _mem.rxfreq.get_raw() == "\xFF\xFF\xFF\xFF": mem.empty = True return mem if _mem.get_raw() == ("\xFF" * 16): LOG.debug("Initializing empty memory") _mem.set_raw("\x00" * 16) if int(_mem.rxfreq) == int(_mem.txfreq): mem.duplex = "" mem.offset = 0 else: mem.duplex = int(_mem.rxfreq) > int(_mem.txfreq) and "-" or "+" mem.offset = abs(int(_mem.rxfreq) - int(_mem.txfreq)) * 10 if _nam: for char in _nam.name: if str(char) == "\xFF": char = " " mem.name += str(char) mem.name = mem.name.rstrip() mem.mode = _mem.isnarrow and "NFM" or "FM" rxtone = txtone = None txtone = self.decode_tone(_mem.txtone) rxtone = self.decode_tone(_mem.rxtone) chirp_common.split_tone_decode(mem, txtone, rxtone) mem.power = RT23_POWER_LEVELS[_mem.highpower] if _scn: if not isscan: mem.skip = "S" mem.extra = RadioSettingGroup("Extra", "extra") rs = RadioSetting("bcl", "BCL", RadioSettingValueBoolean(_mem.bcl)) mem.extra.append(rs) rs = RadioSetting("pttid", "PTT ID", RadioSettingValueList( LIST_PTTID, LIST_PTTID[_mem.pttid])) mem.extra.append(rs) rs = RadioSetting("signaling", "Optional Signaling", RadioSettingValueList(LIST_SIGNALING, LIST_SIGNALING[_mem.signaling])) mem.extra.append(rs) return mem def set_memory(self, mem): LOG.debug("Setting %i(%s)" % (mem.number, mem.extd_number)) if mem.number < 0: # special channels val = str(RT23_SPECIAL[mem.number + len(RT23_SPECIAL)]) _mem = getattr(self._memobj, val) #_nam = None #_scn = None #_usd = None if re.match('^rpt', val): _special_enables = self._memobj.special_enables setattr(_special_enables, val + "_enable", True) else: _mem = self._memobj.channels[mem.number - 1] _nam = self._memobj.names[mem.number - 1] bitpos = (1 << ((mem.number - 1) % 8)) bytepos = ((mem.number - 1) / 8) _scn = self._memobj.scanflags[bytepos] _usd = self._memobj.usedflags[bytepos] if mem.empty: _mem.set_raw("\xFF" * 16) if mem.number < 0: val = str(RT23_SPECIAL[mem.number + 6]) _special_enables = self._memobj.special_enables setattr(_special_enables, val + "_enable", False) return else: _nam.name = ("\xFF" * 7) _usd &= ~bitpos _scn &= ~bitpos return else: if mem.number < 0: val = str(RT23_SPECIAL[mem.number + 6]) _special_enables = self._memobj.special_enables setattr(_special_enables, val + "_enable", True) else: _usd |= bitpos if _mem.get_raw() == ("\xFF" * 16): LOG.debug("Initializing empty memory") _mem.set_raw("\x00" * 16) if _scn: _scn |= bitpos ##_mem.set_raw("\x00" * 16) _mem.rxfreq = mem.freq / 10 if mem.duplex == "off": for i in range(0, 4): _mem.txfreq[i].set_raw("\xFF") elif mem.duplex == "split": _mem.txfreq = mem.offset / 10 elif mem.duplex == "+": _mem.txfreq = (mem.freq + mem.offset) / 10 elif mem.duplex == "-": _mem.txfreq = (mem.freq - mem.offset) / 10 else: _mem.txfreq = mem.freq / 10 if mem.number >= 0: _namelength = self.get_features().valid_name_length for i in range(_namelength): try: _nam.name[i] = mem.name[i] except IndexError: _nam.name[i] = "\xFF" ####_mem.scan = mem.skip != "S" if mem.skip == "S": _scn &= ~bitpos else: _scn |= bitpos _mem.isnarrow = mem.mode == "NFM" ((txmode, txtone, txpol), (rxmode, rxtone, rxpol)) = \ chirp_common.split_tone_encode(mem) self.encode_tone(_mem.txtone, txmode, txtone, txpol) self.encode_tone(_mem.rxtone, rxmode, rxtone, rxpol) _mem.highpower = mem.power == RT23_POWER_LEVELS[1] for setting in mem.extra: setattr(_mem, setting.get_name(), setting.value) def get_settings(self): ####_keys = self._memobj.keys _settings = self._memobj.settings _mem = self._memobj basic = RadioSettingGroup("basic", "Basic Settings") advanced = RadioSettingGroup("advanced", "Advanced Settings") other = RadioSettingGroup("other", "Other Settings") workmode = RadioSettingGroup("workmode", "Workmode Settings") fmradio = RadioSettingGroup("fmradio", "FM Radio Settings") top = RadioSettings(basic, advanced, other, workmode, fmradio) #step = RadioSetting("step", "Step", RadioSettingValueList( # LIST_STEP, LIST_STEP[_settings.step])) #basic.append(step) save = RadioSetting("save", "Battery Saver", RadioSettingValueBoolean(_settings.save)) basic.append(save) vox = RadioSetting("vox", "VOX Gain", RadioSettingValueList( LIST_VOX, LIST_VOX[_settings.vox])) basic.append(vox) squelch = RadioSetting("squelch", "Squelch Level", RadioSettingValueInteger( 0, 9, _settings.squelch)) basic.append(squelch) relay = RadioSetting("relay", "Repeater", RadioSettingValueBoolean(_settings.relay)) basic.append(relay) tot = RadioSetting("tot", "Time-out timer", RadioSettingValueList( LIST_TOT, LIST_TOT[_settings.tot])) basic.append(tot) beep = RadioSetting("beep", "Key Beep", RadioSettingValueBoolean(_settings.beep)) basic.append(beep) color = RadioSetting("color", "Background Color", RadioSettingValueList( LIST_COLOR, LIST_COLOR[_settings.color - 1])) basic.append(color) vot = RadioSetting("vot", "VOX Delay Time", RadioSettingValueList( LIST_VOT, LIST_VOT[_settings.vot])) basic.append(vot) dwait = RadioSetting("dwait", "Dual Standby", RadioSettingValueBoolean(_settings.dwait)) basic.append(dwait) led = RadioSetting("led", "Background Light", RadioSettingValueList( LIST_LED, LIST_LED[_settings.led])) basic.append(led) voice = RadioSetting("voice", "Voice Prompt", RadioSettingValueList( LIST_VOICE, LIST_VOICE[_settings.voice])) basic.append(voice) roger = RadioSetting("roger", "Roger Beep", RadioSettingValueBoolean(_settings.roger)) basic.append(roger) autolk = RadioSetting("autolk", "Auto Key Lock", RadioSettingValueBoolean(_settings.autolk)) basic.append(autolk) opnset = RadioSetting("opnset", "Power On Message", RadioSettingValueList( LIST_OPNSET, LIST_OPNSET[_settings.opnset])) basic.append(opnset) def _filter(name): filtered = "" for char in str(name): if char in chirp_common.CHARSET_ASCII: filtered += char else: filtered += " " return filtered _msg = self._memobj.poweron_msg ponmsg = RadioSetting("poweron_msg.line1", "Power-On Message 1", RadioSettingValueString( 0, 7, _filter(_msg.line1))) basic.append(ponmsg) scans = RadioSetting("scans", "Scan Mode", RadioSettingValueList( LIST_SCANS, LIST_SCANS[_settings.scans])) basic.append(scans) dw = RadioSetting("dw", "FM Radio Dual Watch", RadioSettingValueBoolean(_settings.dw)) basic.append(dw) name = RadioSetting("name", "Display Names", RadioSettingValueBoolean(_settings.name)) basic.append(name) rptrl = RadioSetting("rptrl", "Repeater TX Delay", RadioSettingValueList( LIST_RPTRL, LIST_RPTRL[_settings.rptrl])) basic.append(rptrl) rptspk = RadioSetting("rptspk", "Repeater Speaker", RadioSettingValueBoolean(_settings.rptspk)) basic.append(rptspk) rptptt = RadioSetting("rptptt", "Repeater PTT Switch", RadioSettingValueBoolean(_settings.rptptt)) basic.append(rptptt) rptmod = RadioSetting("rptmod", "Repeater Mode", RadioSettingValueList( LIST_RPTMOD, LIST_RPTMOD[_settings.rptmod])) basic.append(rptmod) volmod = RadioSetting("volmod", "Volume Mode", RadioSettingValueList( LIST_VOLMOD, LIST_VOLMOD[_settings.volmod])) basic.append(volmod) dst = RadioSetting("dst", "DTMF Side Tone", RadioSettingValueBoolean(_settings.dst)) basic.append(dst) txsel = RadioSetting("txsel", "Priority TX Channel", RadioSettingValueList( LIST_TXSEL, LIST_TXSEL[_settings.txsel])) basic.append(txsel) ste = RadioSetting("ste", "Squelch Tail Eliminate", RadioSettingValueBoolean(_settings.ste)) basic.append(ste) #advanced if _settings.pf1 > 0x0A: val = 0x00 else: val = _settings.pf1 pf1 = RadioSetting("pf1", "PF1 Key", RadioSettingValueList( LIST_PFKEY, LIST_PFKEY[val])) advanced.append(pf1) if _settings.pf2 > 0x0A: val = 0x00 else: val = _settings.pf2 pf2 = RadioSetting("pf2", "PF2 Key", RadioSettingValueList( LIST_PFKEY, LIST_PFKEY[val])) advanced.append(pf2) # other _limit = str(int(_mem.limits.vhf.lower) / 10) val = RadioSettingValueString(0, 3, _limit) val.set_mutable(False) rs = RadioSetting("limits.vhf.lower", "VHF low", val) other.append(rs) _limit = str(int(_mem.limits.vhf.upper) / 10) val = RadioSettingValueString(0, 3, _limit) val.set_mutable(False) rs = RadioSetting("limits.vhf.upper", "VHF high", val) other.append(rs) _limit = str(int(_mem.limits.uhf.lower) / 10) val = RadioSettingValueString(0, 3, _limit) val.set_mutable(False) rs = RadioSetting("limits.uhf.lower", "UHF low", val) other.append(rs) _limit = str(int(_mem.limits.uhf.upper) / 10) val = RadioSettingValueString(0, 3, _limit) val.set_mutable(False) rs = RadioSetting("limits.uhf.upper", "UHF high", val) other.append(rs) #work mode vfomr_a = RadioSetting("vfomr_a", "Display Mode A", RadioSettingValueList( LIST_VFOMR, LIST_VFOMR[_settings.vfomr_a])) workmode.append(vfomr_a) vfomr_b = RadioSetting("vfomr_b", "Display Mode B", RadioSettingValueList( LIST_VFOMR, LIST_VFOMR[_settings.vfomr_b])) workmode.append(vfomr_b) mrcha = RadioSetting("mrcha", "Channel # A", RadioSettingValueInteger( 1, 128, _settings.mrcha)) workmode.append(mrcha) mrchb = RadioSetting("mrchb", "Channel # B", RadioSettingValueInteger( 1, 128, _settings.mrchb)) workmode.append(mrchb) #fm radio vfomr_fm = RadioSetting("vfomr_fm", "FM Radio Display Mode", RadioSettingValueList( LIST_VFOMRFM, LIST_VFOMRFM[_settings.vfomr_fm])) fmradio.append(vfomr_fm) fmch = RadioSetting("fmch", "FM Radio Channel #", RadioSettingValueInteger( 1, 25, _settings.fmch)) fmradio.append(fmch) return top 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]: obj = getattr(obj, bit) setting = bits[-1] else: obj = self._memobj.settings setting = element.get_name() if element.has_apply_callback(): LOG.debug("Using apply callback") element.run_apply_callback() elif setting == "color": setattr(obj, setting, int(element.value) + 1) elif element.value.get_mutable(): LOG.debug("Setting %s = %s" % (setting, element.value)) setattr(obj, setting, element.value) except Exception, e: LOG.debug(element.get_name()) raise @classmethod def match_model(cls, filedata, filename): match_size = False match_model = False # testing the file data size if len(filedata) in [0x1000, ]: match_size = True # testing the model fingerprint match_model = model_match(cls, filedata) if match_size and match_model: return True else: return False