Project

General

Profile

New Model #1035 » th9000-003.patch

David Fannin, 05/14/2014 03:03 PM

View differences:

/dev/null Thu Jan 01 00:00:00 1970 +0000 → chirp/th9000vhf.py Mon May 12 10:04:50 2014 -0700
# Copyright 2012 Dan Smith <dsmith@danplanet.com>
#
# 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 <http://www.gnu.org/licenses/>.
import os
import struct
import time
from chirp import chirp_common
from chirp import directory
from chirp import memmap
from chirp import bitwise
from chirp import errors
from chirp import util
#
# Chirp Driver for TYT TH-9000 VHF (2 meter) Model
# by David Fannin <dfannin@sushisoft.com>, KK6DF
#
# Version 0.2 (Experimental - Known Bugs and Issues)
# Use for development purposes only!
# Features working:
# - Download from Radio
# - Display Memories (only None, Tone, TSQL signalling supported)
# - Save image file
# - memory map decoded (about 90%)
#
# Features not working:
# - Upload to radio
# - Modification of memories
# - feature settings
# - DCS , Cross Signaling
# - Skip channels
#
# Global Parameters
#
MMAPSIZE = 16128
TONES = [62.5] + list(chirp_common.TONES)
TMODES = ['','Tone','DTCS']
DUPLEXES = ['','err','-','+'] # index 2 not used
MODES = ['WFM','FM','NFM'] # 25k, 20k,15k bw
TUNING_STEPS=[ 5.0, 6.25, 8.33, 10.0, 12.5, 15.0, 20.0, 25.0, 30.0, 50.0 ] # index 0-9
POWER_LEVELS=[chirp_common.PowerLevel("High", watts=65),
chirp_common.PowerLevel("Mid", watts=25),
chirp_common.PowerLevel("Low", watts=10)]
CROSS_MODES = chirp_common.CROSS_MODES
VALID_MODEL = ['TH-9000']
#
#
#
MEM_FORMAT = """
#seekto 0x0100;
struct {
bit c[8];
} csetflag[24];
struct {
u8 unknown0100[7];
} ropt0100;
#seekto 0x0120;
struct {
bit c[8];
} cskipflag[24];
struct {
u8 unknown0120[7];
} ropt0120;
"""
MEM_FORMAT = MEM_FORMAT + """
#seekto 0x0200;
struct {
bbcd txrangelow[4];
bbcd txrangehi[4];
bbcd rxrangelow[4];
bbcd rxrangehi[4];
} ropt0200;
"""
MEM_FORMAT = MEM_FORMAT + """
#seekto 0x0210;
struct {
u8 bootup_passwd[6];
u8 unknown2010[10];
} ropt0210;
"""
MEM_FORMAT = MEM_FORMAT + """
#seekto 0x0220;
struct {
u8 display_mode;
u8 vfo_mr;
u8 unknown0220A;
u8 squelch;
u8 unknown0220B[2];
u8 channel_lock;
u8 unknown0220C;
u8 bg_brightness;
u8 unknown0220D;
u8 bg_color;
u8 tbst_freq;
u8 timeout_timer;
u8 unknown0220E;
u8 auto_power_off;
u8 voice_prompt;
} ropt0220;
"""
MEM_FORMAT = MEM_FORMAT + """
#seekto 0x0230;
struct {
u8 unknown0230A:6,
elim_sql_tail:1,
sql_key_function:1;
u8 unknown0230B[2];
u8 unknown0230C:4,
inhibit_init_ops:1,
unknown0230D:1,
inhibit_setup_bg_chk:1,
unknown0230E:1;
u8 tail_elim_type;
u8 choose_tx_power;
u8 unknown0230F[2];
u8 bootup_passwd_flag;
u8 unknown0230G[7];
}ropt0230;
"""
MEM_FORMAT = MEM_FORMAT + """
#seekto 0x2000;
struct {
bbcd freq[4];
bbcd offset[4];
u8 unknown2000A:4,
tune_step:4;
u8 unknown2000B:4,
channel_width:2,
reverse:1,
txoff:1;
u8 talkaround:1,
compander:1,
unknown2000C:2,
power:2,
duplex:2;
u8 unknown2000D:4,
rxtmode:2,
txtmode:2;
u8 unknown2000E:2,
txtone:6;
u8 unknown2000F:2,
rxtone:6;
u8 txcode;
u8 rxcode;
u8 unknown2000G[3];
char name[7];
u8 unknown2000H:6,
busychannellockout:2;
u8 unknown2000I[4];
u8 unknown2000J:7,
scrambler:1;
} memory[200] ;
"""
def _debug(string):
if "CHIRP_DEBUG" in os.environ or True:
print string
def _echo_write(radio, data):
try:
radio.pipe.write(data)
radio.pipe.read(len(data))
except Exception, e:
print "Error writing to radio: %s" % e
raise errors.RadioError("Unable to write to radio")
def _checksum(data):
cs = 0
for byte in data:
cs += ord(byte)
return cs % 256
def _read(radio, length):
try:
data = radio.pipe.read(length)
except Exception, e:
print "Error reading from radio: %s" % e
raise errors.RadioError("Unable to read from radio")
if len(data) != length:
print "Short read from radio (%i, expected %i)" % (len(data),
length)
print util.hexprint(data)
raise errors.RadioError("Short read from radio")
return data
def _ident(radio):
radio.pipe.setTimeout(1)
_echo_write(radio,"PROGRAM")
response = radio.pipe.read(3)
if response != "QX\06":
print "Response was :\n%s" % util.hexprint(response)
raise errors.RadioError("Unsupported model")
_echo_write(radio, "\x02")
response = radio.pipe.read(16)
_debug(util.hexprint(response))
if response[1:8] != "TH-9000":
print "Looking for:\n%s" % util.hexprint("TH-9000")
print "Response was:\n%s" % util.hexprint(response)
raise errors.RadioError("Unsupported model")
def _send(radio, cmd, addr, length, data=None):
frame = struct.pack(">cHb", cmd, addr, length)
if data:
frame += data
frame += chr(_checksum(frame[1:]))
frame += "\x06"
_echo_write(radio, frame)
_debug("Sent:\n%s" % util.hexprint(frame))
if data:
result = radio.pipe.read(1)
if result != "\x06":
print "Ack was: %s" % repr(result)
raise errors.RadioError("Radio did not accept block at %04x" % addr)
return
result = _read(radio, length + 6)
_debug("Got:\n%s" % util.hexprint(result))
header = result[0:4]
data = result[4:-2]
ack = result[-1]
if ack != "\x06":
print "Ack was: %s" % repr(ack)
raise errors.RadioError("Radio NAK'd block at %04x" % addr)
_cmd, _addr, _length = struct.unpack(">cHb", header)
if _addr != addr or _length != _length:
print "Expected/Received:"
print " Length: %02x/%02x" % (length, _length)
print " Addr: %04x/%04x" % (addr, _addr)
raise errors.RadioError("Radio send unexpected block")
cs = _checksum(result[1:-2])
if cs != ord(result[-2]):
print "Calculated: %02x" % cs
print "Actual: %02x" % ord(result[-2])
raise errors.RadioError("Block at 0x%04x failed checksum" % addr)
return data
def _finish(radio):
endframe = "\x45\x4E\x44"
_echo_write(radio, endframe)
result = radio.pipe.read(1)
if result != "\x06":
print "Got:\n%s" % util.hexprint(result)
raise errors.RadioError("Radio did not finish cleanly")
def do_download(radio):
print "download"
_ident(radio)
_memobj = None
data = ""
for start,end in radio._ranges:
for addr in range(start,end,0x10):
block = _send(radio,'R',addr,0x10)
data += block
status = chirp_common.Status()
status.cur = len(data)
status.max = end
status.msg = "Cloning from radio"
radio.status_fn(status)
_finish(radio)
return memmap.MemoryMap(data)
def do_upload(radio):
"""This is your upload function"""
raise Exception("Upload not yet working.")
return
# Get the serial port connection
serial = radio.pipe
# Our fake radio is just a simple upload of 1000 bytes
# to the serial port. Do that one byte at a time, reading
# from our memory map
for i in range(0, MMAPSIZE):
serial.write(radio.get_mmap()[i])
@directory.register
class Th9000VHFRadio(chirp_common.CloneModeRadio):
"""TYT TH-9000 VHF"""
VENDOR = "TYT"
MODEL = "TH9000"
BAUD_RATE = 9600
_file_ident = "TH-9000"
_memsize = MMAPSIZE
_ranges = [(0x0000,0x4000)]
@classmethod
def get_prompts(cls):
rp = chirp_common.RadioPrompts()
rp.experimental = ("The TYT TH-9000 driver is experimental."
"Proceed with Caution and backup your data")
return rp
def get_features(self):
rf = chirp_common.RadioFeatures()
rf.has_settings = False
rf.has_bank = False
rf.has_cross = True
rf.has_tuning_step = True
rf.has_rx_dtcs = True
rf.valid_skips = ["","S","P"]
rf.memory_bounds = (0, 199)
rf.valid_bands = [(136000000, 172000000)]
rf.valid_name_length = 7
rf.valid_characters = chirp_common.CHARSET_UPPER_NUMERIC + "-"
rf.valid_modes = MODES
rf.valid_tmodes = chirp_common.TONE_MODES
rf.valid_cross_modes = CROSS_MODES
rf.valid_power_levels = POWER_LEVELS
rf.valid_dtcs_codes = chirp_common.ALL_DTCS_CODES
return rf
# Do a download of the radio from the serial port
def sync_in(self):
self._mmap = do_download(self)
self.process_mmap()
# Do an upload of the radio to the serial port
def sync_out(self):
do_upload(self)
def process_mmap(self):
self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
# Return a raw representation of the memory object, which
# is very helpful for development
def get_raw_memory(self, number):
return repr(self._memobj.memory[number])
# not working
def _get_dcs_index(self, _mem,which):
base = getattr(_mem, '%scode' % which)
extra = getattr(_mem, '%sdcsextra' % which)
return (int(extra) << 8) | int(base)
def _set_dcs_index(self, _mem, which, index):
base = getattr(_mem, '%scode' % which)
extra = getattr(_mem, '%sdcsextra' % which)
base.set_value(index & 0xFF)
extra.set_value(index >> 8)
# Extract a high-level memory object from the low-level memory map
# This is called to populate a memory in the UI
def get_memory(self, number):
# Get a low-level memory object mapped to the image
_mem = self._memobj.memory[number]
# Create a high-level memory object to return to the UI
mem = chirp_common.Memory()
mem.number = number # Set the memory number
mem.freq = int(_mem.freq) * 100
mem.offset = int(_mem.offset) * 100
mem.name = str(_mem.name).rstrip() # Set the alpha tag
mem.duplex = DUPLEXES[_mem.duplex]
mem.mode = MODES[_mem.channel_width]
mem.power = POWER_LEVELS[_mem.power]
rxtone = txtone = None
rxmode = TMODES[_mem.rxtmode]
txmode = TMODES[_mem.txtmode]
# doesn't work
if rxmode == "Tone":
rxtone = TONES[_mem.rxtone]
elif rxmode == "DTCS":
rxtone = chirp_common.ALL_DTCS_CODES[self._get_dcs_index(_mem,'rx')]
if txmode == "Tone":
txtone = TONES[_mem.txtone]
elif txmode == "DTCS":
txtone = chirp_common.ALL_DTCS_CODES[self._get_dcs_index(_mem,'tx')]
rxpol = ""
txpol = ""
chirp_common.split_tone_decode(mem,
(txmode, txtone, txpol),
(rxmode, rxtone, rxpol))
mem.skip = ""
# We'll consider any blank (i.e. 0MHz frequency) to be empty
if mem.freq == 0:
mem.empty = True
return mem
# Store details about a high-level memory to the memory map
# This is called when a user edits a memory in the UI
def set_memory(self, mem):
# Get a low-level memory object mapped to the image
_mem = self._memobj.memory[mem.number]
_mem.freq = mem.freq / 100 # Convert to low-level frequency
_mem.offset = mem.offset / 100 # Convert to low-level frequency
_mem.name = mem.name.ljust(7)[:7] # Store the alpha tag
@classmethod
def match_model(cls,filedata,filename):
return cls._file_ident in filedata[0x00:0x30]
chirp/th9000vhf.py Mon May 12 10:04:50 2014 -0700 → chirp/th9000vhf.py Wed May 14 14:52:17 2014 -0700
from chirp import bitwise
from chirp import errors
from chirp import util
from chirp.settings import RadioSetting, RadioSettingGroup, \
RadioSettingValueInteger, RadioSettingValueList, \
RadioSettingValueBoolean, RadioSettingValueString, \
RadioSettingValueFloat, InvalidValueError
#
# Chirp Driver for TYT TH-9000 VHF (2 meter) Model
# by David Fannin <dfannin@sushisoft.com>, KK6DF
#
# Version 0.2 (Experimental - Known Bugs and Issues)
# Version 0.3 (Experimental - Known Bugs and Issues)
# Use for development purposes only!
# Features working:
# - Download from Radio
# - Display Memories (only None, Tone, TSQL signalling supported)
# - Save image file
# - memory map decoded (about 90%)
#
# Features not working:
# - Upload to radio
# - Modification of memories
# - feature settings
#
# Features not working:
# - DCS , Cross Signaling
# - Skip channels
......
CROSS_MODES = chirp_common.CROSS_MODES
VALID_MODEL = ['TH-9000']
APO_LIST = [ "Off","30 min","1 hr","2 hrs" ]
BGCOLOR_LIST = ["Blue","Orange","Purple"]
BGBRIGHT_LIST = ["%s" % x for x in range(1,32)]
SQUELCH_LIST = ["Off"] + ["Level %s" % x for x in range(1,20)]
TIMEOUT_LIST = ["Off"] + ["%s min" % x for x in range(1,30)]
TXPWR_LIST = ["60W","25W"] # maximum power for Hi setting
TBSTFREQ_LIST = ["1750Hz","2100Hz","1000Hz","1450Hz"]
BEEP_LIST = ["Off","On"]
SETTING_LISTS = {
"auto_power_off": APO_LIST,
"bg_color" : BGCOLOR_LIST,
"bg_brightness" : BGBRIGHT_LIST,
"squelch" : SQUELCH_LIST,
"timeout_timer" : TIMEOUT_LIST,
"choose_tx_power": TXPWR_LIST,
"tbst_freq" : TBSTFREQ_LIST,
"voice_prompt" : BEEP_LIST
}
#
#
......
#seekto 0x0100;
struct {
bit c[8];
} csetflag[24];
} csetflag[32];
struct {
u8 unknown0100[7];
......
#seekto 0x0120;
struct {
bit c[8];
} cskipflag[24];
} cskipflag[32];
struct {
u8 unknown0120[7];
......
bbcd txrangehi[4];
bbcd rxrangelow[4];
bbcd rxrangehi[4];
} ropt0200;
} freqrange;
"""
MEM_FORMAT = MEM_FORMAT + """
......
u8 unknown0220E;
u8 auto_power_off;
u8 voice_prompt;
} ropt0220;
"""
MEM_FORMAT = MEM_FORMAT + """
#seekto 0x0230;
struct {
u8 unknown0230A:6,
elim_sql_tail:1,
sql_key_function:1;
......
u8 unknown0230F[2];
u8 bootup_passwd_flag;
u8 unknown0230G[7];
}ropt0230;
} settings;
"""
......
def do_download(radio):
print "download"
_ident(radio)
_memobj = None
......
status = chirp_common.Status()
status.cur = len(data)
status.max = end
status.msg = "Cloning from radio"
status.msg = "Downloading from radio"
radio.status_fn(status)
_finish(radio)
......
return memmap.MemoryMap(data)
def do_upload(radio):
"""This is your upload function"""
raise Exception("Upload not yet working.")
return
# Get the serial port connection
serial = radio.pipe
_ident(radio)
# Our fake radio is just a simple upload of 1000 bytes
# to the serial port. Do that one byte at a time, reading
# from our memory map
for i in range(0, MMAPSIZE):
serial.write(radio.get_mmap()[i])
for start,end in radio._ranges:
for addr in range(start,end,0x10):
if addr < 0x0100:
continue
block = radio._mmap[addr:addr+0x10]
_send(radio,'W',addr,len(block),block)
status = chirp_common.Status()
status.cur = addr
status.max = end
status.msg = "Uploading to Radio"
radio.status_fn(status)
_finish(radio)
@directory.register
class Th9000VHFRadio(chirp_common.CloneModeRadio):
......
@classmethod
def get_prompts(cls):
rp = chirp_common.RadioPrompts()
rp.experimental = ("The TYT TH-9000 driver is experimental."
"Proceed with Caution and backup your data")
rp.experimental = ("The TYT TH-9000 driver is an alpha version."
"Use only for testing and development"
"Proceed with Caution and backup your data"
"as you may lose it using this driver!")
return rp
def get_features(self):
rf = chirp_common.RadioFeatures()
rf.has_settings = False
rf.has_settings = True
rf.has_bank = False
rf.has_cross = True
rf.has_tuning_step = True
rf.has_rx_dtcs = True
rf.valid_skips = ["","S","P"]
rf.valid_skips = ["","S"]
rf.memory_bounds = (0, 199)
rf.valid_bands = [(136000000, 172000000)]
rf.valid_name_length = 7
rf.valid_characters = chirp_common.CHARSET_UPPER_NUMERIC + "-"
rf.valid_modes = MODES
......
rf.valid_cross_modes = CROSS_MODES
rf.valid_power_levels = POWER_LEVELS
rf.valid_dtcs_codes = chirp_common.ALL_DTCS_CODES
rf.valid_bands = [(136000000, 174000000)]
return rf
# Do a download of the radio from the serial port
......
extra.set_value(index >> 8)
# Extract a high-level memory object from the low-level memory map
# This is called to populate a memory in the UI
def get_memory(self, number):
# Get a low-level memory object mapped to the image
_mem = self._memobj.memory[number]
# Create a high-level memory object to return to the UI
# get flag info
cbyte = number / 8 ;
cbit = 7 - (number % 8) ;
setflag = self._memobj.csetflag[cbyte].c[cbit];
skipflag = self._memobj.cskipflag[cbyte].c[cbit];
mem = chirp_common.Memory()
mem.number = number # Set the memory number
if setflag == 1:
mem.empty = True
return mem
mem.freq = int(_mem.freq) * 100
mem.offset = int(_mem.offset) * 100
mem.name = str(_mem.name).rstrip() # Set the alpha tag
......
txmode = TMODES[_mem.txtmode]
rxpol = txpol = ""
# doesn't work
if rxmode == "Tone":
rxpol = ""
rxtone = TONES[_mem.rxtone]
elif rxmode == "DTCS":
rxpol = "N"
rxtone = chirp_common.ALL_DTCS_CODES[self._get_dcs_index(_mem,'rx')]
if txmode == "Tone":
txpol = ""
txtone = TONES[_mem.txtone]
elif txmode == "DTCS":
txpol = "N"
txtone = chirp_common.ALL_DTCS_CODES[self._get_dcs_index(_mem,'tx')]
rxpol = ""
txpol = ""
chirp_common.split_tone_decode(mem,
(txmode, txtone, txpol),
(rxmode, rxtone, rxpol))
mem.skip = ""
mem.skip = "S" if skipflag == 1 else ""
# We'll consider any blank (i.e. 0MHz frequency) to be empty
......
# This is called when a user edits a memory in the UI
def set_memory(self, mem):
# Get a low-level memory object mapped to the image
_mem = self._memobj.memory[mem.number]
cbyte = mem.number / 8
cbit = 7 - (mem.number % 8)
if mem.empty:
self._memobj.csetflag[cbyte].c[cbit] = 1
self._memobj.cskipflag[cbyte].c[cbit] = 1
return
self._memobj.csetflag[cbyte].c[cbit] = 0
self._memobj.cskipflag[cbyte].c[cbit] = 1 if (mem.skip == "S") else 0
_mem.set_raw("\x00" * 32)
_mem.freq = mem.freq / 100 # Convert to low-level frequency
_mem.offset = mem.offset / 100 # Convert to low-level frequency
_mem.name = mem.name.ljust(7)[:7] # Store the alpha tag
_mem.duplex = DUPLEXES.index(mem.duplex)
@classmethod
def match_model(cls,filedata,filename):
return cls._file_ident in filedata[0x00:0x30]
try:
_mem.channel_width = MODES.index(mem.mode)
except ValueError:
_mem.channel_width = 0
((txmode, txtone, txpol),
(rxmode, rxtone, rxpol)) = chirp_common.split_tone_encode(mem)
_mem.txtmode = TMODES.index(txmode)
_mem.rxtmode = TMODES.index(rxmode)
if txmode == "Tone":
_mem.txtone = TONES.index(txtone)
elif txmode == "DTCS":
self._set_dcs_index(_mem,'tx',chirp_common.ALL_DTCS_CODES.index(txtone))
if rxmode == "Tone":
_mem.rxtone = TONES.index(rxtone)
elif rxmode == "DTCS":
self._set_dcs_index(_mem, 'rx', chirp_common.ALL_DTCS_CODES.index(rxtone))
#_mem.txinv = txpol == "N"
#_mem.rxinv = rxpol == "N"
if mem.power:
_mem.power = POWER_LEVELS.index(mem.power)
else:
_mem.power = 0
def _get_settings(self):
_settings = self._memobj.settings
_freqrange = self._memobj.freqrange
basic = RadioSettingGroup("basic","Global Settings")
freqrange = RadioSettingGroup("freqrange","Frequency Ranges")
top = RadioSettingGroup("top","All Settings",basic,freqrange)
rs = RadioSetting("bg_color","Background Color",
RadioSettingValueList(BGCOLOR_LIST, BGCOLOR_LIST[_settings.bg_color]))
basic.append(rs)
rs = RadioSetting("bg_brightness","Background Brightness",
RadioSettingValueList(BGBRIGHT_LIST, BGBRIGHT_LIST[_settings.bg_brightness]))
basic.append(rs)
rs = RadioSetting("squelch","Squelch Level",
RadioSettingValueList(SQUELCH_LIST, SQUELCH_LIST[_settings.squelch]))
basic.append(rs)
rs = RadioSetting("timeout_timer","Timeout Timer",
RadioSettingValueList(TIMEOUT_LIST, TIMEOUT_LIST[_settings.timeout_timer]))
basic.append(rs)
rs = RadioSetting("auto_power_off","Auto Power Off",
RadioSettingValueList(APO_LIST, APO_LIST[_settings.auto_power_off]))
basic.append(rs)
rs = RadioSetting("voice_prompt","Beep Prompt",
RadioSettingValueList(BEEP_LIST, BEEP_LIST[_settings.voice_prompt]))
basic.append(rs)
rs = RadioSetting("tbst_freq","Tone Burst Frequency",
RadioSettingValueList(TBSTFREQ_LIST, TBSTFREQ_LIST[_settings.tbst_freq]))
basic.append(rs)
rs = RadioSetting("choose_tx_power","Max Level of TX Power",
RadioSettingValueList(TXPWR_LIST, TXPWR_LIST[_settings.choose_tx_power]))
basic.append(rs)
rs = RadioSetting("txrangelow","TX Freq, Lower Limit (khz)", RadioSettingValueInteger(136000,144000, int(_freqrange.txrangelow)/10))
freqrange.append(rs)
rs = RadioSetting("txrangehi","TX Freq, Upper Limit (khz)", RadioSettingValueInteger(148000,174000,int(_freqrange.txrangehi)/10))
freqrange.append(rs)
rs = RadioSetting("rxrangelow","RX Freq, Lower Limit (khz)", RadioSettingValueInteger(136000,144000, int(_freqrange.rxrangelow)/10))
freqrange.append(rs)
rs = RadioSetting("rxrangehi","RX Freq, Upper Limit (khz)", RadioSettingValueInteger(148000,174000,int(_freqrange.rxrangehi)/10))
freqrange.append(rs)
return top
def get_settings(self):
try:
return self._get_settings()
except:
import traceback
print "failed to parse settings"
traceback.print_exc()
return None
def set_settings(self,settings):
_settings = self._memobj.settings
for element in settings:
if not isinstance(element,RadioSetting):
self.set_settings(element)
continue
else:
try:
name = element.get_name()
if name in ["txrangelow","txrangehi","rxrangelow","rxrangehi"]:
print "setting %s = %s" % (name,int(element.value)*10)
setattr(self._memobj.freqrange,name,int(element.value)*10)
continue
obj = _settings
setting = element.get_name()
if element.has_apply_callback():
print "using apply callback"
element.run_apply_callback()
else:
print "Setting %s = %s" % (setting, element.value)
setattr(obj, setting, element.value)
except Exception, e:
print element.get_name()
raise
@classmethod
def match_model(cls, filedata, filename):
return cls._file_ident in filedata[0x10:0x20]
(4-4/14)