# HG changeset patch # User Dan Smith dsmith@danplanet.com # Date 1335562541 25200 # Node ID f805c420592f8a8b1b0dd89107920c6bbed7fdf7 # Parent db82df47f205409ac1f71304f7372ca7f7d88e52 pylint fixes round 1 #93
diff -r db82df47f205 -r f805c420592f chirp/alinco.py --- a/chirp/alinco.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/alinco.py Fri Apr 27 14:35:41 2012 -0700 @@ -13,11 +13,11 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
-from chirp import chirp_common, bitwise, memmap, errors, directory +from chirp import chirp_common, bitwise, memmap, errors, directory, util
import time
-DRx35_mem_format = """ +DRX35_MEM_FORMAT = """ #seekto 0x0120; u8 used_flags[25];
@@ -59,7 +59,9 @@ STEPS = [5.0, 10.0, 12.5, 15.0, 20.0, 25.0, 30.0]
class AlincoStyleRadio(chirp_common.CloneModeRadio): + """Base class for all known Alinco radios""" _memsize = 0 + _model = "NONE"
def _send(self, data): self.pipe.write(data) @@ -96,20 +98,19 @@ time.sleep(0.1)
if self.status_fn: - s = chirp_common.Status() - s.cur = addr + 16 - s.max = self._memsize - s.msg = "Downloading from radio" - self.status_fn(s) + status = chirp_common.Status() + status.cur = addr + 16 + status.max = self._memsize + status.msg = "Downloading from radio" + self.status_fn(status)
self._send("AL~E\r\n") - r = self.pipe.read(20) - #print r + self.pipe.read(20)
return memmap.MemoryMap(data)
def _identify(self): - for i in range(0, 3): + for _i in range(0, 3): self._send("%s\r\n" % self._model) resp = self.pipe.read(6) if resp.strip() == "OK": @@ -137,18 +138,18 @@ time.sleep(0.1)
if self.status_fn: - s = chirp_common.Status() - s.cur = addr + 16 - s.max = self._memsize - s.msg = "Uploading to radio" - self.status_fn(s) + status = chirp_common.Status() + status.cur = addr + 16 + status.max = self._memsize + status.msg = "Uploading to radio" + self.status_fn(status)
self._send("AL~E\r\n") - r = self.pipe.read(20) + self.pipe.read(20) #print r
def process_mmap(self): - self._memobj = bitwise.parse(DRx35_mem_format, self._mmap) + self._memobj = bitwise.parse(DRX35_MEM_FORMAT, self._mmap)
def sync_in(self): try: @@ -183,32 +184,33 @@ [chr(x + ord("A")) for x in range(0, 26)] + [" "] + \ list("\x00" * 128)
+def _get_name(_mem): + name = "" + for i in _mem.name: + if not i: + break + name += CHARSET[i] + return name + +def _set_name(mem, _mem): + name = [0x00] * 7 + j = 0 + for i in range(0, 7): + try: + name[j] = CHARSET.index(mem.name[i]) + j += 1 + except IndexError: + pass + except ValueError: + pass + return name + class DRx35Radio(AlincoStyleRadio): + """Base class for the DR-x35 radios""" _range = [(118000000, 155000000)] _power_levels = [] _valid_tones = list(chirp_common.TONES)
- def _get_name(self, mem, _mem): - name = "" - for i in _mem.name: - if not i: - break - name += CHARSET[i] - return name - - def _set_name(self, mem, _mem): - name = [0x00] * 7 - j = 0 - for i in range(0, 7): - try: - name[j] = CHARSET.index(mem.name[i]) - j += 1 - except IndexError: - pass - except ValueError: - pass - return name - def get_features(self): rf = chirp_common.RadioFeatures() rf.valid_tmodes = ["", "Tone", "TSQL", "DTCS"] @@ -254,7 +256,7 @@ if _skp & bit: mem.skip = "S"
- mem.name = self._get_name(mem, _mem).rstrip() + mem.name = _get_name(_mem).rstrip()
return mem
@@ -298,10 +300,11 @@ else: _skp &= ~bit
- _mem.name = self._set_name(mem, _mem) + _mem.name = _set_name(mem, _mem)
@directory.register class DR03Radio(DRx35Radio): + """Alinco DR03""" VENDOR = "Alinco" MODEL = "DR03T"
@@ -316,6 +319,7 @@
@directory.register class DR06Radio(DRx35Radio): + """Alinco DR06""" VENDOR = "Alinco" MODEL = "DR06T"
@@ -330,6 +334,7 @@
@directory.register class DR135Radio(DRx35Radio): + """Alinco DR135""" VENDOR = "Alinco" MODEL = "DR135T"
@@ -344,6 +349,7 @@
@directory.register class DR235Radio(DRx35Radio): + """Alinco DR235""" VENDOR = "Alinco" MODEL = "DR235T"
@@ -358,6 +364,7 @@
@directory.register class DR435Radio(DRx35Radio): + """Alinco DR435""" VENDOR = "Alinco" MODEL = "DR435T"
@@ -385,6 +392,7 @@
@directory.register class DJ596Radio(DRx35Radio): + """Alinco DJ596""" VENDOR = "Alinco" MODEL = "DJ596"
@@ -402,6 +410,7 @@
@directory.register class JT220MRadio(DRx35Radio): + """Jetstream JT220""" VENDOR = "Jetstream" MODEL = "JT220M"
diff -r db82df47f205 -r f805c420592f chirp/bitwise.py --- a/chirp/bitwise.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/bitwise.py Fri Apr 27 14:35:41 2012 -0700 @@ -136,6 +136,10 @@ def set_raw(self, data): self._data[self._offset] = data[:self._size]
+ def __getattr__(self, name): + raise AttributeError("Unknown attribute %s in %s" % (name, + self.__class__)) + def __repr__(self): return "(%s:%i bytes @ %04x)" % (self.__class__.__name__, self._size, @@ -542,7 +546,10 @@ self._keys.append(key)
def __getattr__(self, name): - return self._generators[name] + try: + return self._generators[name] + except KeyError: + raise AttributeError("No attribute %s in struct" % name)
def __setattr__(self, name, value): if not self.__dict__.has_key("_structDataElement__init"): diff -r db82df47f205 -r f805c420592f chirp/chirp_common.py --- a/chirp/chirp_common.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/chirp_common.py Fri Apr 27 14:35:41 2012 -0700 @@ -17,9 +17,7 @@
#print "Using separation character of '%s'" % SEPCHAR
-import threading import math -from decimal import Decimal
from chirp import errors, memmap
@@ -60,7 +58,8 @@ "->DTCS", ]
-MODES = ["WFM", "FM", "NFM", "AM", "NAM", "DV", "USB", "LSB", "CW", "RTTY", "DIG", "PKT", "NCW", "NCWR", "CWR", "P25"] +MODES = ["WFM", "FM", "NFM", "AM", "NAM", "DV", "USB", "LSB", "CW", "RTTY", + "DIG", "PKT", "NCW", "NCWR", "CWR", "P25"]
STD_6M_OFFSETS = [ (51620000, 51980000, -500000), @@ -108,6 +107,7 @@
# NB: This only works for some bands, throws an Exception otherwise def freq_to_band(freq): + """Returns the band (in cm) for a given frequency""" for band, (lo, hi) in BAND_TO_MHZ.items(): if int(freq) > lo and int(freq) < hi: return band @@ -138,12 +138,15 @@ CHARSET_ASCII = "".join([chr(x) for x in range(ord(" "), ord("~")+1)])
def watts_to_dBm(watts): + """Converts @watts in watts to dBm""" return int(10 * math.log10(int(watts * 1000)))
def dBm_to_watts(dBm): + """Converts @dBm from dBm to watts""" return int(math.pow(10, (dBm - 30) / 10))
class PowerLevel: + """Represents a power level supported by a radio""" def __init__(self, label, watts=0, dBm=0): if watts: dBm = watts_to_dBm(watts) @@ -180,6 +183,7 @@ return "%s (%i dBm)" % (self._label, self._power)
def parse_freq(freqstr): + """Parse a frequency string and return the value in integral Hz""" if "." in freqstr: MHz, kHz = freqstr.split(".") else: @@ -192,9 +196,12 @@ return int(("%s%-6s" % (MHz, kHz)).replace(" ", "0"))
def format_freq(freq): + """Format a frequency given in Hz as a string""" + return "%i.%06i" % (freq / 1000000, freq % 1000000)
class Memory: + """Base class for a single radio memory""" freq = 0 number = 0 extd_number = "" @@ -262,13 +269,15 @@ return "Memory[%i]" % self.number
def dupe(self): - m = self.__class__() + """Return a deep copy of @self""" + mem = self.__class__() for k, v in self.__dict__.items(): - m.__dict__[k] = v + mem.__dict__[k] = v
- return m + return mem
def clone(self, source): + """Absorb all of the properties of @source""" for k, v in source.__dict__.items(): self.__dict__[k] = v
@@ -294,9 +303,11 @@ self.__dict__[name] = val
def format_freq(self): + """Return a properly-formatted string of this memory's frequency""" return format_freq(self.freq)
def parse_freq(self, freqstr): + """Set the frequency from a string""" self.freq = parse_freq(freqstr) return self.freq
@@ -321,7 +332,7 @@ else: dup = self.duplex
- return "Memory %i: %s%s%s %s (%s) r%.1f%s c%.1f%s d%03i%s%s [TS=%.2f]"% \ + return "Memory %i: %s%s%s %s (%s) r%.1f%s c%.1f%s d%03i%s%s [%.2f]"% \ (self.number, format_freq(self.freq), dup, @@ -338,6 +349,7 @@ self.tuning_step)
def to_csv(self): + """Return a CSV representation of this memory""" return [ "%i" % self.number, "%s" % self.name, @@ -355,18 +367,16 @@ "%s" % self.comment, "", "", "", ""]
- class Callable: - def __init__(self, target): - self.__call__ = target - - def _from_csv(_line): + @classmethod + def _from_csv(cls, _line): line = _line.strip() if line.startswith("Location"): raise errors.InvalidMemoryLocation("Non-CSV line")
vals = line.split(SEPCHAR) if len(vals) < 11: - raise errors.InvalidDataError("CSV format error (14 columns expected)") + raise errors.InvalidDataError("CSV format error " + + "(14 columns expected)")
if vals[10] == "DV": mem = DVMemory() @@ -376,9 +386,8 @@ mem.really_from_csv(vals) return mem
- from_csv = Callable(_from_csv) - def really_from_csv(self, vals): + """Careful parsing of split-out @vals""" try: self.number = int(vals[0]) except: @@ -450,6 +459,7 @@ return True
class DVMemory(Memory): + """A Memory with D-STAR attributes""" dv_urcall = "CQCQCQ" dv_rpt1call = "" dv_rpt2call = "" @@ -493,10 +503,11 @@ self.dv_rpt2call = vals[17].rstrip()[:8] try: self.dv_code = int(vals[18].strip()) - except: + except Exception: self.dv_code = 0
class Bank: + """Base class for a radio's Bank""" def __init__(self, model, index, name): self._model = model self._index = index @@ -520,6 +531,7 @@ return self.get_index() == other.get_index()
class NamedBank(Bank): + """A bank that can have a name""" def set_name(self, name): """Changes the user-adjustable bank name""" self._name = name @@ -556,6 +568,7 @@ raise Exception("Not implemented")
class BankIndexInterface: + """Interface for banks with index capabilities""" def get_index_bounds(self): """Returns a tuple (lo,hi) of the minimum and maximum bank indices""" raise Exception("Not implemented") @@ -579,18 +592,16 @@ pass
def console_status(status): + """Write a status object to the console""" import sys
sys.stderr.write("\r%s" % status)
-class Callable: - def __init__(self, target): - self.__call__ = target - BOOLEAN = [True, False]
class RadioFeatures: + """Radio Feature Flags""" _valid_map = { # General "has_bank_index" : BOOLEAN, @@ -602,7 +613,6 @@ "has_bank" : BOOLEAN, "has_bank_names" : BOOLEAN, "has_tuning_step" : BOOLEAN, - "has_name" : BOOLEAN, "has_ctone" : BOOLEAN, "has_cross" : BOOLEAN, "has_infinite_number" : BOOLEAN, @@ -663,11 +673,17 @@ name)) self.__dict__[name] = val
+ def __getattr__(self, name): + raise AttributeError("pylint is confused by RadioFeatures") + def init(self, attribute, default, doc=None): + """Initialize a feature flag @attribute with default value @default, + and documentation string @doc""" self.__setattr__(attribute, default) self.__docs[attribute] = doc
def get_doc(self, attribute): + """Return the description of @attribute""" return self.__docs[attribute]
def __init__(self): @@ -751,70 +767,79 @@ "callsign at the beginning of the master URCALL list")
def is_a_feature(self, name): + """Returns True if @name is a valid feature flag name""" return name in self._valid_map.keys()
def __getitem__(self, name): return self.__dict__[name]
class ValidationMessage(str): + """Base class for Validation Errors and Warnings""" pass
class ValidationWarning(ValidationMessage): + """A non-fatal warning during memory validation""" pass
class ValidationError(ValidationMessage): + """A fatal error during memory validation""" pass
class Radio: + """Base class for all Radio drivers""" BAUD_RATE = 9600 HARDWARE_FLOW = False VENDOR = "Unknown" MODEL = "Unknown" VARIANT = ""
- status_fn = lambda x, y: console_status(y) + def status_fn(self, status): + """Deliver @status to the UI""" + console_status(status)
def __init__(self, pipe): self.errors = [] self.pipe = pipe
def get_features(self): + """Return a RadioFeatures object for this radio""" return RadioFeatures()
def get_settings(self): + """Return a RadioSettingsGroup object for this radio""" return None
def set_settings(self, settings): + """Sets the settings contained in the @settings object that has + been queried with get_settings() and modified""" raise Exception("Not implemented")
- def _get_name_raw(*args): - cls = args[-1] + @classmethod + def get_name(cls): + """Return a printable name for this radio""" return "%s %s" % (cls.VENDOR, cls.MODEL)
- def get_name(self): - return self._get_name_raw(self.__class__) - - _get_name = Callable(_get_name_raw) - def set_pipe(self, pipe): + """Set the serial object to be used for communications""" self.pipe = pipe
def get_memory(self, number): + """Return a Memory object for the memory at location @number""" pass
def erase_memory(self, number): - m = Memory() - m.number = number - m.empty = True - self.set_memory(m) + """Erase memory at location @number""" + mem = Memory() + mem.number = number + mem.empty = True + self.set_memory(mem)
def get_memories(self, lo=None, hi=None): + """Get all the memories between @lo and @hi""" pass
def set_memory(self, memory): - pass - - def set_memories(self, memories): + """Set the memory object @memory""" pass
def get_bank_model(self): @@ -822,22 +847,30 @@ return None
def get_raw_memory(self, number): + """Return a raw string describing the memory at @number""" pass
def get_special_locations(self): + """Return a list of special memory location names""" return []
def filter_name(self, name): + """Filter @name to just the length and characters supported""" rf = self.get_features() if rf.valid_characters == rf.valid_characters.upper(): # Radio only supports uppercase, so help out here name = name.upper() - return "".join([x for x in name[:rf.valid_name_length] if x in rf.valid_characters]) + return "".join([x for x in name[:rf.valid_name_length] + if x in rf.valid_characters])
def get_sub_devices(self): + """Return a list of sub-device Radio objects, if + RadioFeatures.has_sub_devices is True""" return []
def validate_memory(self, mem): + """Return a list of warnings and errors that will be encoundered + if trying to set @mem on the current radio""" msgs = [] rf = self.get_features()
@@ -857,8 +890,10 @@ msgs.append(msg) else: if mem.tmode == "Cross": - if rf.valid_cross_modes and mem.cross_mode not in rf.valid_cross_modes: - msg = ValidationError("Cross tone mode %s not supported" % mem.cross_mode) + if rf.valid_cross_modes and \ + mem.cross_mode not in rf.valid_cross_modes: + msg = ValidationError("Cross tone mode %s not supported" % \ + mem.cross_mode) msgs.append(msg)
if rf.has_dtcs_polarity and mem.dtcs_polarity not in rf.valid_dtcs_pols: @@ -933,16 +968,24 @@ """A file-backed radio stores its data in a file""" FILE_EXTENSION = "img"
+ def __init__(self, *args, **kwargs): + Radio.__init__(self, *args, **kwargs) + self._memobj = None + def save(self, filename): + """Save the radio's memory map to @filename""" self.save_mmap(filename)
def load(self, filename): + """Load the radio's memory map object from @filename""" self.load_mmap(filename)
def process_mmap(self): + """Process a newly-loaded or downloaded memory map""" pass
def load_mmap(self, filename): + """Load the radio's memory map from @filename""" mapfile = file(filename, "rb") self._mmap = memmap.MemoryMap(mapfile.read()) mapfile.close() @@ -957,26 +1000,13 @@ mapfile = file(filename, "wb") mapfile.write(self._mmap.get_packed()) mapfile.close() - except IOError,e: + except IOError: raise Exception("File Access Error")
def get_mmap(self): + """Return the radio's memory map object""" return self._mmap
- def get_memsize(self): - return self._memsize - - @classmethod - def match_model(cls, filedata, filename): - """Given contents of a stored file (@filedata), return True if - this radio driver handles the represented model""" - - # Unless the radio driver does something smarter, claim - # support if the data is the same size as our memory. - # Ideally, each radio would perform an intelligent analysis to - # make this determination to avoid model conflicts with - # memories of the same size. - return len(filedata) == cls._memsize
class CloneModeRadio(FileBackedRadio): @@ -997,7 +1027,23 @@ self._mmap = pipe self.process_mmap() else: - Radio.__init__(self, pipe) + FileBackedRadio.__init__(self, pipe) + + def get_memsize(self): + """Return the radio's memory size""" + return self._memsize + + @classmethod + def match_model(cls, filedata, filename): + """Given contents of a stored file (@filedata), return True if + this radio driver handles the represented model""" + + # Unless the radio driver does something smarter, claim + # support if the data is the same size as our memory. + # Ideally, each radio would perform an intelligent analysis to + # make this determination to avoid model conflicts with + # memories of the same size. + return len(filedata) == cls._memsize
def sync_in(self): "Initiate a radio-to-PC clone operation" @@ -1008,36 +1054,47 @@ pass
class LiveRadio(Radio): + """Base class for all Live-Mode radios""" pass
class NetworkSourceRadio(Radio): + """Base class for all radios based on a network source""" def do_fetch(self): + """Fetch the source data from the network""" pass
class IcomDstarSupport: + """Base interface for radios supporting Icom's D-STAR technology""" MYCALL_LIMIT = (1, 1) URCALL_LIMIT = (1, 1) RPTCALL_LIMIT = (1, 1)
def get_urcall_list(self): + """Return a list of URCALL callsigns""" return []
def get_repeater_call_list(self): + """Return a list of RPTCALL callsigns""" return []
def get_mycall_list(self): + """Return a list of MYCALL callsigns""" return []
def set_urcall_list(self, calls): + """Set the URCALL callsign list""" pass
def set_repeater_call_list(self, calls): + """Set the RPTCALL callsign list""" pass
def set_mycall_list(self, calls): + """Set the MYCALL callsign list""" pass
class Status: + """Clone status object for conveying clone progress to the UI""" name = "Job" msg = "Unknown" max = 100 @@ -1055,21 +1112,27 @@ return "|%-10s| %2.1f%% %s" % (ticks, pct, self.msg)
def is_fractional_step(freq): + """Returns True if @freq requires a 12.5kHz or 6.25kHz step""" return not is_5_0(freq) and (is_12_5(freq) or is_6_25(freq))
def is_5_0(freq): + """Returns True if @freq is reachable by a 5kHz step""" return (freq % 5000) == 0
def is_12_5(freq): + """Returns True if @freq is reachable by a 12.5kHz step""" return (freq % 12500) == 0
def is_6_25(freq): + """Returns True if @freq is reachable by a 6.25kHz step""" return (freq % 6250) == 0
def is_2_5(freq): + """Returns True if @freq is reachable by a 2.5kHz step""" return (freq % 2500) == 0
def required_step(freq): + """Returns the simplest tuning step that is required to reach @freq""" if is_5_0(freq): return 5.0 elif is_12_5(freq): @@ -1080,10 +1143,13 @@ return 2.5 else: raise errors.InvalidDataError("Unable to calculate the required " + - "tuning step for %i.%5i" % (freq / 1000000, - freq % 1000000)) + "tuning step for %i.%5i" % \ + (freq / 1000000, + freq % 1000000))
def fix_rounded_step(freq): + """Some radios imply the last bit of 12.5kHz and 6.25kHz step + frequencies. Take the base @freq and return the corrected one""" try: required_step(freq) return freq @@ -1112,57 +1178,43 @@ format_freq(freq))
def _name(name, len, just_upper): + """Justify @name to @len, optionally converting to all uppercase""" if just_upper: name = name.upper() return name.ljust(len)[:len]
def name6(name, just_upper=True): + """6-char name""" return _name(name, 6, just_upper)
def name8(name, just_upper=False): + """8-char name""" return _name(name, 8, just_upper)
def name16(name, just_upper=False): + """16-char name""" return _name(name, 16, just_upper)
-class KillableThread(threading.Thread): - def __tid(self): - if not self.isAlive(): - raise threading.ThreadError("Not running") - - for tid, thread in threading._active.items(): - if thread == self: - return tid - - raise threading.ThreadError("I don't know my own TID") - - def kill(self, exception): - import ctypes - import inspect - - if not inspect.isclass(exception): - raise Exception("Parameter is not an Exception") - - ctype = ctypes.py_object(exception) - ret = ctypes.pythonapi.PyThreadState_SetAsyncExc(self.__tid(), ctype) - if ret != 1: - ctypes.pythonapi.PyThreadState_SetAsyncExc(self.__tid(), 0) - raise Exception("Failed to signal thread!") - def to_GHz(val): + """Convert @val in GHz to Hz""" return val * 1000000000
def to_MHz(val): + """Convert @val in MHz to Hz""" return val * 1000000
def to_kHz(val): + """Convert @val in kHz to Hz""" return val * 1000
def from_GHz(val): + """Convert @val in Hz to GHz""" return val / 100000000
def from_MHz(val): + """Convert @val in Hz to MHz""" return val / 100000
def from_kHz(val): + """Convert @val in Hz to kHz""" return val / 100 diff -r db82df47f205 -r f805c420592f chirp/detect.py --- a/chirp/detect.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/detect.py Fri Apr 27 14:35:41 2012 -0700 @@ -15,16 +15,16 @@
import serial
-from chirp import chirp_common, errors, idrp, util, icf, directory, ic9x_ll -from chirp import kenwood_live, tmv71, tmv71_ll, icomciv, thd72 +from chirp import errors, icf, directory, ic9x_ll +from chirp import kenwood_live, icomciv
def _icom_model_data_to_rclass(md): - for rtype, rclass in directory.DRV_TO_RADIO.items(): + for _rtype, rclass in directory.DRV_TO_RADIO.items(): if rclass.VENDOR != "Icom": continue - if not rclass._model: + if not rclass.get_model(): continue - if rclass._model[:4] == md[:4]: + if rclass.get_model()[:4] == md[:4]: return rclass
raise errors.RadioError("Unknown radio type %02x%02x%02x%02x" %\ @@ -33,22 +33,21 @@ ord(md[2]), ord(md[3])))
-def _detect_icom_radio(s): +def _detect_icom_radio(ser): # ICOM VHF/UHF Clone-type radios @ 9600 baud
try: - s.setBaudrate(9600) - md = icf.get_model_data(s) + ser.setBaudrate(9600) + md = icf.get_model_data(ser) return _icom_model_data_to_rclass(md) except errors.RadioError, e: print e - pass
# ICOM IC-91/92 Live-mode radios @ 4800/38400 baud
- s.setBaudrate(4800) + ser.setBaudrate(4800) try: - ic9x_ll.send_magic(s) + ic9x_ll.send_magic(ser) return _icom_model_data_to_rclass("ic9x") except errors.RadioError: pass @@ -57,25 +56,26 @@
for rate in [9600, 4800, 19200]: try: - s.setBaudrate(rate) - return icomciv.probe_model(s) + ser.setBaudrate(rate) + return icomciv.probe_model(ser) except errors.RadioError: pass
- s.close() + ser.close()
raise errors.RadioError("Unable to get radio model")
def detect_icom_radio(port): - s = serial.Serial(port=port, timeout=0.5) + """Detect which Icom model is connected to @port""" + ser = serial.Serial(port=port, timeout=0.5)
try: - result = _detect_icom_radio(s) + result = _detect_icom_radio(ser) except Exception: - s.close() + ser.close() raise
- s.close() + ser.close()
print "Auto-detected %s %s on %s" % (result.VENDOR, result.MODEL, @@ -84,9 +84,10 @@ return result
def detect_kenwoodlive_radio(port): - s = serial.Serial(port=port, baudrate=9600, timeout=0.5) - r_id = kenwood_live.get_id(s) - s.close() + """Detect which Kenwood model is connected to @port""" + ser = serial.Serial(port=port, baudrate=9600, timeout=0.5) + r_id = kenwood_live.get_id(ser) + ser.close()
models = {} for rclass in directory.DRV_TO_RADIO.values(): @@ -102,8 +103,3 @@ "Icom" : detect_icom_radio, "Kenwood" : detect_kenwoodlive_radio, } - -if __name__ == "__main__": - import sys - - print "Found %s" % detect_radio(sys.argv[1]) diff -r db82df47f205 -r f805c420592f chirp/directory.py --- a/chirp/directory.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/directory.py Fri Apr 27 14:35:41 2012 -0700 @@ -21,6 +21,7 @@ from chirp import chirp_common, util, rfinder, radioreference, errors
def radio_class_id(cls): + """Return a unique identification string for @cls""" ident = "%s_%s" % (cls.VENDOR, cls.MODEL) if cls.VARIANT: ident += "_%s" % cls.VARIANT @@ -31,6 +32,7 @@ return ident
def register(cls): + """Register radio @cls with the directory""" global DRV_TO_RADIO ident = radio_class_id(cls) if ident in DRV_TO_RADIO.keys(): @@ -45,20 +47,24 @@ RADIO_TO_DRV = {}
def get_radio(driver): + """Get radio driver class by identification string""" if DRV_TO_RADIO.has_key(driver): return DRV_TO_RADIO[driver] else: raise Exception("Unknown radio type `%s'" % driver)
-def get_driver(radio): - if RADIO_TO_DRV.has_key(radio): - return RADIO_TO_DRV[radio] - elif RADIO_TO_DRV.has_key(radio.__bases__[0]): - return RADIO_TO_DRV[radio.__bases__[0]] +def get_driver(rclass): + """Get the identification string for a given class""" + if RADIO_TO_DRV.has_key(rclass): + return RADIO_TO_DRV[rclass] + elif RADIO_TO_DRV.has_key(rclass.__bases__[0]): + return RADIO_TO_DRV[rclass.__bases__[0]] else: - raise Exception("Unknown radio type `%s'" % radio) + raise Exception("Unknown radio type `%s'" % rclass)
def icf_to_image(icf_file, img_file): + # FIXME: Why is this here? + """Convert an ICF file to a .img file""" mdata, mmap = icf.read_file(icf_file) img_data = None
@@ -80,16 +86,17 @@ raise Exception("Unsupported model")
def get_radio_by_image(image_file): + """Attempt to get the radio class that owns @image_file""" if image_file.startswith("radioreference://"): - method, _, zipcode, username, password = image_file.split("/", 4) + _, _, zipcode, username, password = image_file.split("/", 4) rr = radioreference.RadioReferenceRadio(None) rr.set_params(zipcode, username, password) return rr
if image_file.startswith("rfinder://"): - method, _, email, passwd, lat, lon, miles = image_file.split("/") + _, _, email, passwd, lat, lon, miles = image_file.split("/") rf = rfinder.RFinderRadio(None) - rf.set_params(float(lat), float(lon), int(miles), email, passwd) + rf.set_params((float(lat), float(lon)), int(miles), email, passwd) return rf
if os.path.exists(image_file) and icf.is_icf_file(image_file): @@ -105,27 +112,9 @@ else: filedata = ""
- for radio in DRV_TO_RADIO.values(): - if not issubclass(radio, chirp_common.FileBackedRadio): + for rclass in DRV_TO_RADIO.values(): + if not issubclass(rclass, chirp_common.FileBackedRadio): continue - if radio.match_model(filedata, image_file): - return radio(image_file) + if rclass.match_model(filedata, image_file): + return rclass(image_file) raise errors.ImageDetectFailed("Unknown file format") - -def get_radio_name(driver): - cls = DRV_TO_RADIO[driver] - return cls._get_name(cls) - -if __name__ == "__main__": - vendors = { - "Icom" : {}, - "Yaesu" : {}, - "Kenwood" : {}, - } - - for radio in DRV_TO_RADIO.values(): - vendors[radio.VENDOR][radio.MODEL] - print "%s %s:" % (radio.VENDOR, radio.MODEL) - if radio.VARIANT: - print " Variant: %s" % radio.VARIANT - print " Baudrate: %i" % radio.BAUD_RATE diff -r db82df47f205 -r f805c420592f chirp/errors.py --- a/chirp/errors.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/errors.py Fri Apr 27 14:35:41 2012 -0700 @@ -14,19 +14,25 @@ # along with this program. If not, see http://www.gnu.org/licenses/.
class InvalidDataError(Exception): + """The radio driver encountered some invalid data""" pass
class InvalidValueError(Exception): + """An invalid value for a given parameter was used""" pass
class InvalidMemoryLocation(Exception): + """The requested memory location does not exist""" pass
class RadioError(Exception): + """An error occurred while talking to the radio""" pass
class UnsupportedToneError(Exception): + """The radio does not support the specified tone value""" pass
class ImageDetectFailed(Exception): + """The driver for the supplied image could not be determined""" pass diff -r db82df47f205 -r f805c420592f chirp/ft2800.py --- a/chirp/ft2800.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/ft2800.py Fri Apr 27 14:35:41 2012 -0700 @@ -14,7 +14,6 @@ # along with this program. If not, see http://www.gnu.org/licenses/.
import time -import struct import os
from chirp import util, memmap, chirp_common, bitwise, directory, errors @@ -23,7 +22,7 @@ DEBUG = os.getenv("CHIRP_DEBUG") and True or False
CHUNK_SIZE = 16 -def send(s, data): +def _send(s, data): for i in range(0, len(data), CHUNK_SIZE): chunk = data[i:i+CHUNK_SIZE] s.write(chunk) @@ -35,9 +34,9 @@ TRAILER = "\x0c\x02\x41\x33\x35\x00\x00\xb7" ACK = "\x0C\x06\x00"
-def download(radio): +def _download(radio): data = "" - for i in range(0, 10): + for _i in range(0, 10): data = radio.pipe.read(8) if data == IDBLOCK: break @@ -48,7 +47,7 @@ if len(data) != 8: raise Exception("Failed to read header")
- send(radio.pipe, ACK) + _send(radio.pipe, ACK)
data = ""
@@ -72,7 +71,7 @@
data += chunk[5:-1]
- send(radio.pipe, ACK) + _send(radio.pipe, ACK) if radio.status_fn: status = chirp_common.Status() status.max = radio._block_sizes[1] @@ -85,14 +84,14 @@
return memmap.MemoryMap(data)
-def upload(radio): - for i in range(0, 10): +def _upload(radio): + for _i in range(0, 10): data = radio.pipe.read(256) if not data: break print "What is this garbage?\n%s" % util.hexprint(data)
- send(radio.pipe, IDBLOCK) + _send(radio.pipe, IDBLOCK) time.sleep(1) ack = radio.pipe.read(300) if DEBUG: @@ -101,9 +100,9 @@ raise Exception("Radio did not ack ID")
block = 0 - while block < (radio._memsize / 32): + while block < (radio.get_memsize() / 32): data = "\x0C\x03\x00\x00" + chr(block) - data += radio._mmap[block*32:(block+1)*32] + data += radio.get_mmap()[block*32:(block+1)*32] cs = 0 for byte in data: cs += ord(byte) @@ -112,7 +111,7 @@ if DEBUG: print "Writing block %i:\n%s" % (block, util.hexprint(data))
- send(radio.pipe, data) + _send(radio.pipe, data) time.sleep(0.1) ack = radio.pipe.read(3) if ack != ACK: @@ -126,9 +125,9 @@ radio.status_fn(status) block += 1
- send(radio.pipe, TRAILER) + _send(radio.pipe, TRAILER)
-mem_format = """ +MEM_FORMAT = """ struct { bbcd freq[4]; u8 unknown1[4]; @@ -164,6 +163,7 @@
@directory.register class FT2800Radio(YaesuCloneModeRadio): + """Yaesu FT-2800""" VENDOR = "Yaesu" MODEL = "FT-2800M"
@@ -196,7 +196,7 @@ self.pipe.setParity("E") start = time.time() try: - self._mmap = download(self) + self._mmap = _download(self) except errors.RadioError: raise except Exception, e: @@ -209,7 +209,7 @@ self.pipe.setParity("E") start = time.time() try: - upload(self) + _upload(self) except errors.RadioError: raise except Exception, e: @@ -217,7 +217,7 @@ print "Uploaded in %.2f sec" % (time.time() - start)
def process_mmap(self): - self._memobj = bitwise.parse(mem_format, self._mmap) + self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
def get_raw_memory(self, number): return repr(self._memobj.memory[number]) diff -r db82df47f205 -r f805c420592f chirp/ft60.py --- a/chirp/ft60.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/ft60.py Fri Apr 27 14:35:41 2012 -0700 @@ -19,13 +19,13 @@
ACK = "\x06"
-def send(pipe, data): +def _send(pipe, data): pipe.write(data) echo = pipe.read(len(data)) if echo != data: raise errors.RadioError("Error reading echo (Bad cable?)")
-def download(radio): +def _download(radio): data = "" for i in range(0, 10): chunk = radio.pipe.read(8) @@ -40,12 +40,12 @@ if not data: raise Exception("Radio is not responding")
- send(radio.pipe, ACK) + _send(radio.pipe, ACK)
for i in range(0, 448): chunk = radio.pipe.read(64) data += chunk - send(radio.pipe, ACK) + _send(radio.pipe, ACK) if len(chunk) == 1 and i == 447: break elif len(chunk) != 64: @@ -53,14 +53,14 @@ if radio.status_fn: status = chirp_common.Status() status.cur = i * 64 - status.max = radio._memsize + status.max = radio.get_memsize() status.msg = "Cloning from radio" radio.status_fn(status)
return memmap.MemoryMap(data)
-def upload(radio): - send(radio.pipe, radio._mmap[0:8]) +def _upload(radio): + _send(radio.pipe, radio.get_mmap()[0:8])
ack = radio.pipe.read(1) if ack != ACK: @@ -68,7 +68,7 @@
for i in range(0, 448): offset = 8 + (i * 64) - send(radio.pipe, radio._mmap[offset:offset+64]) + _send(radio.pipe, radio.get_mmap()[offset:offset+64]) ack = radio.pipe.read(1) if ack != ACK: raise Exception("Radio did not ack block %i" % i) @@ -76,11 +76,11 @@ if radio.status_fn: status = chirp_common.Status() status.cur = offset+64 - status.max = radio._memsize + status.max = radio.get_memsize() status.msg = "Cloning to radio" radio.status_fn(status)
-mem_format = """ +MEM_FORMAT = """ #seekto 0x0238; struct { u8 used:1, @@ -136,6 +136,7 @@
@directory.register class FT60Radio(yaesu_clone.YaesuCloneModeRadio): + """Yaesu FT-60""" BAUD_RATE = 9600 VENDOR = "Yaesu" MODEL = "FT-60" @@ -158,6 +159,7 @@ rf.has_ctone = False rf.has_bank = False rf.has_dtcs_polarity = False + return rf
def _checksums(self): @@ -165,7 +167,7 @@
def sync_in(self): try: - self._mmap = download(self) + self._mmap = _download(self) except errors.RadioError: raise except Exception, e: @@ -175,14 +177,14 @@ def sync_out(self): self.update_checksums() try: - upload(self) + _upload(self) except errors.RadioError: raise except Exception, e: raise errors.RadioError("Failed to communicate with radio: %s" % e)
def process_mmap(self): - self._memobj = bitwise.parse(mem_format, self._mmap) + self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
def get_raw_memory(self, number): return repr(self._memobj.memory[number]) + \ diff -r db82df47f205 -r f805c420592f chirp/ft7800.py --- a/chirp/ft7800.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/ft7800.py Fri Apr 27 14:35:41 2012 -0700 @@ -15,11 +15,11 @@
import time from chirp import chirp_common, yaesu_clone, memmap, directory -from chirp import bitwise, util, errors +from chirp import bitwise, errors
ACK = chr(0x06)
-mem_format = """ +MEM_FORMAT = """ #seekto 0x04C8; struct { u8 used:1, @@ -89,16 +89,15 @@ chirp_common.PowerLevel("Mid2", watts=10), chirp_common.PowerLevel("Low", watts=5)]
-def send(s, data): - +def _send(ser, data): for i in data: - s.write(i) + ser.write(i) time.sleep(0.002) - echo = s.read(len(data)) + echo = ser.read(len(data)) if echo != data: raise errors.RadioError("Error reading echo (Bad cable?)")
-def download(radio): +def _download(radio): data = ""
chunk = "" @@ -111,49 +110,49 @@ raise Exception("Failed to read header (%i)" % len(chunk)) data += chunk
- send(radio.pipe, ACK) + _send(radio.pipe, ACK)
for i in range(0, radio._block_lengths[1], 64): chunk = radio.pipe.read(64) data += chunk if len(chunk) != 64: break - raise Exception("No block at %i" % i) time.sleep(0.01) - send(radio.pipe, ACK) + _send(radio.pipe, ACK) if radio.status_fn: status = chirp_common.Status() - status.max = radio._memsize + status.max = radio.get_memsize() status.cur = i+len(chunk) status.msg = "Cloning from radio" radio.status_fn(status)
data += radio.pipe.read(1) - send(radio.pipe, ACK) + _send(radio.pipe, ACK)
return memmap.MemoryMap(data)
-def upload(radio): +def _upload(radio): cur = 0 for block in radio._block_lengths: - for i in range(0, block, 64): + for _i in range(0, block, 64): length = min(64, block) #print "i=%i length=%i range: %i-%i" % (i, length, # cur, cur+length) - send(radio.pipe, radio._mmap[cur:cur+length]) + _send(radio.pipe, radio.get_mmap()[cur:cur+length]) if radio.pipe.read(1) != ACK: raise errors.RadioError("Radio did not ack block at %i" % cur) cur += length time.sleep(0.05)
if radio.status_fn: - s = chirp_common.Status() - s.cur = cur - s.max = radio._memsize - s.msg = "Cloning to radio" - radio.status_fn(s) + status = chirp_common.Status() + status.cur = cur + status.max = radio.get_memsize() + status.msg = "Cloning to radio" + radio.status_fn(status)
def get_freq(rawfreq): + """Decode a frequency that may include a fractional step flag""" # Ugh. The 0x80 and 0x40 indicate values to add to get the # real frequency. Gross. if rawfreq > 8000000000: @@ -165,6 +164,7 @@ return rawfreq
def set_freq(freq, obj, field): + """Encode a frequency with any necessary fractional step flags""" obj[field] = freq / 10000 if (freq % 1000) == 500: obj[field][0].set_bits(0x40) @@ -175,6 +175,7 @@ return freq
class FTx800Radio(yaesu_clone.YaesuCloneModeRadio): + """Base class for FT-7800,7900,8800,8900 radios""" BAUD_RATE = 9600 VENDOR = "Yaesu"
@@ -200,30 +201,30 @@ return [ yaesu_clone.YaesuChecksum(0x0000, 0x7B47) ]
def sync_in(self): - t = time.time() + start = time.time() try: - self._mmap = download(self) + self._mmap = _download(self) except errors.RadioError: raise except Exception, e: raise errors.RadioError("Failed to communicate with radio: %s" % e) - print "Download finished in %i seconds" % (time.time() - t) + print "Download finished in %i seconds" % (time.time() - start) self.check_checksums() self.process_mmap()
def process_mmap(self): - self._memobj = bitwise.parse(mem_format, self._mmap) + self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
def sync_out(self): self.update_checksums() - t = time.time() + start = time.time() try: - upload(self) + _upload(self) except errors.RadioError: raise except Exception, e: raise errors.RadioError("Failed to communicate with radio: %s" % e) - print "Upload finished in %i seconds" % (time.time() - t) + print "Upload finished in %i seconds" % (time.time() - start)
def get_raw_memory(self, number): return repr(self._memobj.memory[number-1]) @@ -330,6 +331,7 @@ self._set_mem_skip(mem, _mem)
class FT7800BankModel(chirp_common.BankModel): + """Yaesu FT-7800/7900 bank model""" def get_num_banks(self): return 20
@@ -353,8 +355,8 @@ _bitmap = self._radio._memobj.bank_channels[bank.index] ishft = 31 - (index % 32) if not (_bitmap.bitmap[index / 32] & (1 << ishft)): - raise Exception(_("Memory {num} is " - "not in bank {bank}").format(num=memory.number, + raise Exception("Memory {num} is " + + "not in bank {bank}".format(num=memory.number, bank=bank)) _bitmap.bitmap[index / 32] &= ~(1 << ishft)
@@ -377,6 +379,7 @@
@directory.register class FT7800Radio(FTx800Radio): + """Yaesu FT-7800""" MODEL = "FT-7800"
_model = "AH016" @@ -396,9 +399,10 @@ FTx800Radio.set_memory(self, memory)
class FT7900Radio(FT7800Radio): + """Yaesu FT-7900""" MODEL = "FT-7900"
-mem_format_8800 = """ +MEM_FORMAT_8800 = """ #seekto %s; struct { u8 used:1, @@ -434,6 +438,7 @@
@directory.register class FT8800Radio(FTx800Radio): + """Base class for Yaesu FT-8800""" MODEL = "FT-8800"
_model = "AH018" @@ -460,7 +465,7 @@ if not self._memstart: return
- self._memobj = bitwise.parse(mem_format_8800 % self._memstart, + self._memobj = bitwise.parse(MEM_FORMAT_8800 % self._memstart, self._mmap)
def _get_mem_offset(self, mem, _mem): @@ -502,14 +507,16 @@ _mem.nameused = bool(mem.name.rstrip())
class FT8800RadioLeft(FT8800Radio): + """Yaesu FT-8800 Left VFO subdevice""" VARIANT = "Left" _memstart = "0x0948"
class FT8800RadioRight(FT8800Radio): + """Yaesu FT-8800 Right VFO subdevice""" VARIANT = "Right" _memstart = "0x2948"
-mem_format_8900 = """ +MEM_FORMAT_8900 = """ #seekto 0x0708; struct { u8 used:1, @@ -546,6 +553,7 @@
@directory.register class FT8900Radio(FT8800Radio): + """Yaesu FT-8900""" MODEL = "FT-8900"
_model = "AH008" @@ -553,7 +561,7 @@ _block_lengths = [8, 14784, 1]
def process_mmap(self): - self._memobj = bitwise.parse(mem_format_8900, self._mmap) + self._memobj = bitwise.parse(MEM_FORMAT_8900, self._mmap)
def get_features(self): rf = FT8800Radio.get_features(self) @@ -595,7 +603,7 @@ # the memory should show up on the sub (right) band _mem = self._memobj.memory[mem.number - 1] if mem.freq < 108000000 or mem.freq > 480000000: - _mem.sub_used = 0; + _mem.sub_used = 0 else: _mem.sub_used = 1
diff -r db82df47f205 -r f805c420592f chirp/ft817.py --- a/chirp/ft817.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/ft817.py Fri Apr 27 14:35:41 2012 -0700 @@ -20,26 +20,29 @@
CMD_ACK = 0x06
-def ft817_read(pipe, block, blocknum): - for i in range(0,60): +def _ft8x7_read(pipe, block, blocknum): + for _i in range(0, 60): data = pipe.read(block+2) - if data: + if data: break - time.sleep(0.5) + time.sleep(0.5) if len(data) == block+2 and data[0] == chr(blocknum): - checksum = yaesu_clone.YaesuChecksum(1, block) - if checksum.get_existing(data) != \ - checksum.get_calculated(data): - raise Exception("Checksum Failed [%02X<>%02X] block %02X" % (checksum.get_existing(data), checksum.get_calculated(data), blocknum)) - data = data[1:block+1] # Chew away the block number and the checksum + checksum = yaesu_clone.YaesuChecksum(1, block) + if checksum.get_existing(data) != \ + checksum.get_calculated(data): + raise Exception("Checksum Failed [%02X<>%02X] block %02X" % \ + (checksum.get_existing(data), + checksum.get_calculated(data), blocknum)) + data = data[1:block+1] # Chew away the block number and the checksum else: - raise Exception("Unable to read block %02X expected %i got %i" % (blocknum, block+2, len(data))) + raise Exception("Unable to read block %02X expected %i got %i" % \ + (blocknum, block+2, len(data)))
if os.getenv("CHIRP_DEBUG"): print "Read %i" % len(data) return data
-def clone_in(radio): +def _ft8x7_clone_in(radio): pipe = radio.pipe
# Be very patient with the radio @@ -54,21 +57,21 @@ status.max = len(radio._block_lengths) + 39 for block in radio._block_lengths: if blocks == 8: - repeat = 40 # repeated read of 40 block same size (memory area btw) + repeat = 40 # repeated read of 40 block same size (memory area) else: repeat = 1 - for i in range(0, repeat): - data += ft817_read(pipe, block, blocks) - pipe.write(chr(CMD_ACK)) - blocks += 1 - status.cur = blocks - radio.status_fn(status) + for _i in range(0, repeat): + data += _ft8x7_read(pipe, block, blocks) + pipe.write(chr(CMD_ACK)) + blocks += 1 + status.cur = blocks + radio.status_fn(status)
print "Clone completed in %i seconds" % (time.time() - start)
return memmap.MemoryMap(data)
-def clone_out(radio): +def _ft8x7_clone_out(radio): delay = 0.5 pipe = radio.pipe
@@ -81,21 +84,24 @@ status.max = len(radio._block_lengths) + 39 for block in radio._block_lengths: if blocks == 8: - repeat = 40 # repeated read of 40 block same size (memory area btw) + repeat = 40 # repeated read of 40 block same size (memory area) else: repeat = 1 - for i in range(0, repeat): + for _i in range(0, repeat): time.sleep(0.01) checksum = yaesu_clone.YaesuChecksum(pos, pos+block-1) if os.getenv("CHIRP_DEBUG"): - print "Block %i - will send from %i to %i byte " % (blocks, pos, pos+block) + print "Block %i - will send from %i to %i byte " % (blocks, + pos, + pos+block) print util.hexprint(chr(blocks)) - print util.hexprint(radio._mmap[pos:pos+block]) - print util.hexprint(chr(checksum.get_calculated(radio._mmap))) + print util.hexprint(radio.get_mmap()[pos:pos+block]) + print util.hexprint(chr(checksum.get_calculated(\ + radio.get_mmap()))) pipe.write(chr(blocks)) - pipe.write(radio._mmap[pos:pos+block]) - pipe.write(chr(checksum.get_calculated(radio._mmap))) - buf = pipe.read(1) + pipe.write(radio.get_mmap()[pos:pos+block]) + pipe.write(chr(checksum.get_calculated(radio.get_mmap()))) + buf = pipe.read(1) if not buf or buf[0] != chr(CMD_ACK): time.sleep(delay) buf = pipe.read(1) @@ -105,12 +111,12 @@ raise Exception("Radio did not ack block %i" % blocks) pos += block blocks += 1 - status.cur = blocks - radio.status_fn(status) + status.cur = blocks + radio.status_fn(status)
print "Clone completed in %i seconds" % (time.time() - start)
-mem_format = """ +MEM_FORMAT = """ struct mem_struct { u8 tag_on_off:1, tag_default:1, @@ -167,21 +173,29 @@
@directory.register class FT817Radio(yaesu_clone.YaesuCloneModeRadio): + """Yaesu FT-817""" BAUD_RATE = 9600 MODEL = "FT-817" _model = ""
DUPLEX = ["", "-", "+", "split"] - MODES = ["LSB", "USB", "CW", "CWR", "AM", "FM", "DIG", "PKT", "NCW", "NCWR", "NFM"] # narrow modes has to be at end + # narrow modes has to be at end + MODES = ["LSB", "USB", "CW", "CWR", "AM", "FM", "DIG", "PKT", "NCW", + "NCWR", "NFM"] TMODES = ["", "Tone", "TSQL", "DTCS"] STEPSFM = [5.0, 6.25, 10.0, 12.5, 15.0, 20.0, 25.0, 50.0] STEPSAM = [2.5, 5.0, 9.0, 10.0, 12.5, 25.0] STEPSSSB = [1.0, 2.5, 5.0] - VALID_BANDS = [(100000,33000000), (33000000,56000000), (76000000,108000000), (108000000,137000000), (137000000,154000000), (420000000,470000000)] # warning ranges has to be in this exact order + + # warning ranges has to be in this exact order + VALID_BANDS = [(100000, 33000000), (33000000, 56000000), + (76000000, 108000000), (108000000, 137000000), + (137000000, 154000000), (420000000, 470000000)]
CHARSET = [chr(x) for x in range(0, 256)]
- POWER_LEVELS = [chirp_common.PowerLevel("Hi", watts=5.00), # not used in memory + # Hi not used in memory + POWER_LEVELS = [chirp_common.PowerLevel("Hi", watts=5.00), chirp_common.PowerLevel("L3", watts=2.50), chirp_common.PowerLevel("L2", watts=1.00), chirp_common.PowerLevel("L1", watts=0.5)] @@ -190,7 +204,8 @@ # block 9 (130 Bytes long) is to be repeted 40 times _block_lengths = [ 2, 40, 208, 182, 208, 182, 198, 53, 130, 118, 118]
- SPECIAL_MEMORIES = { # WARNING Index are hard wired in memory management code !!! + # WARNING Index are hard wired in memory management code !!! + SPECIAL_MEMORIES = { "VFOa-1.8M" : -35, "VFOa-3.5M" : -34, "VFOa-7M" : -33, @@ -232,11 +247,12 @@ FIRST_VFOA_INDEX = -21 LAST_VFOA_INDEX = -35
- SPECIAL_MEMORIES_REV = dict(zip(SPECIAL_MEMORIES.values(), SPECIAL_MEMORIES.keys())) + SPECIAL_MEMORIES_REV = dict(zip(SPECIAL_MEMORIES.values(), + SPECIAL_MEMORIES.keys()))
def sync_in(self): try: - self._mmap = clone_in(self) + self._mmap = _ft8x7_clone_in(self) except errors.RadioError: raise except Exception, e: @@ -245,14 +261,14 @@
def sync_out(self): try: - clone_out(self) + _ft8x7_clone_out(self) except errors.RadioError: raise except Exception, e: raise errors.RadioError("Failed to communicate with radio: %s" % e)
def process_mmap(self): - self._memobj = bitwise.parse(mem_format, self._mmap) + self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
def get_features(self): rf = chirp_common.RadioFeatures() @@ -276,27 +292,28 @@ def get_raw_memory(self, number): return repr(self._memobj.memory[number-1])
- def get_duplex(self, mem, _mem): + def _get_duplex(self, mem, _mem): if _mem.is_duplex == 1: mem.duplex = self.DUPLEX[_mem.duplex] else: mem.duplex = ""
- def get_tmode(self, mem, _mem): + def _get_tmode(self, mem, _mem): mem.tmode = self.TMODES[_mem.tmode]
- def set_duplex(self, mem, _mem): + def _set_duplex(self, mem, _mem): _mem.duplex = self.DUPLEX.index(mem.duplex) _mem.is_duplex = mem.duplex != ""
- def set_tmode(self, mem, _mem): + def _set_tmode(self, mem, _mem): _mem.tmode = self.TMODES.index(mem.tmode)
def get_memory(self, number): if isinstance(number, str): return self._get_special(number) elif number < 0: - # I can't stop delete operation from loosing extd_number but I know how to get it back + # I can't stop delete operation from loosing extd_number but + # I know how to get it back return self._get_special(self.SPECIAL_MEMORIES_REV[number]) else: return self._get_normal(number) @@ -315,27 +332,32 @@ mem.number = self.SPECIAL_MEMORIES[number] mem.extd_number = number
- if mem.number in range(self.FIRST_VFOA_INDEX, self.LAST_VFOA_INDEX -1, -1): + if mem.number in range(self.FIRST_VFOA_INDEX, + self.LAST_VFOA_INDEX - 1, + -1): _mem = self._memobj.vfoa[-self.LAST_VFOA_INDEX + mem.number] - immutable = ["number", "skip", "rtone", "ctone", "extd_number", "name", - "dtcs_polarity", "power", "comment"] - elif mem.number in range(self.FIRST_VFOB_INDEX, self.LAST_VFOB_INDEX -1, -1): + immutable = ["number", "skip", "rtone", "ctone", "extd_number", + "name", "dtcs_polarity", "power", "comment"] + elif mem.number in range(self.FIRST_VFOB_INDEX, + self.LAST_VFOB_INDEX - 1, + -1): _mem = self._memobj.vfob[-self.LAST_VFOB_INDEX + mem.number] - immutable = ["number", "skip", "rtone", "ctone", "extd_number", "name", - "dtcs_polarity", "power", "comment"] + immutable = ["number", "skip", "rtone", "ctone", "extd_number", + "name", "dtcs_polarity", "power", "comment"] elif mem.number in range(-2, -6, -1): _mem = self._memobj.home[5 + mem.number] immutable = ["number", "skip", "rtone", "ctone", "extd_number", "dtcs_polarity", "power", "comment"] elif mem.number == -1: _mem = self._memobj.qmb - immutable = ["number", "skip", "rtone", "ctone", "extd_number", "name", - "dtcs_polarity", "power", "comment"] - else: - raise Exception("Sorry, special memory index %i unknown you hit a bug!!" % mem.number) + immutable = ["number", "skip", "rtone", "ctone", "extd_number", + "name", "dtcs_polarity", "power", "comment"] + else: + raise Exception("Sorry, special memory index %i " % mem.number + + "unknown you hit a bug!!")
mem = self._get_memory(mem, _mem) - mem.immutable = immutable + mem.immutable = immutable
return mem
@@ -352,16 +374,21 @@ "is not supported on this channel")
# TODO add frequency range check for vfo and home memories - if mem.number in range(self.FIRST_VFOA_INDEX, self.LAST_VFOA_INDEX -1, -1): + if mem.number in range(self.FIRST_VFOA_INDEX, + self.LAST_VFOA_INDEX -1, + -1): _mem = self._memobj.vfoa[-self.LAST_VFOA_INDEX + mem.number] - elif mem.number in range(self.FIRST_VFOB_INDEX, self.LAST_VFOB_INDEX -1, -1): + elif mem.number in range(self.FIRST_VFOB_INDEX, + self.LAST_VFOB_INDEX -1, + -1): _mem = self._memobj.vfob[-self.LAST_VFOB_INDEX + mem.number] elif mem.number in range(-2, -6, -1): _mem = self._memobj.home[5 + mem.number] elif mem.number == -1: _mem = self._memobj.qmb - else: - raise Exception("Sorry, special memory index %i unknown you hit a bug!!" % mem.number) + else: + raise Exception("Sorry, special memory index %i " % mem.number + + "unknown you hit a bug!!")
self._set_memory(mem, _mem)
@@ -382,8 +409,10 @@
def _set_normal(self, mem): _mem = self._memobj.memory[mem.number-1] - wasused = (self._memobj.visible[(mem.number-1)/8] >> (mem.number-1)%8) & 0x01 - wasvalid = (self._memobj.filled[(mem.number-1)/8] >> (mem.number-1)%8) & 0x01 + wasused = (self._memobj.visible[(mem.number - 1) / 8] >> \ + (mem.number - 1) % 8) & 0x01 + wasvalid = (self._memobj.filled[(mem.number - 1) / 8] >> \ + (mem.number - 1) % 8) & 0x01
if mem.empty: if mem.number == 1: @@ -391,18 +420,20 @@ # if you ulpoad an empty image you can brick your radio raise Exception("Sorry, can't delete first memory") if wasvalid and not wasused: - self._memobj.filled[(mem.number-1)/8] &= ~ (1 << (mem.number-1)%8) - self._memobj.visible[(mem.number-1)/8] &= ~ (1 << (mem.number-1)%8) + self._memobj.filled[(mem.number-1) / 8] &= \ + ~(1 << (mem.number - 1) % 8) + self._memobj.visible[(mem.number-1) / 8] &= \ + ~(1 << (mem.number - 1) % 8) return
- self._memobj.visible[(mem.number-1)/8] |= 1 << (mem.number-1)%8 - self._memobj.filled[(mem.number-1)/8] |= 1 << (mem.number-1)%8 + self._memobj.visible[(mem.number - 1) / 8] |= 1 << (mem.number - 1) % 8 + self._memobj.filled[(mem.number - 1) / 8] |= 1 << (mem.number - 1) % 8 self._set_memory(mem, _mem)
def _get_memory(self, mem, _mem): mem.freq = int(_mem.freq) * 10 mem.offset = int(_mem.offset) * 10 - self.get_duplex(mem, _mem) + self._get_duplex(mem, _mem) mem.mode = self.MODES[_mem.mode] if mem.mode == "FM": if _mem.is_fm_narrow == 1: @@ -420,11 +451,11 @@ except IndexError: pass mem.skip = _mem.skip and "S" or "" - self.get_tmode(mem, _mem) + self._get_tmode(mem, _mem) mem.rtone = mem.ctone = chirp_common.TONES[_mem.tone] mem.dtcs = chirp_common.DTCS_CODES[_mem.dcs]
- if _mem.tag_on_off == 1: + if _mem.tag_on_off == 1: for i in _mem.name: if i == "\xFF": break @@ -442,31 +473,34 @@ else: _mem.tag_on_off = 0 _mem.tag_default = 0 # never use default label "CH-nnn" - self.set_duplex(mem, _mem) + self._set_duplex(mem, _mem) if mem.mode[0] == "N": # is it narrow? _mem.mode = self.MODES.index(mem.mode[1:]) - _mem.is_fm_narrow = _mem.is_cwdig_narrow = 1 # here I suppose it's safe to set both + # here I suppose it's safe to set both + _mem.is_fm_narrow = _mem.is_cwdig_narrow = 1 else: _mem.mode = self.MODES.index(mem.mode) - _mem.is_fm_narrow = _mem.is_cwdig_narrow = 0 # here I suppose it's safe to set both - i = 0 # This search can probably be written better but - for lo, hi in self.VALID_BANDS: # I just don't know python enought + # here I suppose it's safe to set both + _mem.is_fm_narrow = _mem.is_cwdig_narrow = 0 + i = 0 + for lo, hi in self.VALID_BANDS: if mem.freq > lo and mem.freq < hi: break - i+=1 + i += 1 _mem.freq_range = i - if mem.duplex == "split": # all this should be safe also when not in split but ... + # all this should be safe also when not in split but ... + if mem.duplex == "split": _mem.tx_mode = _mem.mode - i = 0 # This search can probably be written better but - for lo, hi in self.VALID_BANDS: # I just don't know python enought + i = 0 + for lo, hi in self.VALID_BANDS: if mem.offset >= lo and mem.offset < hi: break - i+=1 + i += 1 _mem.tx_freq_range = i _mem.skip = mem.skip == "S" _mem.ipo = 0 # not supported in chirp _mem.att = 0 # not supported in chirp - self.set_tmode(mem, _mem) + self._set_tmode(mem, _mem) try: _mem.ssb_step = self.STEPSSSB.index(mem.tuning_step) except ValueError: @@ -490,10 +524,11 @@ def validate_memory(self, mem): msgs = yaesu_clone.YaesuCloneModeRadio.validate_memory(self, mem)
- lo, hi = self.VALID_BANDS[2] # this is fm broadcasting - if mem.freq >= lo and mem.freq <= hi: + lo, hi = self.VALID_BANDS[2] # this is fm broadcasting + if mem.freq >= lo and mem.freq <= hi: if mem.mode != "FM": - msgs.append(chirp_common.ValidationError("Only FM is supported in this band")) + msgs.append(chirp_common.ValidationError(\ + "Only FM is supported in this band")) # TODO check that step is valid in current mode return msgs
@@ -503,6 +538,7 @@
@directory.register class FT817NDRadio(FT817Radio): + """Yaesu FT-817ND""" MODEL = "FT-817ND"
_model = "" @@ -512,8 +548,9 @@
@directory.register class FT817ND_US_Radio(FT817Radio): - # seems that radios configured for 5MHz operations send one paket more than others - # so we have to distinguish sub models + """Yaesu FT-817ND (US version)""" + # seems that radios configured for 5MHz operations send one paket + # more than others so we have to distinguish sub models MODEL = "FT-817ND (US)"
_model = "" @@ -533,14 +570,16 @@ SPECIAL_MEMORIES = dict(FT817Radio.SPECIAL_MEMORIES) SPECIAL_MEMORIES.update(SPECIAL_60M)
- SPECIAL_MEMORIES_REV = dict(zip(SPECIAL_MEMORIES.values(), SPECIAL_MEMORIES.keys())) + SPECIAL_MEMORIES_REV = dict(zip(SPECIAL_MEMORIES.values(), + SPECIAL_MEMORIES.keys()))
def _get_special_60M(self, number): mem = chirp_common.Memory() mem.number = self.SPECIAL_60M[number] mem.extd_number = number
- _mem = self._memobj.sixtymeterchannels[-self.LAST_SPECIAL60M_INDEX + mem.number] + _mem = self._memobj.sixtymeterchannels[-self.LAST_SPECIAL60M_INDEX + + mem.number]
mem = self._get_memory(mem, _mem)
@@ -564,16 +603,19 @@ "is not supported on M-60x channels")
if mem.mode not in ["USB", "LSB", "CW", "CWR", "NCW", "NCWR", "DIG"]: - raise errors.RadioError(_("Mode {mode} is not valid " - "in 60m channels").format(mode=mem.mode)) - _mem = self._memobj.sixtymeterchannels[-self.LAST_SPECIAL60M_INDEX + mem.number] + raise errors.RadioError("Mode {mode} is not valid " + "in 60m channels".format(mode=mem.mode)) + _mem = self._memobj.sixtymeterchannels[-self.LAST_SPECIAL60M_INDEX + + mem.number] self._set_memory(mem, _mem)
def get_memory(self, number): if number in self.SPECIAL_60M.keys(): return self._get_special_60M(number) - elif number < 0 and self.SPECIAL_MEMORIES_REV[number] in self.SPECIAL_60M.keys(): - # I can't stop delete operation from loosing extd_number but I know how to get it back + elif number < 0 and \ + self.SPECIAL_MEMORIES_REV[number] in self.SPECIAL_60M.keys(): + # I can't stop delete operation from loosing extd_number but + # I know how to get it back return self._get_special_60M(self.SPECIAL_MEMORIES_REV[number]) else: return FT817Radio.get_memory(self, number) diff -r db82df47f205 -r f805c420592f chirp/ft857.py --- a/chirp/ft857.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/ft857.py Fri Apr 27 14:35:41 2012 -0700 @@ -18,7 +18,7 @@ from chirp import bitwise import os
-mem_format = """ +MEM_FORMAT = """ struct mem_struct{ u8 tag_on_off:1, tag_default:1, @@ -84,6 +84,7 @@
@directory.register class FT857Radio(ft817.FT817Radio): + """Yaesu FT-857/897""" MODEL = "FT-857/897" _model = ""
@@ -121,10 +122,15 @@ _memsize = 7341 # block 9 (140 Bytes long) is to be repeted 40 times # should be 42 times but this way I can use original 817 functions - _block_lengths = [ 2, 82, 252, 196, 252, 196, 212, 55, 140, 140, 140, 38, 176] - VALID_BANDS = [(100000,33000000), (33000000,56000000), (76000000,108000000), (108000000,137000000), (137000000,164000000), (420000000,470000000)] # warning ranges has to be in this exact order + _block_lengths = [ 2, 82, 252, 196, 252, 196, 212, 55, 140, 140, 140, + 38, 176] + # warning ranges has to be in this exact order + VALID_BANDS = [(100000, 33000000), (33000000, 56000000), + (76000000, 108000000), (108000000, 137000000), + (137000000, 164000000), (420000000, 470000000)]
- SPECIAL_MEMORIES = { # WARNING Index are hard wired in memory management code !!! + # WARNING Index are hard wired in memory management code !!! + SPECIAL_MEMORIES = { "VFOa-1.8M" : -37, "VFOa-3.5M" : -36, "VFOa-5M" : -35, @@ -168,7 +174,8 @@ FIRST_VFOA_INDEX = -22 LAST_VFOA_INDEX = -37
- SPECIAL_PMS = { # WARNING Index are hard wired in memory management code !!! + # WARNING Index are hard wired in memory management code !!! + SPECIAL_PMS = { "PMS-1L" : -47, "PMS-1U" : -46, "PMS-2L" : -45, @@ -184,7 +191,8 @@ SPECIAL_MEMORIES = dict(SPECIAL_MEMORIES) SPECIAL_MEMORIES.update(SPECIAL_PMS)
- SPECIAL_MEMORIES_REV = dict(zip(SPECIAL_MEMORIES.values(), SPECIAL_MEMORIES.keys())) + SPECIAL_MEMORIES_REV = dict(zip(SPECIAL_MEMORIES.values(), + SPECIAL_MEMORIES.keys()))
def get_features(self): rf = ft817.FT817Radio.get_features(self) @@ -193,22 +201,25 @@ rf.valid_cross_modes = self.CROSS_MODES_REV.keys() return rf
- def get_duplex(self, mem, _mem): + def _get_duplex(self, mem, _mem): # radio set is_duplex only for + and - but not for split - # at the same time it does not complain if we set it same way 817 does (so no set_duplex here) + # at the same time it does not complain if we set it same way 817 does + # (so no set_duplex here) mem.duplex = self.DUPLEX[_mem.duplex]
- def get_tmode(self, mem, _mem): - # I do not use is_split_tone here because the radio sometimes set it also for standard tone mode + def _get_tmode(self, mem, _mem): + # I do not use is_split_tone here because the radio sometimes set it + # also for standard tone mode try: mem.tmode = self.TMODES[int(_mem.tmode)] except KeyError: mem.tmode = "Cross" mem.cross_mode = self.CROSS_MODES[int(_mem.tmode)]
- def set_tmode(self, mem, _mem): - _mem.unknown_flag = 0 # have to put this bit to 0 otherwise we get strange display in tone frequency (menu 83) - # see bug #88 + def _set_tmode(self, mem, _mem): + # have to put this bit to 0 otherwise we get strange display in tone + # frequency (menu 83). See bug #88 + _mem.unknown_flag = 0 if mem.tmode != "Cross": _mem.is_split_tone = 0 _mem.tmode = self.TMODES_REV[mem.tmode] @@ -217,18 +228,24 @@ _mem.is_split_tone = 1
def process_mmap(self): - self._memobj = bitwise.parse(mem_format, self._mmap) + self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
def _get_special_pms(self, number): mem = chirp_common.Memory() mem.number = self.SPECIAL_PMS[number] mem.extd_number = number
- bitindex = 47 + mem.number + bitindex = 47 + mem.number used = (self._memobj.pmsvisible >> bitindex) & 0x01 valid = (self._memobj.pmsfilled >> bitindex) & 0x01 if os.getenv("CHIRP_DEBUG"): - print "mem.number %i bitindex %i pmsvisible %i pmsfilled %i used %i filled %i" % (mem.number, bitindex, self._memobj.pmsvisible, self._memobj.pmsfilled, used, valid) + print "mem.number %i bitindex %i pmsvisible %i" % \ + (mem.number, + bitindex, + self._memobj.pmsvisible), + print "pmsfilled %i used %i filled %i" % (self._memobj.pmsfilled, + used, + valid) if not used: mem.empty = True if not valid: @@ -249,7 +266,7 @@ def _set_special_pms(self, mem): cur_mem = self._get_special_pms(self.SPECIAL_MEMORIES_REV[mem.number])
- bitindex = 47 + mem.number + bitindex = 47 + mem.number wasused = (self._memobj.pmsvisible >> bitindex) & 0x01 wasvalid = (self._memobj.pmsfilled >> bitindex) & 0x01
@@ -273,8 +290,10 @@ def get_memory(self, number): if number in self.SPECIAL_PMS.keys(): return self._get_special_pms(number) - elif number < 0 and self.SPECIAL_MEMORIES_REV[number] in self.SPECIAL_PMS.keys(): - # I can't stop delete operation from loosing extd_number but I know how to get it back + elif number < 0 and \ + self.SPECIAL_MEMORIES_REV[number] in self.SPECIAL_PMS.keys(): + # I can't stop delete operation from loosing extd_number but + # I know how to get it back return self._get_special_pms(self.SPECIAL_MEMORIES_REV[number]) else: return ft817.FT817Radio.get_memory(self, number) @@ -287,16 +306,17 @@
@directory.register class FT857_US_Radio(FT857Radio): - # seems that radios configured for 5MHz operations send one paket more than others - # so we have to distinguish sub models + """Yaesu FT857/897 (US version)""" + # seems that radios configured for 5MHz operations send one paket more + # than others so we have to distinguish sub models MODEL = "FT-857/897 (US)"
_model = "" _memsize = 7481 # block 9 (140 Bytes long) is to be repeted 40 times # should be 42 times but this way I can use original 817 functions - _block_lengths = [ 2, 82, 252, 196, 252, 196, 212, 55, 140, 140, 140, 38, 176, 140] - + _block_lengths = [ 2, 82, 252, 196, 252, 196, 212, 55, 140, 140, 140, 38, + 176, 140]
SPECIAL_60M = { "M-601" : -52, @@ -310,7 +330,8 @@ SPECIAL_MEMORIES = dict(FT857Radio.SPECIAL_MEMORIES) SPECIAL_MEMORIES.update(SPECIAL_60M)
- SPECIAL_MEMORIES_REV = dict(zip(SPECIAL_MEMORIES.values(), SPECIAL_MEMORIES.keys())) + SPECIAL_MEMORIES_REV = dict(zip(SPECIAL_MEMORIES.values(), + SPECIAL_MEMORIES.keys()))
# this is identical to the one in FT817ND_US_Radio but we inherit from 857 def _get_special_60M(self, number): @@ -318,7 +339,8 @@ mem.number = self.SPECIAL_60M[number] mem.extd_number = number
- _mem = self._memobj.sixtymeterchannels[-self.LAST_SPECIAL60M_INDEX + mem.number] + _mem = self._memobj.sixtymeterchannels[-self.LAST_SPECIAL60M_INDEX + + mem.number]
mem = self._get_memory(mem, _mem)
@@ -343,16 +365,19 @@ "is not supported on M-60x channels")
if mem.mode not in ["USB", "LSB", "CW", "CWR", "NCW", "NCWR", "DIG"]: - raise errors.RadioError(_("Mode {mode} is not valid " - "in 60m channels").format(mode=mem.mode)) - _mem = self._memobj.sixtymeterchannels[-self.LAST_SPECIAL60M_INDEX + mem.number] + raise errors.RadioError("Mode {mode} is not valid " + "in 60m channels".format(mode=mem.mode)) + _mem = self._memobj.sixtymeterchannels[-self.LAST_SPECIAL60M_INDEX + + mem.number] self._set_memory(mem, _mem)
def get_memory(self, number): if number in self.SPECIAL_60M.keys(): return self._get_special_60M(number) - elif number < 0 and self.SPECIAL_MEMORIES_REV[number] in self.SPECIAL_60M.keys(): - # I can't stop delete operation from loosing extd_number but I know how to get it back + elif number < 0 and \ + self.SPECIAL_MEMORIES_REV[number] in self.SPECIAL_60M.keys(): + # I can't stop delete operation from loosing extd_number but + # I know how to get it back return self._get_special_60M(self.SPECIAL_MEMORIES_REV[number]) else: return FT857Radio.get_memory(self, number) diff -r db82df47f205 -r f805c420592f chirp/generic_csv.py --- a/chirp/generic_csv.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/generic_csv.py Fri Apr 27 14:35:41 2012 -0700 @@ -19,10 +19,29 @@ from chirp import chirp_common, errors, directory
class OmittedHeaderError(Exception): + """Internal exception to signal that a column has been omitted""" pass
+def get_datum_by_header(headers, data, header): + """Return the column corresponding to @headers[@header] from @data""" + if header not in headers: + raise OmittedHeaderError("Header %s not provided" % header) + + try: + return data[headers.index(header)] + except IndexError: + raise OmittedHeaderError("Header %s not provided on this line" % \ + header) + +def write_memory(writer, mem): + """Write @mem using @writer if not empty""" + if mem.empty: + return + writer.writerow(mem.to_csv()) + @directory.register class CSVRadio(chirp_common.FileBackedRadio, chirp_common.IcomDstarSupport): + """A driver for Generic CSV files""" VENDOR = "Generic" MODEL = "CSV" FILE_EXTENSION = "csv" @@ -51,13 +70,14 @@ self.errors = [] self.memories = [] for i in range(0, 1000): - m = chirp_common.Memory() - m.number = i - m.empty = True - self.memories.append(m) + mem = chirp_common.Memory() + mem.number = i + mem.empty = True + self.memories.append(mem)
def __init__(self, pipe): chirp_common.FileBackedRadio.__init__(self, None) + self.memories = []
self._filename = pipe if self._filename and os.path.exists(self._filename): @@ -86,34 +106,17 @@
return rf
- def _parse_quoted_line(self, line): - line = line.replace("\n", "") - line = line.replace("\r", "") - line = line.replace('"', "") - - return line.split(",") - - def _get_datum_by_header(self, headers, data, header): - if header not in headers: - raise OmittedHeaderError("Header %s not provided" % header) - - try: - return data[headers.index(header)] - except IndexError: - raise OmittedHeaderError("Header %s not provided on this line" %\ - header) - def _parse_csv_data_line(self, headers, line): mem = chirp_common.Memory() try: - if self._get_datum_by_header(headers, line, "Mode") == "DV": + if get_datum_by_header(headers, line, "Mode") == "DV": mem = chirp_common.DVMemory() except OmittedHeaderError: pass
for header, (typ, attr) in self.ATTR_MAP.items(): try: - val = self._get_datum_by_header(headers, line, header) + val = get_datum_by_header(headers, line, header) if not val and typ == int: val = None else: @@ -174,12 +177,6 @@ print self.errors raise errors.InvalidDataError("No channels found")
- def save_memory(self, writer, mem): - if mem.empty: - return - - writer.writerow(mem.to_csv()) - def save(self, filename=None): if filename is None and self._filename is None: raise errors.RadioError("Need a location to save to") @@ -192,7 +189,7 @@ writer.writerow(chirp_common.Memory.CSV_FORMAT)
for mem in self.memories: - self.save_memory(writer, mem) + write_memory(writer, mem)
f.close()
@@ -220,20 +217,20 @@ delta += 1
for i in range(len(self.memories), len(self.memories) + delta + 1): - m = chirp_common.Memory() - m.empty = True - m.number = i - self.memories.append(m) + mem = chirp_common.Memory() + mem.empty = True + mem.number = i + self.memories.append(mem)
def set_memory(self, newmem): self._grow(newmem.number) self.memories[newmem.number] = newmem
def erase_memory(self, number): - m = chirp_common.Memory() - m.number = number - m.empty = True - self.memories[number] = m + mem = chirp_common.Memory() + mem.number = number + mem.empty = True + self.memories[number] = mem
def get_raw_memory(self, number): return ",".join(chirp_common.Memory.CSV_FORMAT) + \ @@ -241,5 +238,6 @@ ",".join(self.memories[number].to_csv())
@classmethod - def match_model(cls, filedata, filename): + def match_model(cls, _filedata, filename): + """Match files ending in .CSV""" return filename.lower().endswith("." + cls.FILE_EXTENSION) diff -r db82df47f205 -r f805c420592f chirp/generic_tpe.py --- a/chirp/generic_tpe.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/generic_tpe.py Fri Apr 27 14:35:41 2012 -0700 @@ -13,12 +13,10 @@ # 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 csv - +import UserDict from chirp import chirp_common, directory, generic_csv
-class TpeMap: +class TpeMap(UserDict.UserDict): """Pretend we're a dict""" def items(self): return [ @@ -27,13 +25,20 @@ ("Call Sign" , (str, "name")), ("Output Frequency", (chirp_common.parse_freq, "freq")), ("Input Frequency" , (str, "duplex")), - ("CTCSS Tones" , (lambda v: "Tone" if float(v) in chirp_common.TONES else "", "tmode")), - ("CTCSS Tones" , (lambda v: float(v) if float(v) in chirp_common.TONES else 88.5, "rtone")), - ("CTCSS Tones" , (lambda v: float(v) if float(v) in chirp_common.TONES else 88.5, "ctone")), + ("CTCSS Tones" , (lambda v: "Tone" + if float(v) in chirp_common.TONES + else "", "tmode")), + ("CTCSS Tones" , (lambda v: float(v) + if float(v) in chirp_common.TONES + else 88.5, "rtone")), + ("CTCSS Tones" , (lambda v: float(v) + if float(v) in chirp_common.TONES + else 88.5, "ctone")), ]
@directory.register class TpeRadio(generic_csv.CSVRadio): + """Generic ARRL Travel Plus""" VENDOR = "ARRL" MODEL = "Travel Plus" FILE_EXTENSION = "tpe" diff -r db82df47f205 -r f805c420592f chirp/generic_xml.py --- a/chirp/generic_xml.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/generic_xml.py Fri Apr 27 14:35:41 2012 -0700 @@ -19,6 +19,7 @@ from chirp import chirp_common, errors, xml_ll, platform, directory
def validate_doc(doc): + """Validate the document""" basepath = platform.get_platform().executable_path() path = os.path.abspath(os.path.join(basepath, "chirp.xsd")) if not os.path.exists(path): @@ -37,16 +38,16 @@ errs = [] warnings = []
- def err(msg, arg=None): + def _err(msg, *_args): errs.append("ERROR: %s" % msg)
- def wrn(msg, arg=None): + def _wrn(msg, *_args): print "WARNING: %s" % msg warnings.append("WARNING: %s" % msg)
- validCtx = schema.schemaNewValidCtxt() - validCtx.setValidityErrorHandler(err, wrn) - err = validCtx.schemaValidateDoc(doc) + validctx = schema.schemaNewValidCtxt() + validctx.setValidityErrorHandler(_err, _wrn) + err = validctx.schemaValidateDoc(doc) print os.linesep.join(warnings) if err: print "---DOC---\n%s\n------" % doc.serialize(format=1) @@ -54,6 +55,7 @@ raise errors.RadioError("Schema error")
def default_banks(): + """Return an empty set of banks""" banks = []
for i in range(0, 26): @@ -63,6 +65,7 @@
@directory.register class XMLRadio(chirp_common.FileBackedRadio, chirp_common.IcomDstarSupport): + """Generic XML driver""" VENDOR = "Generic" MODEL = "XML" FILE_EXTENSION = "chirp" @@ -135,18 +138,6 @@ xml_ll.del_memory(self.doc, number)
@classmethod - def match_model(cls, filedata, filename): + def match_model(cls, _filedata, filename): + """Match this driver if the extension matches""" return filename.lower().endswith("." + cls.FILE_EXTENSION) - -if __name__ == "__main__": - r = XMLRadio("testmem.chirp") - - print r.get_memory(3) - - m = chirp_common.Memory() - m.name = "TestMem2" - m.freq = 123.456 - m.number = 10 - - #r.set_memory(m) - #r.erase_memory(10) diff -r db82df47f205 -r f805c420592f chirp/ic2100.py --- a/chirp/ic2100.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/ic2100.py Fri Apr 27 14:35:41 2012 -0700 @@ -16,7 +16,7 @@ from chirp import chirp_common, icf, util, directory from chirp import bitwise, memmap
-mem_format = """ +MEM_FORMAT = """ struct { bbcd freq[2]; u8 freq_10khz:4, @@ -82,8 +82,73 @@ DUPLEX = ["", "", "+", "-"] STEPS = [5.0, 10.0, 12.5, 15.0, 20.0, 25.0, 30.0, 50.0]
+def _get_special(): + special = { "C": 506 } + for i in range(0, 3): + ida = "%iA" % (i + 1) + idb = "%iB" % (i + 1) + num = 500 + (i * 2) + special[ida] = num + special[idb] = num + 1 + + return special + +def _get_freq(mem): + freq = (int(mem.freq) * 100000) + \ + (mem.freq_10khz * 10000) + \ + (mem.freq_1khz * 1000) + + if mem.is_12_5: + if chirp_common.is_12_5(freq): + pass + elif mem.freq_1khz == 2: + freq += 500 + elif mem.freq_1khz == 5: + freq += 2500 + elif mem.freq_1khz == 7: + freq += 500 + else: + raise Exception("Unable to resolve 12.5kHz: %i" % freq) + + return freq + +def _set_freq(mem, freq): + mem.freq = freq / 100000 + mem.freq_10khz = (freq / 10000) % 10 + khz = (freq / 1000) % 10 + mem.freq_1khz = khz + mem.is_12_5 = chirp_common.is_12_5(freq) + +def _get_offset(mem): + raw = memmap.MemoryMap(mem.get_raw()) + if ord(raw[5]) & 0x0A: + raw[5] = ord(raw[5]) & 0xF0 + mem.set_raw(raw.get_packed()) + offset = int(mem.offset) * 1000 + 5000 + raw[5] = ord(raw[5]) | 0x0A + mem.set_raw(raw.get_packed()) + return offset + else: + return int(mem.offset) * 1000 + +def _set_offset(mem, offset): + if (offset % 10) == 5000: + extra = 0x0A + offset -= 5000 + else: + extra = 0x00 + + mem.offset = offset / 1000 + raw = memmap.MemoryMap(mem.get_raw()) + raw[5] = ord(raw[5]) | extra + mem.set_raw(raw.get_packed()) + +def _wipe_memory(mem, char): + mem.set_raw(char * (mem.size() / 8)) + @directory.register class IC2100Radio(icf.IcomCloneModeRadio): + """Icom IC-2100""" VENDOR = "Icom" MODEL = "IC-2100H"
@@ -110,81 +175,20 @@ return rf
def process_mmap(self): - self._memobj = bitwise.parse(mem_format, self._mmap) - - def _get_special(self): - special = { "C": 506 } - for i in range(0, 3): - idA = "%iA" % (i+1) - idB = "%iB" % (i+1) - num = 500 + (i * 2) - special[idA] = num - special[idB] = num + 1 - - return special + self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
def get_special_locations(self): - return sorted(self._get_special().keys()) - - def __get_freq(self, mem): - freq = (int(mem.freq) * 100000) + \ - (mem.freq_10khz * 10000) + \ - (mem.freq_1khz * 1000) - - if mem.is_12_5: - if chirp_common.is_12_5(freq): - pass - elif mem.freq_1khz == 2: - freq += 500 - elif mem.freq_1khz == 5: - freq += 2500 - elif mem.freq_1khz == 7: - freq += 500 - else: - raise Exception("Unable to resolve 12.5kHz: %i" % freq) - - return freq - - def __set_freq(self, mem, freq): - mem.freq = freq / 100000 - mem.freq_10khz = (freq / 10000) % 10 - khz = (freq / 1000) % 10 - mem.freq_1khz = khz - mem.is_12_5 = chirp_common.is_12_5(freq) - - def __get_offset(self, mem): - raw = memmap.MemoryMap(mem.get_raw()) - if ord(raw[5]) & 0x0A: - raw[5] = ord(raw[5]) & 0xF0 - mem.set_raw(raw.get_packed()) - offset = int(mem.offset) * 1000 + 5000 - raw[5] = ord(raw[5]) | 0x0A - mem.set_raw(raw.get_packed()) - return offset - else: - return int(mem.offset) * 1000 - - def __set_offset(self, mem, offset): - if (offset % 10) == 5000: - extra = 0x0A - offset -= 5000 - else: - extra = 0x00 - - mem.offset = offset / 1000 - raw = memmap.MemoryMap(mem.get_raw()) - raw[5] = ord(raw[5]) | extra - mem.set_raw(raw.get_packed()) + return sorted(_get_special().keys())
def get_memory(self, number): mem = chirp_common.Memory()
if isinstance(number, str): if number == "C": - number = self._get_special()[number] + number = _get_special()[number] _mem = self._memobj.call[0] else: - number = self._get_special()[number] + number = _get_special()[number] _mem = self._memobj.special[number - 500] empty = False else: @@ -202,15 +206,15 @@ if number <= 100: mem.skip = isskip and "S" or "" else: - mem.extd_number = util.get_dict_rev(self._get_special(), number) + mem.extd_number = util.get_dict_rev(_get_special(), number) mem.immutable = ["number", "skip", "extd_number"]
if empty: mem.empty = True return mem
- mem.freq = self.__get_freq(_mem) - mem.offset = self.__get_offset(_mem) + mem.freq = _get_freq(_mem) + mem.offset = _get_offset(_mem) mem.rtone = chirp_common.TONES[_mem.rtone] mem.ctone = chirp_common.TONES[_mem.ctone] mem.tmode = TMODES[_mem.tmode] @@ -218,14 +222,11 @@
return mem
- def _wipe_memory(self, mem, char): - mem.set_raw(char * (mem.size() / 8)) - def set_memory(self, mem): if mem.number == "C": _mem = self._memobj.call[0] elif isinstance(mem.number, str): - _mem = self._memobj.special[self._get_special[number] - 500] + _mem = self._memobj.special[_get_special[mem.number] - 500] else: number = mem.number - 1 _mem = self._memobj.memory[number] @@ -242,8 +243,8 @@ _skp &= ~mask _mem.name = mem.name.ljust(6)
- self.__set_freq(_mem, mem.freq) - self.__set_offset(_mem, mem.offset) + _set_freq(_mem, mem.freq) + _set_offset(_mem, mem.offset) _mem.rtone = chirp_common.TONES.index(mem.rtone) _mem.ctone = chirp_common.TONES.index(mem.ctone) _mem.tmode = TMODES.index(mem.tmode) diff -r db82df47f205 -r f805c420592f chirp/ic2200.py --- a/chirp/ic2200.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/ic2200.py Fri Apr 27 14:35:41 2012 -0700 @@ -16,7 +16,7 @@ from chirp import chirp_common, icf, util, directory from chirp import bitwise
-mem_format = """ +MEM_FORMAT = """ struct { ul16 freq; ul16 offset; @@ -83,8 +83,23 @@ chirp_common.PowerLevel("MidLow", watts=10), chirp_common.PowerLevel("Low", watts=5)]
+def _get_special(): + special = { "C" : 206 } + for i in range(0, 3): + ida = "%iA" % (i+1) + idb = "%iB" % (i+1) + num = 200 + i * 2 + special[ida] = num + special[idb] = num + 1 + + return special + +def _wipe_memory(mem, char): + mem.set_raw(char * (mem.size() / 8)) + @directory.register class IC2200Radio(icf.IcomCloneModeRadio, chirp_common.IcomDstarSupport): + """Icom IC-2200""" VENDOR = "Icom" MODEL = "IC-2200H"
@@ -145,25 +160,14 @@ return rf
def process_mmap(self): - self._memobj = bitwise.parse(mem_format, self._mmap) - - def _get_special(self): - special = { "C" : 206 } - for i in range(0, 3): - idA = "%iA" % (i+1) - idB = "%iB" % (i+1) - num = 200 + i * 2 - special[idA] = num - special[idB] = num + 1 - - return special + self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
def get_special_locations(self): - return sorted(self._get_special().keys()) + return sorted(_get_special().keys())
def get_memory(self, number): if isinstance(number, str): - number = self._get_special()[number] + number = _get_special()[number]
_mem = self._memobj.memory[number] _flag = self._memobj.flags[number] @@ -183,7 +187,7 @@ if number < 200: mem.skip = _flag.skip and "S" or "" else: - mem.extd_number = util.get_dict_rev(self._get_special(), number) + mem.extd_number = util.get_dict_rev(_get_special(), number) mem.immutable = ["number", "skip", "bank", "bank_index", "extd_number"]
@@ -214,12 +218,9 @@
return [m for m in self._memories if m.number >= lo and m.number <= hi]
- def _wipe_memory(self, mem, char): - mem.set_raw(char * (mem.size() / 8)) - def set_memory(self, mem): if isinstance(mem.number, str): - number = self._get_special()[mem.number] + number = _get_special()[mem.number] else: number = mem.number
@@ -230,11 +231,11 @@
_flag.empty = mem.empty if mem.empty: - self._wipe_memory(_mem, "\xFF") + _wipe_memory(_mem, "\xFF") return
if was_empty: - self._wipe_memory(_mem, "\x00") + _wipe_memory(_mem, "\x00")
_mem.unknown8 = 0 _mem.is_625 = chirp_common.is_fractional_step(mem.freq) diff -r db82df47f205 -r f805c420592f chirp/ic2720.py --- a/chirp/ic2720.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/ic2720.py Fri Apr 27 14:35:41 2012 -0700 @@ -13,10 +13,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
-from chirp import chirp_common, icf, util, directory +from chirp import chirp_common, icf, directory from chirp import bitwise
-mem_format = """ +MEM_FORMAT = """ struct { u32 freq; u32 offset; @@ -69,6 +69,7 @@
@directory.register class IC2720Radio(icf.IcomCloneModeRadio): + """Icom IC-2720""" VENDOR = "Icom" MODEL = "IC-2720H"
@@ -113,7 +114,7 @@ return rf
def process_mmap(self): - self._memobj = bitwise.parse(mem_format, self._mmap) + self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
def get_raw_memory(self, number): return repr(self._memobj.memory[number]) diff -r db82df47f205 -r f805c420592f chirp/ic2820.py --- a/chirp/ic2820.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/ic2820.py Fri Apr 27 14:35:41 2012 -0700 @@ -13,10 +13,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
-from chirp import chirp_common, icf, errors, util, directory -from chirp import bitwise; +from chirp import chirp_common, icf, util, directory +from chirp import bitwise
-mem_format = """ +MEM_FORMAT = """ struct { u32 freq; u32 offset; @@ -84,7 +84,8 @@
MEM_LOC_SIZE = 48
-class IC2820Bank(icf.IcomBank): +class IC2820Bank(icf.IcomNamedBank): + """An IC2820 bank""" def get_name(self): _banks = self._model._radio._memobj.bank_names return str(_banks[self.index].name).rstrip() @@ -93,8 +94,30 @@ _banks = self._model._radio._memobj.bank_names _banks[self.index].name = str(name).ljust(8)[:8]
+def _get_special(): + special = {"C0" : 500 + 20, + "C1" : 500 + 21} + + for i in range(0, 10): + ida = "%iA" % i + idb = "%iB" % i + special[ida] = 500 + i * 2 + special[idb] = 500 + i * 2 + 1 + + return special + +def _resolve_memory_number(number): + if isinstance(number, str): + return _get_special()[number] + else: + return number + +def _wipe_memory(mem, char): + mem.set_raw(char * (mem.size() / 8)) + @directory.register class IC2820Radio(icf.IcomCloneModeRadio, chirp_common.IcomDstarSupport): + """Icom IC-2820""" VENDOR = "Icom" MODEL = "IC-2820H"
@@ -156,32 +179,14 @@ rf.valid_name_length = 8 return rf
- def _get_special(self): - special = {"C0" : 500 + 20, - "C1" : 500 + 21} - - for i in range(0, 10): - idA = "%iA" % i - idB = "%iB" % i - special[idA] = 500 + i * 2 - special[idB] = 500 + i * 2 + 1 - - return special - def get_special_locations(self): - return sorted(self._get_special().keys()) + return sorted(_get_special().keys())
def process_mmap(self): - self._memobj = bitwise.parse(mem_format, self._mmap) - - def _resolve_memory_number(self, number): - if isinstance(number, str): - return self._get_special()[number] - else: - return number + self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
def get_memory(self, number): - number = self._resolve_memory_number(number) + number = _resolve_memory_number(number)
bitpos = (1 << (number % 8)) bytepos = number / 8 @@ -208,7 +213,7 @@ elif _pskip & bitpos: mem.skip = "P" else: - mem.extd_number = util.get_dict_rev(self._get_special(), number) + mem.extd_number = util.get_dict_rev(_get_special(), number) mem.immutable = ["number", "skip", "bank", "bank_index", "extd_number"]
@@ -233,9 +238,6 @@
return mem
- def _wipe_memory(self, mem, char): - mem.set_raw(char * (mem.size() / 8)) - def set_memory(self, mem): bitpos = (1 << (mem.number % 8)) bytepos = mem.number / 8 @@ -259,13 +261,13 @@
if mem.empty: _used |= bitpos - self._wipe_memory(_mem, "\xFF") + _wipe_memory(_mem, "\xFF") self._set_bank(mem.number, None) return
_used &= ~bitpos if was_empty: - self._wipe_memory(_mem, "\x00") + _wipe_memory(_mem, "\x00")
_mem.freq = mem.freq _mem.offset = mem.offset diff -r db82df47f205 -r f805c420592f chirp/ic9x.py --- a/chirp/ic9x.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/ic9x.py Fri Apr 27 14:35:41 2012 -0700 @@ -16,13 +16,11 @@ import time import threading
-from chirp import chirp_common, errors, memmap, ic9x_ll, util, icf, directory +from chirp import chirp_common, errors, ic9x_ll, icf, util, directory from chirp import bitwise
-IC9xA_SPECIAL = {} -IC9xA_SPECIAL_REV = {} -IC9xB_SPECIAL = {} -IC9xB_SPECIAL_REV = {} +IC9XA_SPECIAL = {} +IC9XB_SPECIAL = {}
for i in range(0, 25): idA = "%iA" % i @@ -30,30 +28,18 @@ Anum = 800 + i * 2 Bnum = 400 + i * 2
- IC9xA_SPECIAL[idA] = Anum - IC9xA_SPECIAL[idB] = Bnum - IC9xA_SPECIAL_REV[Anum] = idA - IC9xA_SPECIAL_REV[Bnum] = idB + IC9XA_SPECIAL[idA] = Anum + IC9XA_SPECIAL[idB] = Bnum
- IC9xB_SPECIAL[idA] = Bnum - IC9xB_SPECIAL[idB] = Bnum + 1 - IC9xB_SPECIAL_REV[Bnum] = idA - IC9xB_SPECIAL_REV[Bnum+1] = idB + IC9XB_SPECIAL[idA] = Bnum + IC9XB_SPECIAL[idB] = Bnum + 1
-IC9xA_SPECIAL["C0"] = IC9xB_SPECIAL["C0"] = -1 -IC9xA_SPECIAL["C1"] = IC9xB_SPECIAL["C1"] = -2 +IC9XA_SPECIAL["C0"] = IC9XB_SPECIAL["C0"] = -1 +IC9XA_SPECIAL["C1"] = IC9XB_SPECIAL["C1"] = -2
-IC9xA_SPECIAL_REV[-1] = IC9xB_SPECIAL_REV[-1] = "C0" -IC9xA_SPECIAL_REV[-2] = IC9xB_SPECIAL_REV[-2] = "C1" - -IC9x_SPECIAL = { - 1 : IC9xA_SPECIAL, - 2 : IC9xB_SPECIAL, -} - -IC9x_SPECIAL_REV = { - 1 : IC9xA_SPECIAL_REV, - 2 : IC9xB_SPECIAL_REV, +IC9X_SPECIAL = { + 1 : IC9XA_SPECIAL, + 2 : IC9XB_SPECIAL, }
CHARSET = chirp_common.CHARSET_ALPHANUMERIC + \ @@ -61,7 +47,8 @@
LOCK = threading.Lock()
-class IC9xBank(icf.IcomBank): +class IC9xBank(icf.IcomNamedBank): + """Icom 9x Bank""" def get_name(self): banks = self._model._radio._ic9x_get_banks() return banks[self.index] @@ -73,6 +60,7 @@
@directory.register class IC9xRadio(icf.IcomLiveRadio): + """Base class for Icom IC-9x radios""" MODEL = "IC-91/92AD"
_model = "ic9x" # Fake model info for detect.py @@ -102,7 +90,7 @@ self.set_memory(mem)
def __init__(self, *args, **kwargs): - chirp_common.LiveRadio.__init__(self, *args, **kwargs) + icf.IcomLiveRadio.__init__(self, *args, **kwargs)
if self.pipe: self.pipe.setTimeout(0.1) @@ -119,35 +107,22 @@ ic9x_ll.send_magic(self.pipe) self.__last = time.time()
- def get_available_bank_index(self, bank): - indexes = [] - for mem in self.__memcache.values(): - if mem.bank == bank and mem.bank_index >= 0: - indexes.append(mem.bank_index) - - print "Index list for %i: %s" % (bank, indexes) - - for i in range(0, 99): - if i not in indexes: - return i - - raise errors.RadioError("Out of slots in this bank") - def get_special_locations(self): - return sorted(IC9x_SPECIAL[self.vfo].keys()) + return sorted(IC9X_SPECIAL[self.vfo].keys())
def get_memory(self, number): if isinstance(number, str): try: - number = IC9x_SPECIAL[self.vfo][number] + number = IC9X_SPECIAL[self.vfo][number] except KeyError: - raise InvalidMemoryLocation("Unknown channel %s" % number) + raise errors.InvalidMemoryLocation("Unknown channel %s" % \ + number)
if number < -2 or number > 999: raise errors.InvalidValueError("Number must be between 0 and 999")
if self.__memcache.has_key(number): - return self.__memcache[number] + return self.__memcache[number]
self._lock.acquire() try: @@ -165,7 +140,8 @@ self._lock.release()
if number > self._upper or number < 0: - mem.extd_number = IC9x_SPECIAL_REV[self.vfo][number] + mem.extd_number = util.get_dict_rev(IC9X_SPECIAL, + [self.vfo][number]) mem.immutable = ["number", "skip", "bank", "bank_index", "extd_number"]
@@ -184,7 +160,7 @@
self._lock.release()
- return repr(bitwise.parse(ic9x_ll.memory_frame_format, mframe)) + return repr(bitwise.parse(ic9x_ll.MEMORY_FRAME_FORMAT, mframe))
def get_memories(self, lo=0, hi=None): if hi is None: @@ -192,7 +168,7 @@
memories = []
- for i in range(lo, hi+1): + for i in range(lo, hi + 1): try: print "Getting %i" % i mem = self.get_memory(i) @@ -244,7 +220,8 @@
def _ic9x_get_banks(self): if len(self.__bankcache.keys()) == 26: - return [self.__bankcache[k] for k in sorted(self.__bankcache.keys())] + return [self.__bankcache[k] for k in + sorted(self.__bankcache.keys())]
self._lock.acquire() try: @@ -302,6 +279,7 @@ return rf
class IC9xRadioA(IC9xRadio): + """IC9x Band A subdevice""" VARIANT = "Band A" vfo = 1 _upper = 849 @@ -323,6 +301,7 @@ return rf
class IC9xRadioB(IC9xRadio, chirp_common.IcomDstarSupport): + """IC9x Band B subdevice""" VARIANT = "Band B" vfo = 2 _upper = 399 @@ -362,7 +341,7 @@ calls = []
self._maybe_send_magic() - for i in range(ulimit-1): + for i in range(ulimit - 1): call = ic9x_ll.get_call(self.pipe, cstype, i+1) calls.append(call)
@@ -426,15 +405,13 @@ self.RPTCALL_LIMIT[1], calls)
+def _test(): + import serial + ser = IC9xRadioB(serial.Serial(port="/dev/ttyUSB1", + baudrate=38400, timeout=0.1)) + print ser.get_urcall_list() + print "-- FOO --" + ser.set_urcall_list(["K7TAY", "FOOBAR", "BAZ"]) + if __name__ == "__main__": - def test(): - import serial - import util - r = IC9xRadioB(serial.Serial(port="/dev/ttyUSB1", - baudrate=38400, timeout=0.1)) - print r.get_urcall_list() - #r.set_urcall_list(["K7TAY", "FOOBAR"]) - print "-- FOO --" - r.set_urcall_list(["K7TAY", "FOOBAR", "BAZ"]) - - test() + _test() diff -r db82df47f205 -r f805c420592f chirp/ic9x_icf.py --- a/chirp/ic9x_icf.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/ic9x_icf.py Fri Apr 27 14:35:41 2012 -0700 @@ -13,7 +13,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
-from chirp import chirp_common, icf, ic9x_icf_ll, util, directory +from chirp import chirp_common, icf, ic9x_icf_ll, util, directory, errors
@directory.register class IC9xICFRadio(chirp_common.CloneModeRadio): @@ -45,7 +45,7 @@ return ic9x_icf_ll.get_memory(self._mmap, number)
def load_mmap(self, filename): - mdata, self._mmap = icf.read_file(filename) + _mdata, self._mmap = icf.read_file(filename)
def get_sub_devices(self): return [IC9xICFRadioA(self._mmap), diff -r db82df47f205 -r f805c420592f chirp/ic9x_icf_ll.py --- a/chirp/ic9x_icf_ll.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/ic9x_icf_ll.py Fri Apr 27 14:35:41 2012 -0700 @@ -14,7 +14,7 @@ # along with this program. If not, see http://www.gnu.org/licenses/.
import struct -from chirp import chirp_common, util +from chirp import chirp_common from chirp.memmap import MemoryMap
MEM_LOC_SIZE_A = 20 @@ -31,12 +31,14 @@ POS_NAME = 12
def get_mem_offset(number): + """Get the offset into the memory map for memory @number""" if number < 850: return MEM_LOC_SIZE_A * number else: return (MEM_LOC_SIZE_A * 850) + (MEM_LOC_SIZE_B * (number - 850))
def get_raw_memory(mmap, number): + """Return a raw representation of memory @number""" offset = get_mem_offset(number) if number >= 850: size = MEM_LOC_SIZE_B @@ -45,6 +47,7 @@ return MemoryMap(mmap[offset:offset+size])
def get_freq(mmap): + """Return the memory frequency""" if ord(mmap[10]) & 0x10: mult = 6250 else: @@ -53,22 +56,27 @@ return val * mult
def get_offset(mmap): + """Return the memory offset""" val, = struct.unpack(">H", mmap[POS_OFFSET:POS_OFFSET+2]) return val * 5000
def get_rtone(mmap): + """Return the memory rtone""" val = (ord(mmap[POS_TONE]) & 0xFC) >> 2 return chirp_common.TONES[val]
def get_ctone(mmap): + """Return the memory ctone""" val = (ord(mmap[POS_TONE]) & 0x03) | ((ord(mmap[POS_TONE+1]) & 0xF0) >> 4) return chirp_common.TONES[val]
def get_dtcs(mmap): + """Return the memory dtcs value""" val = ord(mmap[POS_DTCS]) >> 1 return chirp_common.DTCS_CODES[val]
def get_mode(mmap): + """Return the memory mode""" val = ord(mmap[POS_MODE]) & 0x07
modemap = ["FM", "NFM", "WFM", "AM", "DV", "FM"] @@ -76,20 +84,22 @@ return modemap[val]
def get_ts(mmap): + """Return the memory tuning step""" val = (ord(mmap[POS_TS]) & 0xF0) >> 4 if val == 14: return 5.0 # Coerce "Auto" to 5.0
- ICF_TS = list(chirp_common.TUNING_STEPS) - ICF_TS.insert(2, 8.33) - ICF_TS.insert(3, 9.00) - ICF_TS.append(100.0) - ICF_TS.append(125.0) - ICF_TS.append(200.0) + icf_ts = list(chirp_common.TUNING_STEPS) + icf_ts.insert(2, 8.33) + icf_ts.insert(3, 9.00) + icf_ts.append(100.0) + icf_ts.append(125.0) + icf_ts.append(200.0)
- return ICF_TS[val] + return icf_ts[val]
def get_dtcs_polarity(mmap): + """Return the memory dtcs polarity""" val = (ord(mmap[POS_DTCSPOL]) & 0x03)
pols = ["NN", "NR", "RN", "RR"] @@ -97,6 +107,7 @@ return pols[val]
def get_duplex(mmap): + """Return the memory duplex""" val = (ord(mmap[POS_DUPLEX]) & 0x0C) >> 2
dup = ["", "-", "+", ""] @@ -104,9 +115,11 @@ return dup[val]
def get_name(mmap): + """Return the memory name""" return mmap[POS_NAME:POS_NAME+8]
def get_memory(_mmap, number): + """Get memory @number from global memory map @_mmap""" mmap = get_raw_memory(_mmap, number) mem = chirp_common.Memory() mem.number = number diff -r db82df47f205 -r f805c420592f chirp/ic9x_ll.py --- a/chirp/ic9x_ll.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/ic9x_ll.py Fri Apr 27 14:35:41 2012 -0700 @@ -32,11 +32,13 @@
# Dirty hack until I clean up this IC9x mess class IC9xMemory(chirp_common.Memory): + """A dirty hack to stash bank information in a memory""" _bank = None _bank_index = 0 def __init__(self): chirp_common.Memory.__init__(self) class IC9xDVMemory(chirp_common.DVMemory): + """See above dirty hack""" _bank = None _bank_index = 0 def __init__(self): @@ -89,32 +91,34 @@
return _ic9x_parse_frames(data)
-class IcomFrame: - pass - -class IC92Frame(IcomFrame): +class IC92Frame: + """IC9x frame base class""" def get_vfo(self): + """Return the vfo number""" return ord(self._map[0])
def set_vfo(self, vfo): + """Set the vfo number""" self._map[0] = chr(vfo)
def from_raw(self, data): + """Construct the frame from raw data""" self._map = MemoryMap(data)
- #self._map.printable() - def from_frame(self, frame): - self._map = frame._map + """Construct the frame by copying another frame""" + self._map = MemoryMap(frame.get_raw())
def __init__(self, subcmd=0, flen=0, cmd=0x1A): self._map = MemoryMap("\x00" * (4 + flen)) self._map[0] = "\x01\x80" + chr(cmd) + chr(subcmd)
def get_payload(self): + """Return the entire payload (sans header)""" return self._map[4:]
def get_raw(self): + """Return the raw version of the frame""" return self._map.get_packed()
def __str__(self): @@ -126,6 +130,7 @@ return string
def send(self, pipe, verbose=False): + """Send the frame to the radio via @pipe""" if verbose: print "Sending:\n%s" % util.hexprint(self.get_raw())
@@ -146,10 +151,11 @@ return self._map[start+4:end+4]
class IC92GetBankFrame(IC92Frame): + """A frame for requesting bank information""" def __init__(self): IC92Frame.__init__(self, 0x09)
- def send(self, pipe): + def send(self, pipe, verbose=False): rframes = ic9x_send(pipe, self.get_raw())
if len(rframes) == 0: @@ -158,27 +164,30 @@ return rframes
class IC92BankFrame(IC92Frame): + """A frame for bank information""" def __init__(self): # 1 byte for identifier # 8 bytes for name IC92Frame.__init__(self, 0x0B, 9)
- def __str__(self): - return "Bank %s: %s" % (self._data[2], self._data[3:]) - def get_name(self): + """Return the bank name""" return self[1:]
def get_identifier(self): + """Return the letter for the bank (A-Z)""" return self[0]
def set_name(self, name): + """Set the bank name""" self[1] = name[:8].ljust(8)
def set_identifier(self, ident): + """Set the letter for the bank (A-Z)""" self[0] = ident[0]
class IC92MemClearFrame(IC92Frame): + """A frame for clearing (erasing) a memory""" def __init__(self, loc): # 2 bytes for location # 1 byte for 0xFF @@ -187,24 +196,27 @@ self[0] = struct.pack(">BHB", 1, int("%i" % loc, 16), 0xFF)
class IC92MemGetFrame(IC92Frame): - def __init__(self, loc, call=False): + """A frame for requesting a memory""" + def __init__(self, loc, iscall=False): # 2 bytes for location IC92Frame.__init__(self, 0x00, 3)
- if call: - c = 2 + if iscall: + call = 2 else: - c = 1 + call = 1
- self[0] = struct.pack(">BH", c, int("%i" % loc, 16)) + self[0] = struct.pack(">BH", call, int("%i" % loc, 16))
class IC92GetCallsignFrame(IC92Frame): - def __init__(self, type, number): - IC92Frame.__init__(self, type, 1, 0x1D) + """A frame for getting callsign information""" + def __init__(self, calltype, number): + IC92Frame.__init__(self, calltype, 1, 0x1D)
self[0] = chr(number)
class IC92CallsignFrame(IC92Frame): + """A frame to communicate callsign information""" command = 0 # Invalid width = 8
@@ -216,19 +228,23 @@ self[0] = chr(number) + callsign[:self.width].ljust(self.width)
def get_callsign(self): + """Return the actual callsign""" return self[1:self.width+1].rstrip()
class IC92YourCallsignFrame(IC92CallsignFrame): + """URCALL frame""" command = 6 # Your
class IC92RepeaterCallsignFrame(IC92CallsignFrame): + """RPTCALL frame""" command = 7 # Repeater
class IC92MyCallsignFrame(IC92CallsignFrame): + """MYCALL frame""" command = 8 # My width = 12 # 4 bytes for /STID
-memory_frame_format = """ +MEMORY_FRAME_FORMAT = """ struct { u8 vfo; bbcd number[2]; @@ -261,6 +277,7 @@ """
class IC92MemoryFrame(IC92Frame): + """A frame for communicating memory information""" def __init__(self): IC92Frame.__init__(self, 0, DV_MEM_LEN)
@@ -284,21 +301,24 @@ self._map.truncate(MEM_LEN + 4)
def set_iscall(self, iscall): + """This frame refers to a call channel if @iscall is True""" if iscall: self[0] = 2 else: self[0] = 1
def get_iscall(self): + """Return True if this frame refers to a call channel""" return ord(self[0]) == 2
def set_memory(self, mem): + """Take Memory object @mem and configure the frame accordingly""" if mem.number < 0: self.set_iscall(True) mem.number = abs(mem.number) - 1 print "Memory is %i (call %s)" % (mem.number, self.get_iscall())
- _mem = bitwise.parse(memory_frame_format, self).mem + _mem = bitwise.parse(MEMORY_FRAME_FORMAT, self).mem
_mem.number = mem.number
@@ -329,7 +349,8 @@ _mem.digital_code = mem.dv_code
def get_memory(self): - _mem = bitwise.parse(memory_frame_format, self).mem + """Return a Memory object based on the contents of the frame""" + _mem = bitwise.parse(MEMORY_FRAME_FORMAT, self).mem
if MODES[_mem.mode] == "DV": mem = IC9xDVMemory() @@ -372,74 +393,55 @@
return mem
-def print_frames(frames): - count = 0 - for i in frames: - print "Frame %i:" % count - print i - count += 1 - def _send_magic_4800(pipe): cmd = "\x01\x80\x19" magic = ("\xFE" * 25) + cmd - for i in [0,1]: - r = ic9x_send(pipe, magic) - if r: - return r[0].get_raw()[0] == "\x80" - return r and r[0].get_raw()[:3] == rsp + for _i in [0, 1]: + resp = ic9x_send(pipe, magic) + if resp: + return resp[0].get_raw()[0] == "\x80" + return True
def _send_magic_38400(pipe): cmd = "\x01\x80\x19" - rsp = "\x80\x01\x19" + #rsp = "\x80\x01\x19" magic = ("\xFE" * 400) + cmd - for i in [0,1]: - r = ic9x_send(pipe, magic) - if r: - return r[0].get_raw()[0] == "\x80" + for _i in [0, 1]: + resp = ic9x_send(pipe, magic) + if resp: + return resp[0].get_raw()[0] == "\x80" return False
def send_magic(pipe): + """Send the magic incantation to wake up an ic9x radio""" if pipe.getBaudrate() == 38400: - r = _send_magic_38400(pipe) - if r: + resp = _send_magic_38400(pipe) + if resp: return print "Switching from 38400 to 4800" pipe.setBaudrate(4800) - r = _send_magic_4800(pipe) + resp = _send_magic_4800(pipe) pipe.setBaudrate(38400) - if r: + if resp: return raise errors.RadioError("Radio not responding") elif pipe.getBaudrate() == 4800: - r = _send_magic_4800(pipe) - if r: + resp = _send_magic_4800(pipe) + if resp: return print "Switching from 4800 to 38400" pipe.setBaudrate(38400) - r = _send_magic_38400(pipe) - if r: + resp = _send_magic_38400(pipe) + if resp: return pipe.setBaudrate(4800) raise errors.RadioError("Radio not responding") else: - raise errors.InvalidDataError("Radio in unknown state (%i)" % r.getBaudrate()) - -def print_banks(pipe): - frames = send(pipe, "\x01\x80\x1a\x09") # Banks - - print "A Banks:" - for i in range(180, 180+26): - bf = IC92BankFrame() - bf.from_frame(frames[i]) - print str(bf) - - print "B Banks:" - for i in range(237, 237+26): - bf = IC92BankFrame() - bf.from_frame(frames[i]) - print str(bf) + raise errors.InvalidDataError("Radio in unknown state (%i)" % \ + pipe.getBaudrate())
def get_memory_frame(pipe, vfo, number): + """Get the memory frame for @vfo and @number via @pipe""" if number < 0: number = abs(number + 1) call = True @@ -452,6 +454,7 @@ return frame.send(pipe)
def get_memory(pipe, vfo, number): + """Get a memory object for @vfo and @number via @pipe""" rframe = get_memory_frame(pipe, vfo, number)
if len(rframe.get_payload()) < 1: @@ -466,6 +469,7 @@ return mf.get_memory()
def set_memory(pipe, vfo, memory): + """Set memory @memory on @vfo via @pipe""" frame = IC92MemoryFrame() frame.set_memory(memory) frame.set_vfo(vfo) @@ -480,6 +484,7 @@ util.hexprint(rframe.get_payload()))
def erase_memory(pipe, vfo, number): + """Erase memory @number on @vfo via @pipe""" frame = IC92MemClearFrame(number) frame.set_vfo(vfo)
@@ -488,6 +493,7 @@ raise errors.InvalidDataError("Radio reported error")
def get_banks(pipe, vfo): + """Get banks for @vfo via @pipe""" frame = IC92GetBankFrame() frame.set_vfo(vfo)
@@ -509,6 +515,7 @@ return banks
def set_banks(pipe, vfo, banks): + """Set banks for @vfo via @pipe""" for i in range(0, 26): bframe = IC92BankFrame() bframe.set_vfo(vfo) @@ -520,6 +527,7 @@ raise errors.InvalidDataError("Radio reported error")
def get_call(pipe, cstype, number): + """Get @cstype callsign @number via @pipe""" cframe = IC92GetCallsignFrame(cstype.command, number) cframe.set_vfo(2) rframe = cframe.send(pipe) @@ -530,28 +538,10 @@ return cframe.get_callsign()
def set_call(pipe, cstype, number, call): + """Set @cstype @call at position @number via @pipe""" cframe = cstype(number, call) cframe.set_vfo(2) rframe = cframe.send(pipe)
if rframe.get_payload() != "\xfb": raise errors.RadioError("Radio reported error") - -def print_memory(pipe, vfo, number): - if vfo not in [1, 2]: - raise errors.InvalidValueError("VFO must be 1 or 2") - - if number < 0 or number > 399: - raise errors.InvalidValueError("Number must be between 0 and 399") - - mf = get_memory(pipe, vfo, number) - - print "Memory %i from VFO %i: %s" % (number, vfo, str(mf)) - -if __name__ == "__main__": - print util.hexprint(util.bcd_encode(1072)) - print util.hexprint(util.bcd_encode(146900000, False)) - print util.hexprint(util.bcd_encode(25, width=4)) - print util.hexprint(util.bcd_encode(5000000, False, 6)) - print util.hexprint(util.bcd_encode(600000, False, 6)) - diff -r db82df47f205 -r f805c420592f chirp/icf.py --- a/chirp/icf.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/icf.py Fri Apr 27 14:35:41 2012 -0700 @@ -13,21 +13,20 @@ # 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 struct import re
from chirp import chirp_common, errors, util, memmap -from chirp import ic9x_ll # for magic; may need to move later
CMD_CLONE_OUT = 0xE2 CMD_CLONE_IN = 0xE3 CMD_CLONE_DAT = 0xE4 -CMD_CLONE_END = 0xE5 +CMD_CLONE_END = 0xE5
-save_pipe = None +SAVE_PIPE = None
class IcfFrame: + """A single ICF communication frame""" src = 0 dst = 0 cmd = 0 @@ -53,6 +52,7 @@ pass
def parse_frame_generic(data): + """Parse an ICF frame of unknown type from the beginning of @data""" frame = IcfFrame()
frame.src = ord(data[2]) @@ -69,6 +69,7 @@ return frame, data[end+1:]
class RadioStream: + """A class to make reading a stream of IcfFrames easier""" def __init__(self, pipe): self.pipe = pipe self.data = "" @@ -105,6 +106,7 @@ return frames
def get_frames(self, nolimit=False): + """Read any pending frames from the stream""" while True: _data = self.pipe.read(64) if not _data: @@ -114,7 +116,7 @@
if not nolimit and len(self.data) > 128 and "\xFD" in self.data: break # Give us a chance to do some status - if len(data) > 1024: + if len(_data) > 1024: break # Avoid an endless loop of chewing garbage
if not self.data: @@ -122,8 +124,9 @@
return self._process_frames()
-def get_model_data(pipe, model="\x00\x00\x00\x00"): - send_clone_frame(pipe, 0xe0, model, raw=True) +def get_model_data(pipe, mdata="\x00\x00\x00\x00"): + """Query the radio connected to @pipe for its model data""" + send_clone_frame(pipe, 0xe0, mdata, raw=True)
stream = RadioStream(pipe) frames = stream.get_frames() @@ -134,7 +137,10 @@ return frames[0].payload
def get_clone_resp(pipe, length=None): + """Read the response to a clone frame""" def exit_criteria(buf, length): + """Stop reading a clone response if we have enough data or encounter + the end of a frame""" if length is None: return buf.endswith("\xfd") else: @@ -147,6 +153,8 @@ return resp
def send_clone_frame(pipe, cmd, data, raw=False, checksum=False): + """Send a clone frame with @cmd and @data to the radio attached + to @pipe""" cs = 0
if raw: @@ -166,9 +174,9 @@
frame = "\xfe\xfe\xee\xef%s%s%s\xfd" % (chr(cmd), hed, cs)
- if save_pipe: + if SAVE_PIPE: print "Saving data..." - save_pipe.write(frame) + SAVE_PIPE.write(frame)
#print "Sending:\n%s" % util.hexprint(frame) #print "Sending:\n%s" % util.hexprint(hed[6:]) @@ -182,6 +190,7 @@ return frame
def process_bcd(bcddata): + """Convert BCD-encoded data to raw""" data = "" i = 0 while i < range(len(bcddata)) and i+1 < len(bcddata): @@ -195,36 +204,45 @@
return data
-def process_data_frame(frame, mmap): +def process_data_frame(frame, _mmap): + """Process a data frame, adding the payload to @_mmap""" _data = process_bcd(frame.payload) - if len(mmap) >= 0x10000: + if len(_mmap) >= 0x10000: saddr, = struct.unpack(">I", _data[0:4]) - bytes, = struct.unpack("B", _data[4]) - data = _data[5:5+bytes] + length, = struct.unpack("B", _data[4]) + data = _data[5:5+length] else: saddr, = struct.unpack(">H", _data[0:2]) - bytes, = struct.unpack("B", _data[2]) - data = _data[3:3+bytes] + length, = struct.unpack("B", _data[2]) + data = _data[3:3+length]
try: - mmap[saddr] = data + _mmap[saddr] = data except IndexError: - print "Error trying to set %i bytes at %05x (max %05x)" %\ - (bytes, saddr, len(mmap)) - return saddr, saddr + bytes + print "Error trying to set %i bytes at %05x (max %05x)" % \ + (bytes, saddr, len(_mmap)) + return saddr, saddr + length
def start_hispeed_clone(radio, cmd): - buf = ("\xFE" * 20) + "\xEE\xEF\xE8" + radio._model + "\x00\x00\x02\x01\xFD" + """Send the magic incantation to the radio to go fast""" + buf = ("\xFE" * 20) + \ + "\xEE\xEF\xE8" + \ + radio.get_model() + \ + "\x00\x00\x02\x01\xFD" print "Starting HiSpeed:\n%s" % util.hexprint(buf) radio.pipe.write(buf) radio.pipe.flush() - r = radio.pipe.read(128) - print "Response:\n%s" % util.hexprint(r) + resp = radio.pipe.read(128) + print "Response:\n%s" % util.hexprint(resp)
print "Switching to 38400 baud" radio.pipe.setBaudrate(38400)
- buf = ("\xFE" * 14) + "\xEE\xEF" + chr(cmd) + radio._model[:3] + "\x00\xFD" + buf = ("\xFE" * 14) + \ + "\xEE\xEF" + \ + chr(cmd) + \ + radio.get_model()[:3] + \ + "\x00\xFD" print "Starting HiSpeed Clone:\n%s" % util.hexprint(buf) radio.pipe.write(buf) radio.pipe.flush() @@ -247,7 +265,7 @@ stream = RadioStream(radio.pipe)
addr = 0 - mmap = memmap.MemoryMap(chr(0x00) * radio._memsize) + _mmap = memmap.MemoryMap(chr(0x00) * radio.get_memsize()) last_size = 0 while True: frames = stream.get_frames() @@ -256,7 +274,7 @@
for frame in frames: if frame.cmd == CMD_CLONE_DAT: - src, dst = process_data_frame(frame, mmap) + src, dst = process_data_frame(frame, _mmap) if last_size != (dst - src): print "ICF Size change from %i to %i at %04x" % (last_size, dst - src, @@ -276,16 +294,18 @@ status.cur = addr radio.status_fn(status)
- return mmap + return _mmap
def clone_from_radio(radio): + """Do a full clone out of the radio's memory""" try: return _clone_from_radio(radio) except Exception, e: raise errors.RadioError("Failed to communicate with the radio: %s" % e)
def send_mem_chunk(radio, start, stop, bs=32): - mmap = radio.get_mmap() + """Send a single chunk of the radio's memory from @start-@stop""" + _mmap = radio.get_mmap()
status = chirp_common.Status() status.msg = "Cloning to radio" @@ -297,11 +317,11 @@ else: size = stop - i
- if radio._memsize >= 0x10000: + if radio.get_memsize() >= 0x10000: chunk = struct.pack(">IB", i, size) else: chunk = struct.pack(">HB", i, size) - chunk += mmap[i:i+size] + chunk += _mmap[i:i+size]
send_clone_frame(radio.pipe, CMD_CLONE_DAT, @@ -315,10 +335,10 @@ return True
def _clone_to_radio(radio): - global save_pipe + global SAVE_PIPE
# Uncomment to save out a capture of what we actually write to the radio - # save_pipe = file("pipe_capture.log", "w", 0) + # SAVE_PIPE = file("pipe_capture.log", "w", 0)
md = get_model_data(radio.pipe)
@@ -347,9 +367,9 @@ send_clone_frame(radio.pipe, CMD_CLONE_END, radio.get_endframe(), raw=True) frames += stream.get_frames(True)
- if save_pipe: - save_pipe.close() - save_pipe = None + if SAVE_PIPE: + SAVE_PIPE.close() + SAVE_PIPE = None
try: result = frames[-1] @@ -359,21 +379,24 @@ return result.payload[0] == '\x00'
def clone_to_radio(radio): + """Initiate a full memory clone out to @radio""" try: return _clone_to_radio(radio) except Exception, e: raise errors.RadioError("Failed to communicate with the radio: %s" % e)
def convert_model(mod_str): + """Convert an ICF-style model string into what we get from the radio""" data = "" for i in range(0, len(mod_str), 2): - hex = mod_str[i:i+2] - val = int(hex, 16) - data += chr(val) + hexval = mod_str[i:i+2] + intval = int(hexval, 16) + data += chr(intval)
return data
def convert_data_line(line): + """Convert an ICF data line to raw memory format""" if line.startswith("#"): return ""
@@ -381,12 +404,10 @@
if len(line) == 38: # Small memory (< 0x10000) - pos = int(line[0:4], 16) size = int(line[4:6], 16) data = line[6:] else: # Large memory (>= 0x10000) - pos = int(line[0:8], 16) size = int(line[8:10], 16) data = line[10:]
@@ -404,6 +425,7 @@ return _mmap
def read_file(filename): + """Read an ICF file and return the model string and memory data""" f = file(filename)
mod_str = f.readline() @@ -419,6 +441,7 @@ return model, memmap.MemoryMap(_mmap)
def is_9x_icf(filename): + """Returns True if @filename is an IC9x ICF file""" f = file(filename) mdata = f.read(8) f.close() @@ -426,6 +449,7 @@ return mdata in ["30660000", "28880000"]
def is_icf_file(filename): + """Returns True if @filename is an ICF file""" f = file(filename) data = f.readline() data += f.readline() @@ -436,10 +460,17 @@ return bool(re.match("^[0-9]{8}#", data))
class IcomBank(chirp_common.Bank): + """A bank that works for all Icom radios""" # Integral index of the bank (not to be confused with per-memory # bank indexes index = 0
+class IcomNamedBank(IcomBank): + """A bank with an adjustable name""" + def set_name(self, name): + """Set the name of the bank""" + pass + class IcomBankModel(chirp_common.BankModel): """Icom radios all have pretty much the same simple bank model. This central implementation can, with a few icom-specific radio interfaces @@ -483,6 +514,7 @@ return [self.get_banks()[index]]
class IcomIndexedBankModel(IcomBankModel, chirp_common.BankIndexInterface): + """Generic bank model for Icom radios with indexed banks""" def get_index_bounds(self): return self._radio._bank_index_bounds
@@ -512,6 +544,7 @@
class IcomCloneModeRadio(chirp_common.CloneModeRadio): + """Base class for Icom clone-mode radios""" VENDOR = "Icom" BAUDRATE = 9600
@@ -523,17 +556,25 @@ _bank_class = IcomBank _can_hispeed = False
- def is_hispeed(self): - return self._can_hispeed + @classmethod + def is_hispeed(cls): + """Returns True if the radio supports hispeed cloning""" + return cls._can_hispeed
- def get_model(self): - return self._model + @classmethod + def get_model(cls): + """Returns the Icom model data for this radio""" + return cls._model
- def get_endframe(self): - return self._endframe + @classmethod + def get_endframe(cls): + """Returns the magic clone end frame for this radio""" + return cls._endframe
- def get_ranges(self): - return self._ranges + @classmethod + def get_ranges(cls): + """Returns the ranges this radio likes to have in a clone""" + return cls._ranges
def sync_in(self): self._mmap = clone_from_radio(self) @@ -563,6 +604,7 @@ raise Exception("Not implemented")
class IcomLiveRadio(chirp_common.LiveRadio): + """Base class for an Icom Live-mode radio""" VENDOR = "Icom" BAUD_RATE = 38400
@@ -579,14 +621,3 @@ return IcomBankModel(self) else: return None - -if __name__ == "__main__": - import sys - - model, mmap = read_file(sys.argv[1]) - - print util.hexprint(model) - - f = file("out.img", "w") - f.write(mmap.get_packed()) - f.close() diff -r db82df47f205 -r f805c420592f chirp/icomciv.py --- a/chirp/icomciv.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/icomciv.py Fri Apr 27 14:35:41 2012 -0700 @@ -1,18 +1,18 @@
import struct -from chirp import chirp_common, icf, util, errors, bitwise, ic9x_ll, directory +from chirp import chirp_common, icf, util, errors, bitwise, directory from chirp.memmap import MemoryMap
DEBUG = True
-mem_format = """ +MEM_FORMAT = """ bbcd number[2]; u8 unknown1; lbcd freq[5]; u8 unknown2:5, mode:3; """ -mem_vfo_format = """ +MEM_VFO_FORMAT = """ u8 vfo; bbcd number[2]; u8 unknown1; @@ -35,6 +35,7 @@ """
class Frame: + """Base class for an ICF frame""" _cmd = 0x00 _sub = 0x00
@@ -42,16 +43,20 @@ self._data = ""
def set_command(self, cmd, sub): + """Set the command number (and optional subcommand)""" self._cmd = cmd self._sub = sub
def get_data(self): + """Return the data payload""" return self._data
def set_data(self, data): + """Set the data payload""" self._data = data
def send(self, src, dst, serial, willecho=True): + """Send the frame over @serial, using @src and @dst addresses""" raw = struct.pack("BBBBBB", 0xFE, 0xFE, src, dst, self._cmd, self._sub) raw += str(self._data) + chr(0xFD)
@@ -68,13 +73,14 @@ print util.hexprint(echo)
def read(self, serial): + """Read the frame from @serial""" data = "" while not data.endswith(chr(0xFD)): - c = serial.read(1) - if not c: + char = serial.read(1) + if not char: print "Read %i bytes total" % len(data) raise errors.RadioError("Timeout") - data += c + data += char
if data == chr(0xFD): raise errors.RadioError("Radio reported error") @@ -90,39 +96,49 @@ return src, dst
class MemFrame(Frame): + """A memory frame""" _cmd = 0x1A _sub = 0x00 _loc = 0
def set_location(self, loc): + """Set the memory location number""" self._loc = loc self._data = struct.pack(">H", int("%04i" % loc, 16))
def make_empty(self): + """Mark as empty so the radio will erase the memory""" self._data = struct.pack(">HB", int("%04i" % self._loc, 16), 0xFF)
def is_empty(self): + """Return True if memory is marked as empty""" return len(self._data) < 5
def get_obj(self): + """Return a bitwise parsed object""" self._data = MemoryMap(str(self._data)) # Make sure we're assignable - return bitwise.parse(mem_format, self._data) + return bitwise.parse(MEM_FORMAT, self._data)
def initialize(self): + """Initialize to sane values""" self._data = MemoryMap("".join(["\x00"] * (self.get_obj().size() / 8)))
class MultiVFOMemFrame(MemFrame): + """A memory frame for radios with multiple VFOs""" def set_location(self, loc, vfo=1): self._loc = loc self._data = struct.pack(">BH", vfo, int("%04i" % loc, 16))
def get_obj(self): self._data = MemoryMap(str(self._data)) # Make sure we're assignable - return bitwise.parse(mem_vfo_format, self._data) + return bitwise.parse(MEM_VFO_FORMAT, self._data)
class IcomCIVRadio(icf.IcomLiveRadio): + """Base class for ICOM CIV-based radios""" BAUD_RATE = 19200 MODEL = "CIV Radio" + _model = "\x00" + _template = 0
def _send_frame(self, frame): return frame.send(ord(self._model), 0xE0, self.pipe, @@ -140,9 +156,9 @@ def _detect_echo(self): echo_test = "\xfe\xfe\xe0\xe0\xfa\xfd" self.pipe.write(echo_test) - r = self.pipe.read(6) - print "Echo:\n%s" % util.hexprint(r) - return r == echo_test + resp = self.pipe.read(6) + print "Echo:\n%s" % util.hexprint(resp) + return resp == echo_test
def __init__(self, *args, **kwargs): icf.IcomLiveRadio.__init__(self, *args, **kwargs) @@ -256,6 +272,7 @@
@directory.register class Icom7200Radio(IcomCIVRadio): + """Icom IC-7200""" MODEL = "7200" _model = "\x76" _template = 201 @@ -277,6 +294,7 @@
@directory.register class Icom7000Radio(IcomCIVRadio): + """Icom IC-7000""" MODEL = "7000" _model = "\x70" _template = 102 @@ -305,14 +323,15 @@ (0x70, 0xE0) : Icom7000Radio, }
-def probe_model(s): +def probe_model(ser): + """Probe the radio attatched to @ser for its model""" f = Frame() f.set_command(0x19, 0x00)
for model, controller in CIV_MODELS.keys(): - f.send(model, controller, s) + f.send(model, controller, ser) try: - f.read(s) + f.read(ser) except errors.RadioError: continue
diff -r db82df47f205 -r f805c420592f chirp/icq7.py --- a/chirp/icq7.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/icq7.py Fri Apr 27 14:35:41 2012 -0700 @@ -13,12 +13,11 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
-from chirp import chirp_common, icf, errors, util, directory +from chirp import chirp_common, icf, directory from chirp import bitwise -from chirp.memmap import MemoryMap from chirp.chirp_common import to_GHz, from_GHz
-mem_format = """ +MEM_FORMAT = """ struct { bbcd freq[3]; u8 fractional:1, @@ -49,6 +48,7 @@
@directory.register class ICQ7Radio(icf.IcomCloneModeRadio): + """Icom IC-Q7A""" VENDOR = "Icom" MODEL = "IC-Q7A"
@@ -76,7 +76,7 @@ return rf
def process_mmap(self): - self._memobj = bitwise.parse(mem_format, self._mmap) + self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
def get_raw_memory(self, number): return repr(self._memobj.memory[number]) diff -r db82df47f205 -r f805c420592f chirp/ict70.py --- a/chirp/ict70.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/ict70.py Fri Apr 27 14:35:41 2012 -0700 @@ -13,11 +13,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
-from chirp import chirp_common, icf, errors, util, directory +from chirp import chirp_common, icf, directory from chirp import bitwise -from chirp.memmap import MemoryMap
-mem_format = """ +MEM_FORMAT = """ struct { u24 freq; ul16 offset; @@ -71,6 +70,7 @@ ]
class ICT70Bank(icf.IcomBank): + """ICT70 bank""" def get_name(self): _bank = self._model._radio._memobj.bank_names[self.index] return str(_bank.name).rstrip() @@ -81,6 +81,7 @@
@directory.register class ICT70Radio(icf.IcomCloneModeRadio): + """Icom IC-T70""" VENDOR = "Icom" MODEL = "IC-T70"
@@ -133,7 +134,7 @@ return rf
def process_mmap(self): - self._memobj = bitwise.parse(mem_format, self._mmap) + self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
def get_raw_memory(self, number): return repr(self._memobj.memory[number]) diff -r db82df47f205 -r f805c420592f chirp/icw32.py --- a/chirp/icw32.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/icw32.py Fri Apr 27 14:35:41 2012 -0700 @@ -13,10 +13,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
-from chirp import chirp_common, icf, errors, util, directory +from chirp import chirp_common, icf, util, directory from chirp import bitwise
-mem_format = """ +MEM_FORMAT = """ #seekto 0x%x; struct { bbcd freq[3]; @@ -61,8 +61,16 @@ DUPLEX = ["", "", "-", "+"] TONE = ["", "", "Tone", "TSQL"]
+def _get_special(): + special = {} + for i in range(0, 5): + special["M%iA" % (i+1)] = 100 + i*2 + special["M%iB" % (i+1)] = 100 + i*2 + 1 + return special + @directory.register class ICW32ARadio(icf.IcomCloneModeRadio): + """Icom IC-W32A""" VENDOR = "Icom" MODEL = "IC-W32A"
@@ -97,26 +105,18 @@ return rf
def process_mmap(self): - format = mem_format % self._mem_positions - self._memobj = bitwise.parse(format, self._mmap) + fmt = MEM_FORMAT % self._mem_positions + self._memobj = bitwise.parse(fmt, self._mmap)
def get_raw_memory(self, number): return repr(self._memobj.memory[number])
- def _get_special(self): - special = {} - for i in range(0, 5): - special["M%iA" % (i+1)] = 100 + i*2 - special["M%iB" % (i+1)] = 100 + i*2 + 1 - - return special - def get_special_locations(self): - return sorted(self._get_special().keys()) + return sorted(_get_special().keys())
def get_memory(self, number): if isinstance(number, str): - number = self._get_special()[number] + number = _get_special()[number]
_mem = self._memobj.memory[number] _flg = self._memobj.flag[number] @@ -129,7 +129,7 @@ mem.skip = _flg.skip and "S" or "" else: # Special memories - mem.extd_number = util.get_dict_rev(self._get_special(), number) + mem.extd_number = util.get_dict_rev(_get_special(), number)
if _flg.empty: mem.empty = True @@ -190,11 +190,13 @@ return filedata[-16:] == "IcomCloneFormat3"
class ICW32ARadioVHF(ICW32ARadio): + """ICW32 VHF subdevice""" VARIANT = "VHF" _limits = (118000000, 174000000) _mem_positions = (0x0000, 0x0DC0)
class ICW32ARadioUHF(ICW32ARadio): + """ICW32 UHF subdevice""" VARIANT = "UHF" _limits = (400000000, 470000000) _mem_positions = (0x06E0, 0x0E2E) diff -r db82df47f205 -r f805c420592f chirp/icx8x.py --- a/chirp/icx8x.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/icx8x.py Fri Apr 27 14:35:41 2012 -0700 @@ -15,7 +15,7 @@
from chirp import chirp_common, icf, icx8x_ll, errors, directory
-def isUHF(pipe): +def _isuhf(pipe): try: md = icf.get_model_data(pipe) val = ord(md[20]) @@ -29,6 +29,7 @@
@directory.register class ICx8xRadio(icf.IcomCloneModeRadio, chirp_common.IcomDstarSupport): + """Icom IC-V/U82""" VENDOR = "Icom" MODEL = "IC-V82/U82"
@@ -69,7 +70,7 @@ rf.valid_duplexes = ["", "-", "+"] rf.valid_tuning_steps = [x for x in chirp_common.TUNING_STEPS if x != 6.25] - if self.isUHF: + if self._isuhf: rf.valid_bands = [(420000000, 470000000)] else: rf.valid_bands = [(118000000, 176000000)] @@ -78,12 +79,12 @@ return rf
def _get_type(self): - flag = (isUHF(self.pipe) != 0) + flag = (_isuhf(self.pipe) != 0)
- if self.isUHF is not None and (self.isUHF != flag): + if self._isuhf is not None and (self._isuhf != flag): raise errors.RadioError("VHF/UHF model mismatch")
- self.isUHF = flag + self._isuhf = flag
return flag
@@ -95,15 +96,15 @@ # file, look for the flag. If we're syncing from serial, set # that flag. if isinstance(pipe, str): - self.isUHF = (ord(self._mmap[0x1930]) != 0) + self._isuhf = (ord(self._mmap[0x1930]) != 0) #print "Found %s image" % (self.isUHF and "UHF" or "VHF") else: - self.isUHF = None + self._isuhf = None
def sync_in(self): self._get_type() icf.IcomCloneModeRadio.sync_in(self) - self._mmap[0x1930] = self.isUHF and 1 or 0 + self._mmap[0x1930] = self._isuhf and 1 or 0
def sync_out(self): self._get_type() @@ -116,7 +117,7 @@ if not self._mmap: self.sync_in()
- if self.isUHF: + if self._isuhf: base = 400 else: base = 0 @@ -134,7 +135,7 @@ if not self._mmap: self.sync_in()
- if self.isUHF: + if self._isuhf: base = 400 else: base = 0 diff -r db82df47f205 -r f805c420592f chirp/id31.py --- a/chirp/id31.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/id31.py Fri Apr 27 14:35:41 2012 -0700 @@ -15,7 +15,7 @@
from chirp import directory, icf, bitwise, chirp_common
-mem_format = """ +MEM_FORMAT = """ struct { u24 freq; u16 offset; @@ -111,7 +111,6 @@
def _encode_call(call): _call = [0x00] * 7 - mask = 0 for i in range(0, 7): val = ord(call[i]) << (i + 1) if i > 0: @@ -121,7 +120,32 @@
return _call
+def _get_freq(_mem): + freq = int(_mem.freq) + offs = int(_mem.offset) + + if freq & 0x00200000: + mult = 6250 + else: + mult = 5000 + + freq &= 0x0003FFFF + + return (freq * mult), (offs * mult) + +def _set_freq(_mem, freq, offset): + if chirp_common.is_fractional_step(freq): + mult = 6250 + flag = 0x00200000 + else: + mult = 5000 + flag = 0x00000000 + + _mem.freq = (freq / mult) | flag + _mem.offset = (offset / mult) + class ID31Bank(icf.IcomBank): + """A ID-31 Bank""" def get_name(self): _banks = self._model._radio._memobj.bank_names return str(_banks[self.index].name).rstrip() @@ -132,6 +156,7 @@
@directory.register class ID31Radio(icf.IcomCloneModeRadio, chirp_common.IcomDstarSupport): + """Icom ID-31""" MODEL = "ID-31A"
_memsize = 0x15500 @@ -179,35 +204,11 @@ return rf
def process_mmap(self): - self._memobj = bitwise.parse(mem_format, self._mmap) + self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
def get_raw_memory(self, number): return repr(self._memobj.memory[number])
- def _get_freq(self, _mem): - freq = int(_mem.freq) - offs = int(_mem.offset) - - if freq & 0x00200000: - mult = 6250 - else: - mult = 5000 - - freq &= 0x0003FFFF - - return (freq * mult), (offs * mult) - - def _set_freq(self, _mem, freq, offset): - if chirp_common.is_fractional_step(freq): - mult = 6250 - flag = 0x00200000 - else: - mult = 5000 - flag = 0x00000000 - - _mem.freq = (freq / mult) | flag - _mem.offset = (offset / mult) - def get_memory(self, number): _mem = self._memobj.memory[number] _usd = self._memobj.used_flags[number / 8] @@ -226,7 +227,7 @@ mem.empty = True return mem
- mem.freq, mem.offset = self._get_freq(_mem) + mem.freq, mem.offset = _get_freq(_mem) mem.name = str(_mem.name).rstrip() mem.rtone = chirp_common.TONES[_mem.rtone] mem.ctone = chirp_common.TONES[_mem.ctone] @@ -261,7 +262,7 @@
bit = (1 << (memory.number % 8))
- self._set_freq(_mem, memory.freq, memory.offset) + _set_freq(_mem, memory.freq, memory.offset) _mem.name = memory.name.ljust(12)[:12] _mem.rtone = chirp_common.TONES.index(memory.rtone) _mem.ctone = chirp_common.TONES.index(memory.ctone) @@ -308,10 +309,8 @@
def get_repeater_call_list(self): calls = [] - i = 0 for rptcall in self._memobj.rptcall: call = _decode_call(rptcall.call) - i += 1 if call.rstrip() and not call == "CALLSIGN": calls.append(call) for repeater in self._memobj.repeaters: diff -r db82df47f205 -r f805c420592f chirp/id800.py --- a/chirp/id800.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/id800.py Fri Apr 27 14:35:41 2012 -0700 @@ -16,7 +16,7 @@ from chirp import chirp_common, icf, errors, directory from chirp import bitwise
-mem_format = """ +MEM_FORMAT = """ #seekto 0x0020; struct { u24 freq; @@ -104,8 +104,50 @@ ALPHA_CHARSET = " ABCDEFGHIJKLMNOPQRSTUVWXYZ" NUMERIC_CHARSET = "0123456789+-=*/()|"
+def get_name(_mem): + """Decode the name from @_mem""" + def _get_char(val): + if val == 0: + return " " + elif val & 0x20: + return ALPHA_CHARSET[val & 0x1F] + else: + return NUMERIC_CHARSET[val & 0x0F] + + name_bytes = [_mem.name1, _mem.name2, _mem.name3, + _mem.name4, _mem.name5, _mem.name6] + name = "" + for val in name_bytes: + name += _get_char(val) + + return name.rstrip() + +def set_name(_mem, name): + """Encode @name in @_mem""" + def _get_index(char): + if char == " ": + return 0 + elif char.isalpha(): + return ALPHA_CHARSET.index(char) | 0x20 + else: + return NUMERIC_CHARSET.index(char) | 0x10 + + name = name.ljust(6)[:6] + + _mem.usealpha = bool(name.strip()) + + # The element override calling convention makes this harder to automate. + # It's just six, so do it manually + _mem.name1 = _get_index(name[0]) + _mem.name2 = _get_index(name[1]) + _mem.name3 = _get_index(name[2]) + _mem.name4 = _get_index(name[3]) + _mem.name5 = _get_index(name[4]) + _mem.name6 = _get_index(name[5]) + @directory.register class ID800v2Radio(icf.IcomCloneModeRadio, chirp_common.IcomDstarSupport): + """Icom ID800""" VENDOR = "Icom" MODEL = "ID-800H" VARIANT = "v2" @@ -186,50 +228,11 @@ return rf
def process_mmap(self): - self._memobj = bitwise.parse(mem_format, self._mmap) + self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
def get_special_locations(self): return sorted(ID800_SPECIAL.keys())
- def _get_name(self, _mem): - def get_char(val): - if val == 0: - return " " - elif val & 0x20: - return ALPHA_CHARSET[val & 0x1F] - else: - return NUMERIC_CHARSET[val & 0x0F] - - name_bytes = [_mem.name1, _mem.name2, _mem.name3, - _mem.name4, _mem.name5, _mem.name6] - name = "" - for val in name_bytes: - name += get_char(val) - - return name.rstrip() - - def _set_name(self, _mem, name): - def get_index(char): - if char == " ": - return 0 - elif char.isalpha(): - return ALPHA_CHARSET.index(char) | 0x20 - else: - return NUMERIC_CHARSET.index(char) | 0x10 - - name = name.ljust(6)[:6] - - _mem.usealpha = bool(name.strip()) - - # The element override calling convention makes this harder to automate. - # It's just six, so do it manually - _mem.name1 = get_index(name[0]) - _mem.name2 = get_index(name[1]) - _mem.name3 = get_index(name[2]) - _mem.name4 = get_index(name[3]) - _mem.name5 = get_index(name[4]) - _mem.name6 = get_index(name[5]) - def get_memory(self, number): if isinstance(number, str): try: @@ -268,7 +271,7 @@ mem.dtcs = chirp_common.DTCS_CODES[_mem.dtcs] mem.dtcs_polarity = DTCS_POL[_mem.dtcs_polarity] mem.tuning_step = STEPS[_mem.tuning_step] - mem.name = self._get_name(_mem) + mem.name = get_name(_mem)
mem.skip = _flg.pskip and "P" or _flg.skip and "S" or ""
@@ -295,7 +298,7 @@ _mem.dtcs = chirp_common.DTCS_CODES.index(mem.dtcs) _mem.dtcs_polarity = DTCS_POL.index(mem.dtcs_polarity) _mem.tuning_step = STEPS.index(mem.tuning_step) - self._set_name(_mem, mem.name) + set_name(_mem, mem.name)
_flg.pskip = mem.skip == "P" _flg.skip = mem.skip == "S" diff -r db82df47f205 -r f805c420592f chirp/id880.py --- a/chirp/id880.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/id880.py Fri Apr 27 14:35:41 2012 -0700 @@ -16,7 +16,7 @@ from chirp import chirp_common, icf, directory from chirp import bitwise
-mem_format = """ +MEM_FORMAT = """ struct { u24 freq; u16 offset; @@ -86,12 +86,13 @@ 100.0, 125.0, 200.0]
def decode_call(sevenbytes): + """Decode a callsign from a packed region @sevenbytes""" if len(sevenbytes) != 7: raise Exception("%i (!=7) bytes to decode_call" % len(sevenbytes))
i = 0 rem = 0 - str = "" + call = "" for byte in [ord(x) for x in sevenbytes]: i += 1
@@ -100,7 +101,7 @@ code = (byte >> i) | rem # Code gets the upper bits of remainder # plus all but the i lower bits of this # byte - str += chr(code) + call += chr(code)
rem = (byte & mask) << 7 - i # Remainder for next time are the masked # bits, moved to the high places for the @@ -108,14 +109,13 @@
# After seven trips gathering overflow bits, we chould have seven # left, which is the final character - str += chr(rem) + call += chr(rem)
- return str.rstrip() + return call.rstrip()
def encode_call(call): + """Encode @call into a 7-byte region""" call = call.ljust(8) - val = 0 - buf = []
for i in range(0, 8): @@ -132,7 +132,33 @@
return "".join([chr(x) for x in buf[:7]])
-class ID880Bank(icf.IcomBank): +def _get_freq(_mem): + val = int(_mem.freq) + + if val & 0x00200000: + mult = 6250 + else: + mult = 5000 + + val &= 0x0003FFFF + + return (val * mult) + +def _set_freq(_mem, freq): + if chirp_common.is_fractional_step(freq): + mult = 6250 + flag = 0x00200000 + else: + mult = 5000 + flag = 0x00000000 + + _mem.freq = (freq / mult) | flag + +def _wipe_memory(mem, char): + mem.set_raw(char * (mem.size() / 8)) + +class ID880Bank(icf.IcomNamedBank): + """ID880 Bank""" def get_name(self): _bank = self._model._radio._memobj.bank_names[self.index] return str(_bank.name).rstrip() @@ -143,6 +169,7 @@
@directory.register class ID880Radio(icf.IcomCloneModeRadio, chirp_common.IcomDstarSupport): + """Icom ID880""" VENDOR = "Icom" MODEL = "ID-880H"
@@ -185,7 +212,7 @@ _bank.index = index
def process_mmap(self): - self._memobj = bitwise.parse(mem_format, self._mmap) + self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
def get_features(self): rf = chirp_common.RadioFeatures() @@ -208,28 +235,6 @@ def get_raw_memory(self, number): return repr(self._memobj.memory[number])
- def _get_freq(self, _mem): - val = int(_mem.freq) - - if val & 0x00200000: - mult = 6250 - else: - mult = 5000 - - val &= 0x0003FFFF - - return (val * mult) - - def _set_freq(self, _mem, freq): - if chirp_common.is_fractional_step(freq): - mult = 6250 - flag = 0x00200000 - else: - mult = 5000 - flag = 0x00000000 - - _mem.freq = (freq / mult) | flag - def get_memory(self, number): bytepos = number / 8 bitpos = 1 << (number % 8) @@ -263,7 +268,7 @@ mem.empty = True return mem
- mem.freq = self._get_freq(_mem) + mem.freq = _get_freq(_mem) mem.offset = (_mem.offset * 5) * 1000 mem.rtone = chirp_common.TONES[_mem.rtone] mem.ctone = chirp_common.TONES[_mem.ctone] @@ -280,9 +285,6 @@
return mem
- def _wipe_memory(self, mem, char): - mem.set_raw(char * (mem.size() / 8)) - def set_memory(self, mem): bitpos = (1 << (mem.number % 8)) bytepos = mem.number / 8 @@ -295,16 +297,16 @@
if mem.empty: _used |= bitpos - self._wipe_memory(_mem, "\xFF") + _wipe_memory(_mem, "\xFF") self._set_bank(mem.number, None) return
_used &= ~bitpos
if was_empty: - self._wipe_memory(_mem, "\x00") + _wipe_memory(_mem, "\x00")
- self._set_freq(_mem, mem.freq) + _set_freq(_mem, mem.freq) _mem.offset = int((mem.offset / 1000) / 5) _mem.rtone = chirp_common.TONES.index(mem.rtone) _mem.ctone = chirp_common.TONES.index(mem.ctone) @@ -359,7 +361,7 @@ _calls = self._memobj.rptcall calls = ["*NOTUSE*"]
- for i in range(*self.RPTCALL_LIMIT): + for _i in range(*self.RPTCALL_LIMIT): # FIXME: Not sure where the repeater list actually is calls.append("UNSUPRTD") continue @@ -370,6 +372,7 @@ # the ID-880. So, don't register right now #@directory.register class ID80Radio(ID880Radio): + """Icom ID80""" MODEL = "ID-80H"
_model = "\x31\x55\x00\x01" diff -r db82df47f205 -r f805c420592f chirp/idrp.py --- a/chirp/idrp.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/idrp.py Fri Apr 27 14:35:41 2012 -0700 @@ -13,16 +13,15 @@ # 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 struct import serial
from chirp import chirp_common, errors -from chirp.memmap import MemoryMap from chirp import util
DEBUG_IDRP = False
def parse_frames(buf): + """Parse frames from the radio""" frames = []
while "\xfe\xfe" in buf: @@ -38,8 +37,9 @@
return frames
-def send(pipe, buffer): - pipe.write("\xfe\xfe%s\xfd" % buffer) +def send(pipe, buf): + """Send data in @buf to @pipe""" + pipe.write("\xfe\xfe%s\xfd" % buf) pipe.flush()
data = "" @@ -55,15 +55,18 @@ return parse_frames(data)
def send_magic(pipe): + """Send the magic wakeup call to @pipe""" send(pipe, ("\xfe" * 15) + "\x01\x7f\x19")
def drain(pipe): + """Chew up any data waiting on @pipe""" while True: buf = pipe.read(4096) if not buf: break
def set_freq(pipe, freq): + """Set the frequency of the radio on @pipe to @freq""" freqbcd = util.bcd_encode(freq, bigendian=False, width=9) buf = "\x01\x7f\x05" + freqbcd
@@ -78,6 +81,7 @@ raise errors.InvalidDataError("Repeater reported error")
def get_freq(pipe): + """Get the frequency of the radio attached to @pipe""" buf = "\x01\x7f\x1a\x09"
drain(pipe) @@ -103,10 +107,8 @@ "ctone", "dtcs", "tmode", "dtcs_polarity", "skip", "duplex", "offset", "mode", "tuning_step", "bank_index"]
-class IcomRepeater(chirp_common.LiveRadio): - pass - -class IDRPx000V(IcomRepeater): +class IDRPx000V(chirp_common.LiveRadio): + """Icom IDRP-*""" BAUD_RATE = 19200 VENDOR = "Icom" MODEL = "ID-2000V/4000V/2D/2V" @@ -154,7 +156,11 @@
set_freq(self.pipe, mem.freq)
+def do_test(): + """Get the frequency of /dev/icom""" + ser = serial.Serial(port="/dev/icom", baudrate=19200, timeout=0.5) + #set_freq(pipe, 439.920) + get_freq(ser) + if __name__ == "__main__": - pipe = serial.Serial(port="/dev/icom", baudrate=19200, timeout=0.5) - #set_freq(pipe, 439.920) - get_freq(pipe) + do_test() diff -r db82df47f205 -r f805c420592f chirp/import_logic.py --- a/chirp/import_logic.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/import_logic.py Fri Apr 27 14:35:41 2012 -0700 @@ -16,12 +16,15 @@ from chirp import chirp_common, errors
class ImportError(Exception): + """An import error""" pass
class DestNotCompatible(ImportError): + """Memory is not compatible with the destination radio""" pass
def ensure_has_calls(radio, memory): + """Make sure @radio has the necessary D-STAR callsigns for @memory""" ulist_changed = rlist_changed = False
ulist = radio.get_urcall_list() @@ -59,10 +62,10 @@ radio.set_repeater_cal_list(rlist)
# Filter the name according to the destination's rules -def _import_name(dst_radio, srcrf, mem): +def _import_name(dst_radio, _srcrf, mem): mem.name = dst_radio.filter_name(mem.name)
-def _import_power(dst_radio, srcrf, mem): +def _import_power(dst_radio, _srcrf, mem): levels = dst_radio.get_features().valid_power_levels if not levels: mem.power = None @@ -101,6 +104,8 @@ mem.ctone = mem.rtone
def import_mem(dst_radio, src_features, src_mem, overrides={}): + """Perform import logic to create a destination memory from + src_mem that will be compatible with @dst_radio""" dst_rf = dst_radio.get_features()
if isinstance(src_mem, chirp_common.DVMemory): @@ -123,10 +128,10 @@ dst_mem.__dict__[k] = v
msgs = dst_radio.validate_memory(dst_mem) - errors = [x for x in msgs if isinstance(x, chirp_common.ValidationError)] - if errors: + errs = [x for x in msgs if isinstance(x, chirp_common.ValidationError)] + if errs: raise DestNotCompatible("Unable to create import memory: %s" %\ - ", ".join(errors)) + ", ".join(errs))
return dst_mem
diff -r db82df47f205 -r f805c420592f chirp/kenwood_hmk.py --- a/chirp/kenwood_hmk.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/kenwood_hmk.py Fri Apr 27 14:35:41 2012 -0700 @@ -14,16 +14,17 @@ # 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 csv
from chirp import chirp_common, errors, directory, generic_csv
class OmittedHeaderError(Exception): + """An internal exception to indicate that a header was omitted""" pass
@directory.register class HMKRadio(generic_csv.CSVRadio): + """Kenwood HMK format""" VENDOR = "Kenwood" MODEL = "HMK" FILE_EXTENSION = "hmk" diff -r db82df47f205 -r f805c420592f chirp/kenwood_live.py --- a/chirp/kenwood_live.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/kenwood_live.py Fri Apr 27 14:35:41 2012 -0700 @@ -23,8 +23,10 @@ import sys sys.path.insert(0, "..")
-from chirp import chirp_common, errors, directory -from chirp.settings import * +from chirp import chirp_common, errors, directory, util +from chirp.settings import RadioSetting, RadioSettingGroup, \ + RadioSettingValueInteger, RadioSettingValueBoolean, \ + RadioSettingValueString, RadioSettingValueList
DEBUG = True
@@ -35,31 +37,24 @@
THF6_MODES = ["FM", "WFM", "AM", "LSB", "USB", "CW"]
-def rev(hash, value): - reverse = {} - for k, v in hash.items(): - reverse[v] = k - - return reverse[value] - LOCK = threading.Lock()
-def command(s, command, *args): +def command(ser, cmd, *args): + """Send @cmd to radio via @ser""" global LOCK
start = time.time()
LOCK.acquire() - cmd = command if args: cmd += " " + " ".join(args) if DEBUG: print "PC->RADIO: %s" % cmd - s.write(cmd + "\r") + ser.write(cmd + "\r")
result = "" while not result.endswith("\r"): - result += s.read(8) + result += ser.read(8) if (time.time() - start) > 0.5: print "Timeout waiting for data" break @@ -72,7 +67,8 @@ return result.strip()
LAST_BAUD = 9600 -def get_id(s): +def get_id(ser): + """Get the ID of the radio attached to @ser""" global LAST_BAUD bauds = [9600, 19200, 38400, 57600] bauds.remove(LAST_BAUD) @@ -80,17 +76,18 @@
for i in bauds: print "Trying ID at baud %i" % i - s.setBaudrate(i) - s.write("\r") - s.read(25) - r = command(s, "ID") - if " " in r: + ser.setBaudrate(i) + ser.write("\r") + ser.read(25) + resp = command(ser, "ID") + if " " in resp: LAST_BAUD = i - return r.split(" ")[1] + return resp.split(" ")[1]
raise errors.RadioError("No response from radio")
def get_tmode(tone, ctcss, dcs): + """Get the tone mode based on the values of the tone, ctcss, dcs""" if dcs and int(dcs) == 1: return "DTCS" elif int(ctcss): @@ -101,9 +98,11 @@ return ""
def iserr(result): + """Returns True if the @result from a radio is an error""" return result in ["N", "?"]
class KenwoodLiveRadio(chirp_common.LiveRadio): + """Base class for all live-mode kenwood radios""" BAUD_RATE = 9600 VENDOR = "Kenwood" MODEL = "" @@ -178,9 +177,9 @@ if " " in result: value = result.split(" ", 1)[1] if value.count(",") == 2: - zero, loc, mem.name = value.split(",") + _zero, _loc, mem.name = value.split(",") else: - loc, mem.name = value.split(",") + _loc, mem.name = value.split(",")
if mem.duplex == "" and self._kenwood_split: result = command(self.pipe, *self._cmd_get_split(number)) @@ -212,7 +211,6 @@ spec = ",".join(spec) r1 = command(self.pipe, *self._cmd_set_memory(memory.number, spec)) if not iserr(r1): - import time time.sleep(0.5) r2 = command(self.pipe, *self._cmd_set_memory_name(memory.number, memory.name)) @@ -238,8 +236,8 @@ if not self.__memcache.has_key(number): return
- r = command(self.pipe, *self._cmd_set_memory(number, "")) - if iserr(r): + resp = command(self.pipe, *self._cmd_set_memory(number, "")) + if iserr(resp): raise errors.RadioError("Radio refused delete of %i" % number) del self.__memcache[number]
@@ -271,6 +269,7 @@
@directory.register class THD7Radio(KenwoodLiveRadio): + """Kenwood TH-D7""" MODEL = "TH-D7"
_kenwood_split = True @@ -294,7 +293,7 @@
def _make_mem_spec(self, mem): if mem.duplex in " -+": - duplex = rev(DUPLEX, mem.duplex) + duplex = util.get_dict_rev(DUPLEX, mem.duplex) offset = mem.offset else: duplex = 0 @@ -312,7 +311,7 @@ "", # DCS Code "%02i" % (self._kenwood_valid_tones.index(mem.ctone) + 1), "%09i" % offset, - "%i" % rev(MODES, mem.mode), + "%i" % util.get_dict_rev(MODES, mem.mode), "%i" % ((mem.skip == "S") and 1 or 0))
return spec @@ -341,15 +340,15 @@ return mem
def _kenwood_get(self, cmd): - r = command(self.pipe, cmd) - if " " in r: - return r.split(" ", 1) + resp = command(self.pipe, cmd) + if " " in resp: + return resp.split(" ", 1) else: raise errors.RadioError("Radio refused to return %s" % cmd)
def _kenwood_set(self, cmd, value): - r = command(self.pipe, cmd, value) - if " " in r: + resp = command(self.pipe, cmd, value) + if " " in resp: return raise errors.RadioError("Radio refused to set %s" % cmd)
@@ -377,7 +376,7 @@ aux, tnc, save, display, dtmf) sky = RadioSettingGroup("sky", "SkyCommand") aprs = RadioSettingGroup("aprs", "APRS") - all = RadioSettingGroup("top", "All Settings", radio, aprs, sky) + top = RadioSettingGroup("top", "All Settings", radio, aprs, sky)
bools = [("AMR", aprs, "APRS Message Auto-Reply"), ("AIP", aux, "Advanced Intercept Point"), @@ -394,9 +393,9 @@
for setting, group, name in bools: value = self._kenwood_get_bool(setting) - s = RadioSetting(setting, name, - RadioSettingValueBoolean(value)) - group.append(s) + rs = RadioSetting(setting, name, + RadioSettingValueBoolean(value)) + group.append(rs)
lists = [("BAL", all, "Balance"), ("BEP", aux, "Beep"), @@ -420,18 +419,18 @@ for setting, group, name in lists: value = self._kenwood_get_int(setting) options = TH_D7_SETTINGS[setting] - s = RadioSetting(setting, name, - RadioSettingValueList(options, - options[value])) - group.append(s) + rs = RadioSetting(setting, name, + RadioSettingValueList(options, + options[value])) + group.append(rs)
ints = [("CNT", display, "Contrast", 1, 16), ] - for setting, group, name, min, max in ints: + for setting, group, name, minv, maxv in ints: value = self._kenwood_get_int(setting) - s = RadioSetting(setting, name, - RadioSettingValueInteger(min, max, value)) - group.append(s) + rs = RadioSetting(setting, name, + RadioSettingValueInteger(minv, maxv, value)) + group.append(rs)
strings = [("MES", display, "Power-on Message", 8), ("MYC", aprs, "APRS Callsign", 8), @@ -442,11 +441,11 @@ ] for setting, group, name, length in strings: _cmd, value = self._kenwood_get(setting) - s = RadioSetting(setting, name, - RadioSettingValueString(0, length, value)) - group.append(s) + rs = RadioSetting(setting, name, + RadioSettingValueString(0, length, value)) + group.append(rs)
- return all + return top
def set_settings(self, settings): for element in settings: @@ -471,10 +470,12 @@
@directory.register class THD7GRadio(THD7Radio): + """Kenwood TH-D7G""" MODEL = "TH-D7G"
@directory.register class TMD700Radio(KenwoodLiveRadio): + """Kenwood TH-D700""" MODEL = "TM-D700"
_kenwood_split = True @@ -497,7 +498,7 @@
def _make_mem_spec(self, mem): if mem.duplex in " -+": - duplex = rev(DUPLEX, mem.duplex) + duplex = util.get_dict_rev(DUPLEX, mem.duplex) else: duplex = 0 spec = ( \ @@ -512,7 +513,7 @@ "%03i0" % (chirp_common.DTCS_CODES.index(mem.dtcs) + 1), "%02i" % (self._kenwood_valid_tones.index(mem.ctone) + 1), "%09i" % mem.offset, - "%i" % rev(MODES, mem.mode), + "%i" % util.get_dict_rev(MODES, mem.mode), "%i" % ((mem.skip == "S") and 1 or 0))
return spec @@ -555,6 +556,7 @@
@directory.register class TMV7Radio(KenwoodLiveRadio): + """Kenwood TM-V7""" MODEL = "TM-V7"
mem_upper_limit = 200 # Will be updated @@ -592,7 +594,7 @@ spec = ( \ "%011i" % mem.freq, "%X" % STEPS.index(mem.tuning_step), - "%i" % rev(DUPLEX, mem.duplex), + "%i" % util.get_dict_rev(DUPLEX, mem.duplex), "0", "%i" % (mem.tmode == "Tone"), "%i" % (mem.tmode == "TSQL"), @@ -637,14 +639,14 @@ mem.empty = False try: self.set_memory(mem) - except: + except Exception: # Failed, so we're past the limit return False
# Erase what we did try: self.erase_memory(loc) - except: + except Exception: pass # V7A Can't delete just yet
return True @@ -653,20 +655,24 @@ return 50
class TMV7RadioSub(TMV7Radio): + """Base class for the TM-V7 sub devices""" def __init__(self, pipe): - KenwoodLiveRadio.__init__(self, pipe) + TMV7Radio.__init__(self, pipe) self._detect_split()
class TMV7RadioVHF(TMV7RadioSub): + """TM-V7 VHF subdevice""" VARIANT = "VHF" _vfo = 0
class TMV7RadioUHF(TMV7RadioSub): + """TM-V7 UHF subdevice""" VARIANT = "UHF" _vfo = 1
@directory.register class TMG707Radio(TMV7Radio): + """Kenwood TM-G707""" MODEL = "TM-G707"
def get_features(self): @@ -677,13 +683,15 @@ (430000000, 450000000)] return rf
-THF6A_STEPS = [5.0, 6.25, 8.33, 9.0, 10.0, 12.5, 15.0, 20.0, 25.0, 30.0, 50.0, 100.0] +THF6A_STEPS = [5.0, 6.25, 8.33, 9.0, 10.0, 12.5, 15.0, 20.0, 25.0, 30.0, 50.0, + 100.0]
THF6A_DUPLEX = dict(DUPLEX) THF6A_DUPLEX[3] = "split"
@directory.register class THF6ARadio(KenwoodLiveRadio): + """Kenwood TH-F6""" MODEL = "TH-F6"
_upper = 399 @@ -751,7 +759,7 @@
def _make_mem_spec(self, mem): if mem.duplex in " +-": - duplex = rev(THF6A_DUPLEX, mem.duplex) + duplex = util.get_dict_rev(THF6A_DUPLEX, mem.duplex) offset = mem.offset elif mem.duplex == "split": duplex = 0 @@ -777,6 +785,7 @@
@directory.register class THF7ERadio(THF6ARadio): + """Kenwood TH-F7""" MODEL = "TH-F7"
D710_DUPLEX = ["", "+", "-", "split"] @@ -786,6 +795,7 @@
@directory.register class TMD710Radio(KenwoodLiveRadio): + """Kenwood TM-D710""" MODEL = "TM-D710"
_upper = 999 @@ -846,11 +856,11 @@ return mem
def _make_mem_spec(self, mem): - print "Index %i for step %.2f" % (chirp_common.TUNING_STEPS.index(mem.tuning_step), mem.tuning_step) spec = ( \ "%010i" % mem.freq, "%X" % D710_STEPS.index(mem.tuning_step), - "%i" % (0 if mem.duplex == "split" else D710_DUPLEX.index(mem.duplex)), + "%i" % (0 if mem.duplex == "split" else \ + D710_DUPLEX.index(mem.duplex)), "0", # Reverse "%i" % (mem.tmode == "Tone" and 1 or 0), "%i" % (mem.tmode == "TSQL" and 1 or 0), @@ -860,7 +870,7 @@ "%03i" % (chirp_common.DTCS_CODES.index(mem.dtcs)), "%08i" % (0 if mem.duplex == "split" else mem.offset), # Offset "%i" % D710_MODES.index(mem.mode), - "%010i" % (mem.offset if mem.duplex == "split" else 0), # TX Frequency + "%010i" % (mem.offset if mem.duplex == "split" else 0), # TX Freq "0", # Unknown "%i" % D710_SKIP.index(mem.skip), # Memory Lockout ) @@ -869,6 +879,7 @@
@directory.register class THD72Radio(TMD710Radio): + """Kenwood TH-D72""" MODEL = "TH-D72" HARDWARE_FLOW = True
@@ -901,11 +912,11 @@ return mem
def _make_mem_spec(self, mem): - print "Index %i for step %.2f" % (chirp_common.TUNING_STEPS.index(mem.tuning_step), mem.tuning_step) spec = ( \ "%010i" % mem.freq, "%X" % D710_STEPS.index(mem.tuning_step), - "%i" % (0 if mem.duplex == "split" else D710_DUPLEX.index(mem.duplex)), + "%i" % (0 if mem.duplex == "split" else \ + D710_DUPLEX.index(mem.duplex)), "0", # Reverse "%i" % (mem.tmode == "Tone" and 1 or 0), "%i" % (mem.tmode == "TSQL" and 1 or 0), @@ -917,7 +928,7 @@ "0", "%08i" % (0 if mem.duplex == "split" else mem.offset), # Offset "%i" % D710_MODES.index(mem.mode), - "%010i" % (mem.offset if mem.duplex == "split" else 0), # TX Frequency + "%010i" % (mem.offset if mem.duplex == "split" else 0), # TX Freq "0", # Unknown "%i" % D710_SKIP.index(mem.skip), # Memory Lockout ) @@ -926,7 +937,8 @@
@directory.register class TMV71Radio(TMD710Radio): - MODEL = "TM-V71" + """Kenwood TM-V71""" + MODEL = "TM-V71"
THK2_DUPLEX = ["", "+", "-"] THK2_MODES = ["FM", "NFM"] @@ -944,6 +956,7 @@
@directory.register class THK2Radio(KenwoodLiveRadio): + """Kenwood TH-K2""" MODEL = "TH-K2"
_kenwood_valid_tones = list(THK2_TONES) @@ -1028,6 +1041,7 @@
@directory.register class TM271Radio(THK2Radio): + """Kenwood TM-271""" MODEL = "TM-271"
def get_features(self): @@ -1059,26 +1073,35 @@ def _cmd_set_memory_name(self, number, name): return "MN", "%03i,%s" % (number, name)
-if __name__ == "__main__": - m = chirp_common.Memory() - m.number = 1 - m.freq = 144000000 - m.duplex = "split" - m.offset = 146000000 +def do_test(): + """Dev test""" + mem = chirp_common.Memory() + mem.number = 1 + mem.freq = 144000000 + mem.duplex = "split" + mem.offset = 146000000
- TestClass = THF6ARadio + tc = THF6ARadio class FakeSerial: + """Faked serial line""" buf = "" def write(self, buf): + """Write""" self.buf = buf def read(self, count): + """Read""" if self.buf[:2] == "ID": return "ID %s\r" % TestClass.MODEL return self.buf def setTimeout(self, foo): + """Set Timeout""" pass def setBaudrate(self, foo): + """Set Baudrate""" pass
- r = TestClass(FakeSerial()) - r.set_memory(m) + radio = tc(FakeSerial()) + radio.set_memory(mem) + +if __name__ == "__main__": + do_test() diff -r db82df47f205 -r f805c420592f chirp/memmap.py --- a/chirp/memmap.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/memmap.py Fri Apr 27 14:35:41 2012 -0700 @@ -24,6 +24,7 @@ self._data = list(data)
def printable(self, start=None, end=None, printit=True): + """Return a printable representation of the memory map""" if not start: start = 0
@@ -38,12 +39,14 @@ return string
def get(self, start, length=1): + """Return a chunk of memory of @length bytes from @start""" if start == -1: return "".join(self._data[start:]) else: return "".join(self._data[start:start+length])
def set(self, pos, value): + """Set a chunk of memory at @pos to @value""" if isinstance(value, int): self._data[pos] = chr(value) elif isinstance(value, str): @@ -55,6 +58,7 @@ type(value).__name__)
def get_packed(self): + """Return the entire memory map as raw data""" return "".join(self._data)
def __len__(self): @@ -80,4 +84,5 @@ return self.printable(printit=False)
def truncate(self, size): + """Truncate the memory map to @size""" self._data = self._data[:size] diff -r db82df47f205 -r f805c420592f chirp/platform.py --- a/chirp/platform.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/platform.py Fri Apr 27 14:35:41 2012 -0700 @@ -1,19 +1,3 @@ -# Copyright 2008 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 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see http://www.gnu.org/licenses/. - -# # Copyright 2008 Dan Smith dsmith@danplanet.com # # This program is free software: you can redistribute it and/or modify @@ -34,26 +18,30 @@ import glob from subprocess import Popen
-def find_me(): +def _find_me(): return sys.modules["chirp.platform"].__file__
class Platform: - # pylint: disable-msg=R0201 + """Base class for platform-specific functions"""
def __init__(self, basepath): self._base = basepath self._last_dir = self.default_dir()
def get_last_dir(self): + """Return the last directory used""" return self._last_dir
def set_last_dir(self, last_dir): + """Set the last directory used""" self._last_dir = last_dir
def config_dir(self): + """Return the preferred configuration file directory""" return self._base
def log_dir(self): + """Return the preferred log file directory""" logdir = os.path.join(self.config_dir(), "logs") if not os.path.isdir(logdir): os.mkdir(logdir) @@ -61,29 +49,37 @@ return logdir
def filter_filename(self, filename): + """Filter @filename for platform-forbidden characters""" return filename
def log_file(self, filename): + """Return the full path to a log file with @filename""" filename = self.filter_filename(filename + ".txt").replace(" ", "_") return os.path.join(self.log_dir(), filename)
def config_file(self, filename): + """Return the full path to a config file with @filename""" return os.path.join(self.config_dir(), self.filter_filename(filename))
def open_text_file(self, path): + """Spawn the necessary program to open a text file at @path""" raise NotImplementedError("The base class can't do that")
def open_html_file(self, path): + """Spawn the necessary program to open an HTML file at @path""" raise NotImplementedError("The base class can't do that")
def list_serial_ports(self): + """Return a list of valid serial ports""" return []
def default_dir(self): + """Return the default directory for this platform""" return "."
def gui_open_file(self, start_dir=None, types=[]): + """Prompt the user to pick a file to open""" import gtk
if not start_dir: @@ -114,6 +110,7 @@ return None
def gui_save_file(self, start_dir=None, default_name=None, types=[]): + """Prompt the user to pick a filename to save""" import gtk
if not start_dir: @@ -154,6 +151,7 @@ return None
def gui_select_dir(self, start_dir=None): + """Prompt the user to pick a directory""" import gtk
if not start_dir: @@ -178,9 +176,11 @@ return None
def os_version_string(self): + """Return a string that describes the OS/platform version""" return "Unknown Operating System"
def executable_path(self): + """Return a full path to the program executable""" def we_are_frozen(): return hasattr(sys, "frozen")
@@ -190,7 +190,8 @@ sys.getfilesystemencoding())) else: # UNIX: Find the parent directory of this module - return os.path.dirname(os.path.abspath(os.path.join(find_me(), ".."))) + return os.path.dirname(os.path.abspath(os.path.join(_find_me(), + "..")))
def _unix_editor(): macos_textedit = "/Applications/TextEdit.app/Contents/MacOS/TextEdit" @@ -201,6 +202,7 @@ return "gedit"
class UnixPlatform(Platform): + """A platform module suitable for UNIX systems""" def __init__(self, basepath): if not basepath: basepath = os.path.abspath(os.path.join(self.default_dir(), @@ -214,7 +216,7 @@ # This is a hack that needs to be properly fixed by importing the # latest changes to this module from d-rats. In the interest of # time, however, I'll throw it here - if sys.platform == "darwin": + if sys.platform == "darwin": if not os.environ.has_key("DISPLAY"): print "Forcing DISPLAY for MacOS" os.environ["DISPLAY"] = ":0" @@ -252,7 +254,6 @@ glob.glob("/dev/tty.KeySerial*"))
def os_version_string(self): - # pylint: disable-msg=W0703 try: issue = file("/etc/issue.net", "r") ver = issue.read().strip().replace("\r", "").replace("\n", "")[:64] @@ -264,6 +265,7 @@ return ver
class Win32Platform(Platform): + """A platform module suitable for Windows systems""" def __init__(self, basepath=None): if not basepath: appdata = os.getenv("APPDATA") @@ -319,7 +321,6 @@ return ports
def gui_open_file(self, start_dir=None, types=[]): - # pylint: disable-msg=W0703,W0613 import win32gui
typestrs = "" @@ -337,11 +338,10 @@ return str(fname)
def gui_save_file(self, start_dir=None, default_name=None, types=[]): - # pylint: disable-msg=W0703,W0613 import win32gui import win32api
- (pform, _, build, _, _) = win32api.GetVersionEx() + (pform, _, _, _, _) = win32api.GetVersionEx()
typestrs = "" custom = "%s\0*.%s\0" % (types[0][0], types[0][1]) @@ -358,10 +358,10 @@
def_ext = "*.%s" % types[0][1] try: - fname, filter, _ = win32gui.GetSaveFileNameW(File=default_name, - CustomFilter=custom, - DefExt=def_ext, - Filter=typestrs) + fname, _, _ = win32gui.GetSaveFileNameW(File=default_name, + CustomFilter=custom, + DefExt=def_ext, + Filter=typestrs) except Exception, e: print "Failed to get filename: %s" % e return None @@ -369,7 +369,6 @@ return str(fname)
def gui_select_dir(self, start_dir=None): - # pylint: disable-msg=W0703,W0613 from win32com.shell import shell
try: @@ -401,8 +400,7 @@
PLATFORM = None def get_platform(basepath=None): - #pylint: disable-msg=W0602 - + """Return the platform singleton""" global PLATFORM
if not PLATFORM: @@ -410,19 +408,19 @@
return PLATFORM
+def _do_test(): + __pform = get_platform() + + print "Config dir: %s" % __pform.config_dir() + print "Default dir: %s" % __pform.default_dir() + print "Log file (foo): %s" % __pform.log_file("foo") + print "Serial ports: %s" % __pform.list_serial_ports() + print "OS Version: %s" % __pform.os_version_string() + #__pform.open_text_file("d-rats.py") + + #print "Open file: %s" % __pform.gui_open_file() + #print "Save file: %s" % __pform.gui_save_file(default_name="Foo.txt") + print "Open folder: %s" % __pform.gui_select_dir("/tmp") + if __name__ == "__main__": - def do_test(): - __pform = get_platform() - - print "Config dir: %s" % __pform.config_dir() - print "Default dir: %s" % __pform.default_dir() - print "Log file (foo): %s" % __pform.log_file("foo") - print "Serial ports: %s" % __pform.list_serial_ports() - print "OS Version: %s" % __pform.os_version_string() - #__pform.open_text_file("d-rats.py") - - #print "Open file: %s" % __pform.gui_open_file() - #print "Save file: %s" % __pform.gui_save_file(default_name="Foo.txt") - print "Open folder: %s" % __pform.gui_select_dir("/tmp") - - do_test() + _do_test() diff -r db82df47f205 -r f805c420592f chirp/radioreference.py --- a/chirp/radioreference.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/radioreference.py Fri Apr 27 14:35:41 2012 -0700 @@ -13,7 +13,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
-from chirp import chirp_common, CHIRP_VERSION, errors +from chirp import chirp_common, errors try: from suds.client import Client HAVE_SUDS = True @@ -31,6 +31,7 @@ }
class RadioReferenceRadio(chirp_common.NetworkSourceRadio): + """RadioReference.com data source""" VENDOR = "Radio Reference LLC" MODEL = "RadioReference.com"
@@ -38,7 +39,7 @@ APPKEY = "46785108"
def __init__(self, *args, **kwargs): - chirp_common.Radio.__init__(self, *args, **kwargs) + chirp_common.NetworkSourceRadio.__init__(self, *args, **kwargs)
if not HAVE_SUDS: raise errors.RadioError( @@ -49,9 +50,11 @@ self._client = Client(self.URL) self._freqs = None self._modes = None + self._zip = None
- def set_params(self, zip, username, password): - self._zip = zip + def set_params(self, zipcode, username, password): + """Set the parameters to be used for a query""" + self._zip = zipcode self._auth["username"] = username self._auth["password"] = password
@@ -72,7 +75,8 @@ print "Fetching category:", cat.cName for subcat in cat.subcats: print "\t", subcat.scName - result = self._client.service.getSubcatFreqs(subcat.scid, self._auth) + result = self._client.service.getSubcatFreqs(subcat.scid, + self._auth) self._freqs += result status.cur += 1 self.status_fn(status) @@ -85,7 +89,8 @@ print "Fetching category:", cat.cName for subcat in cat.subcats: print "\t", subcat.scName - result = self._client.service.getSubcatFreqs(subcat.scid, self._auth) + result = self._client.service.getSubcatFreqs(subcat.scid, + self._auth) self._freqs += result status.cur += 1 self.status_fn(status) @@ -126,7 +131,7 @@ else: try: tone, tmode = freq.tone.split(" ") - except: + except Exception: tone, tmode = None, None if tmode == "PL": mem.tmode = "TSQL" @@ -164,7 +169,9 @@ """ import sys rrr = RadioReferenceRadio(None) - rrr.set_params(zip=sys.argv[1], username=sys.argv[2], password=sys.argv[3]) + rrr.set_params(zipcode=sys.argv[1], + username=sys.argv[2], + password=sys.argv[3]) rrr.do_fetch() print rrr.get_raw_memory(0) print rrr.get_memory(0) diff -r db82df47f205 -r f805c420592f chirp/rfinder.py --- a/chirp/rfinder.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/rfinder.py Fri Apr 27 14:35:41 2012 -0700 @@ -17,7 +17,7 @@ import hashlib import re
-from math import pi,cos,acos,sin,atan2 +from math import pi, cos, acos, sin, atan2
from chirp import chirp_common, CHIRP_VERSION
@@ -48,46 +48,55 @@ ]
def deg2rad(deg): + """Convert degrees to radians""" return deg * (pi / 180)
def rad2deg(rad): + """Convert radians to degrees""" return rad / (pi / 180)
-def dm2deg(deg, min): - return deg + (min / 60.0) +def dm2deg(degrees, minutes): + """Convert degrees and minutes to decimal degrees""" + return degrees + (minutes / 60.0)
def deg2dm(decdeg): - deg = int(decdeg) - min = (decdeg - deg) * 60.0 + """Convert decimal degrees to degrees and minutes""" + degrees = int(decdeg) + minutes = (decdeg - degrees) * 60.0
- return deg, min + return degrees, minutes
-def nmea2deg(nmea, dir="N"): +def nmea2deg(nmea, direction="N"): + """Convert NMEA-encoded value to float""" deg = int(nmea) / 100 try: - min = nmea % (deg * 100) - except ZeroDivisionError, e: - min = int(nmea) + minutes = nmea % (deg * 100) + except ZeroDivisionError: + minutes = int(nmea)
- if dir == "S" or dir == "W": - m = -1 + if direction == "S" or direction == "W": + sign = -1 else: - m = 1 + sign = 1
- return dm2deg(deg, min) * m + return dm2deg(deg, minutes) * sign
def deg2nmea(deg): - deg, min = deg2dm(deg) + """Convert degrees to a NMEA-encoded value""" + degrees, minutes = deg2dm(deg)
- return (deg * 100) + min + return (degrees * 100) + minutes
def meters2feet(meters): + """Convert meters to feet""" return meters * 3.2808399
def feet2meters(feet): + """Convert feet to meters""" return feet * 0.3048
def distance(lat_a, lon_a, lat_b, lon_b): + """Calculate the distance between two points""" lat_a = deg2rad(lat_a) lon_a = deg2rad(lon_a)
@@ -108,30 +117,27 @@ elif tmp < -1: tmp = -1
- distance = acos(tmp) + dist = acos(tmp)
- return distance * earth_radius + return dist * earth_radius
def bearing(lat_a, lon_a, lat_b, lon_b): + """Calculate the bearing between two points""" lat_me = deg2rad(lat_a) - lon_me = deg2rad(lon_a) - lat_u = deg2rad(lat_b) - lon_u = deg2rad(lon_b) - - lat_d = deg2rad(lat_b - lat_a) lon_d = deg2rad(lon_b - lon_a)
- y = sin(lon_d) * cos(lat_u) - x = cos(lat_me) * sin(lat_u) - \ + posy = sin(lon_d) * cos(lat_u) + posx = cos(lat_me) * sin(lat_u) - \ sin(lat_me) * cos(lat_u) * cos(lon_d)
- bearing = rad2deg(atan2(y, x)) + bear = rad2deg(atan2(posy, posx))
- return (bearing + 360) % 360 + return (bear + 360) % 360
def fuzzy_to(lat_a, lon_a, lat_b, lon_b): - dir = bearing(lat_a, lon_a, lat_b, lon_b) + """Calculate a fuzzy distance to a point""" + bear = bearing(lat_a, lon_a, lat_b, lon_b)
dirs = ["N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", @@ -143,27 +149,29 @@
direction = "?" for i in dirs: - if dir > angle and dir < (angle + delta): + if bear > angle and bear < (angle + delta): direction = i angle += delta
return direction
class RFinderParser: + """Parser for RFinder's data format""" def __init__(self, lat, lon): self.__memories = [] self.__cheat = {} self.__lat = lat self.__lon = lon
- def fetch_data(self, user, pw, lat, lon, radius): + def fetch_data(self, user, pw, coords, radius): + """Fetches the data for a set of parameters""" print user print pw args = { "email" : urllib.quote_plus(user), "pass" : hashlib.md5(pw).hexdigest(), - "lat" : "%7.5f" % lat, - "lon" : "%8.5f" % lon, + "lat" : "%7.5f" % coords[0], + "lon" : "%8.5f" % coords[1], "radius": "%i" % radius, "vers" : "CH%s" % CHIRP_VERSION, } @@ -183,7 +191,7 @@
return data
- def parse_line(self, line): + def _parse_line(self, line): mem = chirp_common.Memory()
_vals = line.split("|") @@ -217,15 +225,16 @@ try: lat = float(vals["LATITUDE"]) lon = float(vals["LONGITUDE"]) - d = distance(self.__lat, self.__lon, lat, lon) - b = fuzzy_to(self.__lat, self.__lon, lat, lon) - mem.comment = "(%imi %s) %s" % (d, b, mem.comment) + dist = distance(self.__lat, self.__lon, lat, lon) + bear = fuzzy_to(self.__lat, self.__lon, lat, lon) + mem.comment = "(%imi %s) %s" % (dist, bear, mem.comment) except Exception, e: print "Failed to calculate distance: %s" % e
return mem
def parse_data(self, data): + """Parse the fetched data""" number = 1 for line in data.split("\n"): if line.startswith("<"): @@ -233,7 +242,7 @@ elif not line.strip(): continue try: - mem = self.parse_line(line) + mem = self._parse_line(line) mem.number = number number += 1 self.__memories.append(mem) @@ -247,23 +256,27 @@ print "\n\n"
def get_memories(self): + """Return the Memory objects associated with the fetched data""" return self.__memories
class RFinderRadio(chirp_common.NetworkSourceRadio): + """A network source radio that supports the RFinder repeater directory""" VENDOR = "ITWeRKS" MODEL = "RFinder"
def __init__(self, *args, **kwargs): - chirp_common.Radio.__init__(self, *args, **kwargs) + chirp_common.NetworkSourceRadio.__init__(self, *args, **kwargs)
self._lat = 0 self._lon = 0 self._user = "" self._pass = "" + self._miles = 25
self._rfp = None
- def set_params(self, lat, lon, miles, email, password): + def set_params(self, (lat, lon), miles, email, password): + """Sets the parameters to use for the query""" self._lat = lat self._lon = lon self._miles = miles @@ -275,8 +288,7 @@
self._rfp.parse_data(self._rfp.fetch_data(self._user, self._pass, - self._lat, - self._lon, + (self._lat, self._lon), self._miles))
def get_features(self): @@ -297,12 +309,14 @@
return self._rfp.get_memories()[number-1]
-if __name__ == "__main__": - import sys - +def _test(): rfp = RFinderParser() - data = rfp.fetch_data(45.525, -122.9164, "KK7DS", "dsmith@danplanet.com") + data = rfp.fetch_data("KK7DS", "dsmith@danplanet.com", + (45.5, -122.91), 25) rfp.parse_data(data)
- for m in rfp.get_memories(): - print m + for mem in rfp.get_memories(): + print mem + +if __name__ == "__main__": + _test() diff -r db82df47f205 -r f805c420592f chirp/settings.py --- a/chirp/settings.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/settings.py Fri Apr 27 14:35:41 2012 -0700 @@ -16,25 +16,31 @@ from chirp import chirp_common
class InvalidValueError(Exception): + """An invalid value was specified for a given setting""" pass
class InternalError(Exception): + """A driver provided an invalid settings object structure""" pass
class RadioSettingValue: + """Base class for a single radio setting""" def __init__(self): self._current = None self._has_changed = False
def changed(self): + """Returns True if the setting has been changed since init""" return self._has_changed
def set_value(self, value): + """Sets the current value, triggers changed""" if self._current != None and value != self._current: self._has_changed = True self._current = value
def get_value(self): + """Gets the current value""" return self._current
def __trunc__(self): @@ -44,10 +50,11 @@ return str(self.get_value())
class RadioSettingValueInteger(RadioSettingValue): - def __init__(self, min, max, current, step=1): + """An integer setting""" + def __init__(self, minval, maxval, current, step=1): RadioSettingValue.__init__(self) - self._min = min - self._max = max + self._min = minval + self._max = maxval self._step = step self.set_value(current)
@@ -63,15 +70,19 @@ RadioSettingValue.set_value(self, value)
def get_min(self): + """Returns the minimum allowed value""" return self._min
def get_max(self): + """Returns the maximum allowed value""" return self._max
def get_step(self): + """Returns the step increment""" return self._step
class RadioSettingValueBoolean(RadioSettingValue): + """A boolean setting""" def __init__(self, current): RadioSettingValue.__init__(self) self.set_value(current) @@ -83,6 +94,7 @@ return str(bool(self.get_value()))
class RadioSettingValueList(RadioSettingValue): + """A list-of-strings setting""" def __init__(self, options, current): RadioSettingValue.__init__(self) self._options = options @@ -94,12 +106,14 @@ RadioSettingValue.set_value(self, value)
def get_options(self): + """Returns the list of valid option values""" return self._options
def __trunc__(self): return self._options.index(self._current)
class RadioSettingValueString(RadioSettingValue): + """A string setting""" def __init__(self, minlength, maxlength, current, autopad=True): RadioSettingValue.__init__(self) @@ -110,6 +124,7 @@ self.set_value(current)
def set_charset(self, charset): + """Sets the set of allowed characters""" self._charset = charset
def set_value(self, value): @@ -128,6 +143,7 @@ return self._current.rstrip()
class RadioSettingGroup(object): + """A group of settings""" def _validate(self, element): # RadioSettingGroup can only contain RadioSettingGroup objects if not isinstance(element, RadioSettingGroup): @@ -146,37 +162,43 @@ self.append(element)
def get_name(self): + """Returns the group name""" return self._name
def get_shortname(self): + """Returns the short group identifier""" return self._shortname
def set_doc(self, doc): + """Sets the docstring for the group""" self.__doc__ = doc
def __str__(self): - s = "{Settings Group %s:\n" % self._name + string = "{Settings Group %s:\n" % self._name for element in self._elements.values(): - s += str(element) + "\n" - s += "}" - return s + string += str(element) + "\n" + string += "}" + return string
# Kinda list interface
def append(self, element): + """Adds an element to the group""" self[element.get_name()] = element
def __iter__(self): class RSGIterator: + """Iterator for a RadioSettingsGroup""" def __init__(self, rsg): self.__rsg = rsg self.__i = 0 def __iter__(self): return self def next(self): - if self.__i >= len(self.__rsg._element_order): + """Next Iterator Interface""" + if self.__i >= len(self.__rsg.keys()): raise StopIteration() - e = self.__rsg._elements[self.__rsg._element_order[self.__i]] + e = self.__rsg[self.__rsg.keys()[self.__i]] self.__i += 1 return e return RSGIterator(self) @@ -196,21 +218,26 @@ self._element_order.append(name)
def items(self): + """Returns a key=>value set of elements, like a dict""" return [(name, self._elements[name]) for name in self._element_order]
def keys(self): + """Returns a list of string element names""" return self._element_order
def values(self): - return [self.elements[name] for name in self._element_order] + """Returns the list of elements""" + return [self._elements[name] for name in self._element_order]
class RadioSetting(RadioSettingGroup): + """A single setting, which could be an array of items like a group""" def _validate(self, value): # RadioSetting can only contain RadioSettingValue objects if not isinstance(value, RadioSettingValue): raise InternalError("Incorrect type")
def changed(self): + """Returns True if any of the elements in the group have been changed""" for element in self._elements.values(): if element.changed(): return True diff -r db82df47f205 -r f805c420592f chirp/template.py --- a/chirp/template.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/template.py Fri Apr 27 14:35:41 2012 -0700 @@ -13,7 +13,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
-from chirp import chirp_common, yaesu_clone, util, directory, memmap +from chirp import chirp_common, directory, memmap from chirp import bitwise
# Here is where we define the memory map for the radio. Since @@ -24,7 +24,7 @@ # With some very basic settings, a 32-bit unsigned integer for the # frequency (in Hertz) and an eight-character alpha tag # -mem_format = """ +MEM_FORMAT = """ #seekto 0x0000; struct { u32 freq; @@ -33,6 +33,7 @@ """
def do_download(radio): + """This is your download function""" # NOTE: Remove this in your real implementation! return memmap.MemoryMap("\x00" * 1000)
@@ -43,12 +44,13 @@ # from the serial port. Do that one byte at a time and # store them in the memory map data = "" - for i in range(0, 1000): + for _i in range(0, 1000): data = serial.read(1)
return memmap.MemoryMap(data)
def do_upload(radio): + """This is your upload function""" # NOTE: Remove this in your real implementation! raise Exception("This template driver does not really work!")
@@ -59,11 +61,12 @@ # to the serial port. Do that one byte at a time, reading # from our memory map for i in range(0, 1000): - serial.write(radio._mmap[i]) + serial.write(radio.get_mmap()[i])
# Uncomment this to actually register this radio in CHIRP # @directory.register class TemplateRadio(chirp_common.CloneModeRadio): + """Acme Template""" VENDOR = "Acme" # Replace this with your vendor MODEL = "Template" # Replace this with your model BAUD_RATE = 9600 # Replace this with your baud rate @@ -82,7 +85,7 @@ # Do a download of the radio from the serial port def sync_in(self): self._mmap = do_download(self) - self._memobj = bitwise.parse(mem_format, self._mmap) + self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
# Do an upload of the radio to the serial port def sync_out(self): diff -r db82df47f205 -r f805c420592f chirp/util.py --- a/chirp/util.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/util.py Fri Apr 27 14:35:41 2012 -0700 @@ -16,6 +16,7 @@ import struct
def hexprint(data): + """Return a hexdump-like encoding of @data""" line_sz = 8
lines = len(data) / line_sz @@ -52,10 +53,8 @@
return out
-def write_in_place(mem, start, data): - return mem[:start] + data + mem[start+len(data):] - def bcd_encode(val, bigendian=True, width=None): + """This is really old and shouldn't be used anymore""" digits = [] while val != 0: digits.append(val % 10) @@ -78,8 +77,9 @@
return result
-def get_dict_rev(dict, key): +def get_dict_rev(thedict, value): + """Return the first matching key for a given @value in @dict""" _dict = {} - for k,v in dict.items(): + for k, v in thedict.items(): _dict[v] = k - return _dict[key] + return _dict[value] diff -r db82df47f205 -r f805c420592f chirp/uv5r.py --- a/chirp/uv5r.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/uv5r.py Fri Apr 27 14:35:41 2012 -0700 @@ -15,11 +15,13 @@
import struct
-from chirp import chirp_common, errors, util, directory, memmap, settings +from chirp import chirp_common, errors, util, directory, memmap from chirp import bitwise -from chirp.settings import * +from chirp.settings import RadioSetting, RadioSettingGroup, \ + RadioSettingValueInteger, RadioSettingValueList, \ + RadioSettingValueList, RadioSettingValueBoolean
-mem_format = """ +MEM_FORMAT = """ #seekto 0x0008; struct { lbcd rxfreq[4]; @@ -83,31 +85,31 @@ """
STEPS = [2.5, 5.0, 6.25, 10.0, 12.5, 25.0] -step_list = [str(x) for x in STEPS] -timeout_list = ["%s sec" % x for x in range(15, 615, 15)] -resume_list = ["TO", "CO", "SE"] -mode_list = ["Channel", "Name", "Frequency"] -color_list = ["Off", "Blue", "Orange", "Purple"] +STEP_LIST = [str(x) for x in STEPS] +TIMEOUT_LIST = ["%s sec" % x for x in range(15, 615, 15)] +RESUME_LIST = ["TO", "CO", "SE"] +MODE_LIST = ["Channel", "Name", "Frequency"] +COLOR_LIST = ["Off", "Blue", "Orange", "Purple"]
SETTING_LISTS = { - "step" : step_list, - "timeout" : timeout_list, - "screv" : resume_list, - "mdfa" : mode_list, - "mdfb" : mode_list, - "wtled" : color_list, - "rxled" : color_list, - "txled" : color_list, + "step" : STEP_LIST, + "timeout" : TIMEOUT_LIST, + "screv" : RESUME_LIST, + "mdfa" : MODE_LIST, + "mdfb" : MODE_LIST, + "wtled" : COLOR_LIST, + "rxled" : COLOR_LIST, + "txled" : COLOR_LIST, }
-def do_status(radio, block): - s = chirp_common.Status() - s.msg = "Cloning" - s.cur = block - s.max = radio._memsize - radio.status_fn(s) +def _do_status(radio, block): + status = chirp_common.Status() + status.msg = "Cloning" + status.cur = block + status.max = radio.get_memsize() + radio.status_fn(status)
-def do_ident(radio): +def _do_ident(radio): serial = radio.pipe serial.setTimeout(1)
@@ -130,12 +132,12 @@
return ident
-def do_download(radio): +def _do_download(radio): serial = radio.pipe
- data = do_ident(radio) + data = _do_ident(radio)
- for i in range(0, radio._memsize - 0x08, 0x40): + for i in range(0, radio.get_memsize() - 0x08, 0x40): msg = struct.pack(">BHB", ord("S"), i, 0x40) serial.write(msg)
@@ -162,23 +164,23 @@ if ack != "\x06": raise errors.RadioError("Radio refused to send block 0x%04x" % i)
- do_status(radio, i) + _do_status(radio, i)
return memmap.MemoryMap(data)
-def do_upload(radio): +def _do_upload(radio): serial = radio.pipe
- do_ident(radio) + _do_ident(radio)
- for i in range(0x08, radio._memsize, 0x10): + for i in range(0x08, radio.get_memsize(), 0x10): msg = struct.pack(">BHB", ord("X"), i - 0x08, 0x10) - serial.write(msg + radio._mmap[i:i+0x10]) + serial.write(msg + radio.get_mmap()[i:i+0x10])
ack = serial.read(1) if ack != "\x06": raise errors.RadioError("Radio refused to accept block 0x%04x" % i) - do_status(radio, i) + _do_status(radio, i)
UV5R_POWER_LEVELS = [chirp_common.PowerLevel("High", watts=4.00), chirp_common.PowerLevel("Low", watts=1.00)] @@ -186,6 +188,7 @@ # Uncomment this to actually register this radio in CHIRP @directory.register class BaofengUV5R(chirp_common.CloneModeRadio): + """Baofeng UV-5R""" VENDOR = "Baofeng" MODEL = "UV-5R" BAUD_RATE = 9600 @@ -212,12 +215,12 @@ return rf
def process_mmap(self): - self._memobj = bitwise.parse(mem_format, self._mmap) + self._memobj = bitwise.parse(MEM_FORMAT, self._mmap) print self.get_settings()
def sync_in(self): try: - self._mmap = do_download(self) + self._mmap = _do_download(self) except errors.RadioError: raise except Exception, e: @@ -226,7 +229,7 @@
def sync_out(self): try: - do_upload(self) + _do_upload(self) except errors.RadioError: raise except Exception, e: @@ -387,81 +390,81 @@ advanced = RadioSettingGroup("advanced", "Advanced Settings") group = RadioSettingGroup("top", "All Settings", basic, advanced)
- s = RadioSetting("squelch", "Carrier Squelch Level", - RadioSettingValueInteger(0, 9, _settings.squelch)) - basic.append(s) + rs = RadioSetting("squelch", "Carrier Squelch Level", + RadioSettingValueInteger(0, 9, _settings.squelch)) + basic.append(rs)
- s = RadioSetting("step", "Tuning Step", - RadioSettingValueList(step_list, - step_list[_settings.step])) - advanced.append(s) + rs = RadioSetting("step", "Tuning Step", + RadioSettingValueList(STEP_LIST, + STEP_LIST[_settings.step])) + advanced.append(rs)
- s = RadioSetting("save", "Battery Saver", - RadioSettingValueInteger(0, 4, _settings.save)) - basic.append(s) + rs = RadioSetting("save", "Battery Saver", + RadioSettingValueInteger(0, 4, _settings.save)) + basic.append(rs)
- s = RadioSetting("vox", "VOX Sensitivity", - RadioSettingValueInteger(0, 10, _settings.vox)) - advanced.append(s) + rs = RadioSetting("vox", "VOX Sensitivity", + RadioSettingValueInteger(0, 10, _settings.vox)) + advanced.append(rs)
- s = RadioSetting("abr", "Backlight Timeout", - RadioSettingValueInteger(0, 5, _settings.abr)) - basic.append(s) + rs = RadioSetting("abr", "Backlight Timeout", + RadioSettingValueInteger(0, 5, _settings.abr)) + basic.append(rs)
- s = RadioSetting("tdr", "Dual Watch", - RadioSettingValueBoolean(_settings.tdr)) - advanced.append(s) + rs = RadioSetting("tdr", "Dual Watch", + RadioSettingValueBoolean(_settings.tdr)) + advanced.append(rs)
- s = RadioSetting("beep", "Beep", - RadioSettingValueBoolean(_settings.beep)) - basic.append(s) + rs = RadioSetting("beep", "Beep", + RadioSettingValueBoolean(_settings.beep)) + basic.append(rs)
- s = RadioSetting("timeout", "Timeout Timer", - RadioSettingValueList(timeout_list, - timeout_list[_settings.tdr])) - basic.append(s) + rs = RadioSetting("timeout", "Timeout Timer", + RadioSettingValueList(TIMEOUT_LIST, + TIMEOUT_LIST[_settings.tdr])) + basic.append(rs)
- s = RadioSetting("voice", "Voice", - RadioSettingValueBoolean(_settings.voice)) - advanced.append(s) + rs = RadioSetting("voice", "Voice", + RadioSettingValueBoolean(_settings.voice)) + advanced.append(rs)
- s = RadioSetting("screv", "Scan Resume", - RadioSettingValueList(resume_list, - resume_list[_settings.screv])) - advanced.append(s) + rs = RadioSetting("screv", "Scan Resume", + RadioSettingValueList(RESUME_LIST, + RESUME_LIST[_settings.screv])) + advanced.append(rs)
- s = RadioSetting("mdfa", "Display Mode (A)", - RadioSettingValueList(mode_list, - mode_list[_settings.mdfa])) - basic.append(s) + rs = RadioSetting("mdfa", "Display Mode (A)", + RadioSettingValueList(MODE_LIST, + MODE_LIST[_settings.mdfa])) + basic.append(rs)
- s = RadioSetting("mdfb", "Display Mode (B)", - RadioSettingValueList(mode_list, - mode_list[_settings.mdfb])) - basic.append(s) + rs = RadioSetting("mdfb", "Display Mode (B)", + RadioSettingValueList(MODE_LIST, + MODE_LIST[_settings.mdfb])) + basic.append(rs)
- s = RadioSetting("bcl", "Busy Channel Lockout", - RadioSettingValueBoolean(_settings.bcl)) - advanced.append(s) + rs = RadioSetting("bcl", "Busy Channel Lockout", + RadioSettingValueBoolean(_settings.bcl)) + advanced.append(rs)
- s = RadioSetting("autolk", "Automatic Key Lock", - RadioSettingValueBoolean(_settings.autolk)) - advanced.append(s) + rs = RadioSetting("autolk", "Automatic Key Lock", + RadioSettingValueBoolean(_settings.autolk)) + advanced.append(rs)
- s = RadioSetting("wtled", "Standby LED Color", - RadioSettingValueList(color_list, - color_list[_settings.wtled])) - basic.append(s) + rs = RadioSetting("wtled", "Standby LED Color", + RadioSettingValueList(COLOR_LIST, + COLOR_LIST[_settings.wtled])) + basic.append(rs)
- s = RadioSetting("rxled", "RX LED Color", - RadioSettingValueList(color_list, - color_list[_settings.rxled])) - basic.append(s) + rs = RadioSetting("rxled", "RX LED Color", + RadioSettingValueList(COLOR_LIST, + COLOR_LIST[_settings.rxled])) + basic.append(rs)
- s = RadioSetting("txled", "TX LED Color", - RadioSettingValueList(color_list, - color_list[_settings.txled])) - basic.append(s) + rs = RadioSetting("txled", "TX LED Color", + RadioSettingValueList(COLOR_LIST, + COLOR_LIST[_settings.txled])) + basic.append(rs)
return group
@@ -471,9 +474,6 @@ if not isinstance(element, RadioSetting): self.set_settings(element) continue - - if element.get_name() in SETTING_LISTS.keys(): - value = SETTING_LISTS[element.get_name()].index(str(element.value)) try: setattr(_settings, element.get_name(), element.value) except Exception, e: diff -r db82df47f205 -r f805c420592f chirp/vx3.py --- a/chirp/vx3.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/vx3.py Fri Apr 27 14:35:41 2012 -0700 @@ -14,7 +14,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
-from chirp import chirp_common, yaesu_clone, util, directory +from chirp import chirp_common, yaesu_clone, directory from chirp import bitwise
#interesting offsets which may be checksums needed later @@ -23,7 +23,7 @@ #0x0409 checksum2? #0x04C9 checksum2a?
-mem_format = """ +MEM_FORMAT = """ #seekto 0x7F4A; u8 checksum;
@@ -93,6 +93,7 @@ chirp_common.PowerLevel("Low", watts=0.10)]
class VX3Bank(chirp_common.NamedBank): + """A VX3 Bank""" def get_name(self): _bank = self._model._radio._memobj.bank_names[self.index] name = "" @@ -108,6 +109,7 @@ _bank.name = [CHARSET.index(x) for x in name.ljust(6)[:6]]
class VX3BankModel(chirp_common.BankModel): + """A VX-3 bank model""" def get_num_banks(self): return 24
@@ -121,8 +123,18 @@ banks.append(bank) return banks
+def _wipe_memory(mem): + mem.set_raw("\x00" * (mem.size() / 8)) + #the following settings are set to match the defaults + #on the radio, some of these fields are unknown + mem.name = [0xFF for _i in range(0, 6)] + mem.unknown5 = 0x0D #not sure what this is + mem.unknown7 = 0x01 #this likely is part of autostep + mem.automode = 0x01 #autoselect mode + @directory.register class VX3Radio(yaesu_clone.YaesuCloneModeRadio): + """Yaesu VX-3""" BAUD_RATE = 19200 VENDOR = "Yaesu" MODEL = "VX-3" @@ -139,7 +151,7 @@ return [ yaesu_clone.YaesuChecksum(0x0000, 0x7F49) ]
def process_mmap(self): - self._memobj = bitwise.parse(mem_format, self._mmap) + self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
def get_features(self): rf = chirp_common.RadioFeatures() @@ -169,7 +181,7 @@
nibble = ((number-1) % 2) and "even" or "odd" used = _flag["%s_masked" % nibble] - valid =_flag["%s_valid" % nibble] + valid = _flag["%s_valid" % nibble] pskip = _flag["%s_pskip" % nibble] skip = _flag["%s_skip" % nibble]
@@ -203,16 +215,6 @@ mem.name = mem.name.rstrip() return mem
- def _wipe_memory(self, mem): - mem.set_raw("\x00" * (mem.size() / 8)) - #the following settings are set to match the defaults - #on the radio, some of these fields are unknown - mem.name = [0xFF for i in range(0, 6)] - mem.unknown5 = 0x0D #not sure what this is - mem.unknown7 = 0x01 #this likely is part of autostep - mem.automode = 0x01 #autoselect mode - - def set_memory(self, mem): _mem = self._memobj.memory[mem.number-1] _flag = self._memobj.flags[(mem.number-1)/2] @@ -223,7 +225,7 @@ valid = _flag["%s_valid" % nibble]
if not mem.empty and not valid: - self._wipe_memory(_mem) + _wipe_memory(_mem)
if mem.empty and valid and not used: _flag["%s_valid" % nibble] = False @@ -251,7 +253,8 @@
for i in range(0, 6): _mem.name[i] = CHARSET.index(mem.name.ljust(6)[i]) - if mem.name.strip(): _mem.name[0] |= 0x80 + if mem.name.strip(): + _mem.name[0] |= 0x80
def validate_memory(self, mem): msgs = yaesu_clone.YaesuCloneModeRadio.validate_memory(self, mem) diff -r db82df47f205 -r f805c420592f chirp/vx5.py --- a/chirp/vx5.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/vx5.py Fri Apr 27 14:35:41 2012 -0700 @@ -14,10 +14,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
-from chirp import chirp_common, yaesu_clone, util, directory +from chirp import chirp_common, yaesu_clone, directory from chirp import bitwise
-mem_format = """ +MEM_FORMAT = """ #seekto 0x012A; struct { u8 zeros:4, @@ -67,6 +67,7 @@
@directory.register class VX5Radio(yaesu_clone.YaesuCloneModeRadio): + """Yaesu VX-5""" BAUD_RATE = 9600 VENDOR = "Yaesu" MODEL = "VX-5" @@ -97,7 +98,7 @@ return rf
def process_mmap(self): - self._memobj = bitwise.parse(mem_format, self._mmap) + self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
def get_raw_memory(self, number): return repr(self._memobj.memory[number-1]) diff -r db82df47f205 -r f805c420592f chirp/vx6.py --- a/chirp/vx6.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/vx6.py Fri Apr 27 14:35:41 2012 -0700 @@ -27,14 +27,15 @@ # cpu_shifted: CPU freq has been shifted (to move a birdie out of channel) # power: 0-3: ["L1", "L2", "L3", "Hi"] # pager: Set if this is a paging memory -# tmodes: 0-7: ["", "Tone", "TSQL", "DTCS", "Rv Tn", "D Code", "T DCS", "D Tone"] +# tmodes: 0-7: ["", "Tone", "TSQL", "DTCS", "Rv Tn", "D Code", +# "T DCS", "D Tone"] # Rv Tn: Reverse CTCSS - mutes receiver on tone # The final 3 are for split: # D Code: DCS Encode only # T DCS: Encodes tone, decodes DCS code # D Tone: Encodes DCS code, decodes tone # } -mem_format = """ +MEM_FORMAT = """ #seekto 0x018A; u16 bank_sizes[24];
@@ -110,6 +111,7 @@
@directory.register class VX6Radio(yaesu_clone.YaesuCloneModeRadio): + """Yaesu VX-6""" BAUD_RATE = 19200 VENDOR = "Yaesu" MODEL = "VX-6" @@ -123,7 +125,7 @@ return [ yaesu_clone.YaesuChecksum(0x0000, 0x7F49) ]
def process_mmap(self): - self._memobj = bitwise.parse(mem_format, self._mmap) + self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
def get_features(self): rf = chirp_common.RadioFeatures() @@ -225,35 +227,35 @@ _flag["%s_pskip" % nibble] = mem.skip == "P" _flag["%s_skip" % nibble] = mem.skip == "S"
- _mem.name == ("\xFF" * 6) + _mem.name = [0xFF] * 6 for i in range(0, 6): _mem.name[i] = CHARSET.index(mem.name.ljust(6)[i])
if mem.name.strip(): _mem.name[0] |= 0x80
- def get_banks(self): - _banks = self._memobj.bank_names +# def get_banks(self): +# _banks = self._memobj.bank_names +# +# banks = [] +# for bank in _banks: +# name = "" +# for i in bank.name: +# name += CHARSET[i & 0x7F] +# banks.append(name.rstrip()) +# +# return banks +# +# # Return channels for a bank. Bank given as number +# def get_bank_channels(self, bank): +# nchannels = 0 +# size = self._memobj.bank_sizes[bank] +# if size <= 198: +# nchannels = 1 + size/2 +# _channels = self._memobj.bank_channels[bank] +# channels = [] +# for i in range(0, nchannels): +# channels.append(int(_channels.channel[i])) +# +# return channels
- banks = [] - for bank in _banks: - name = "" - for i in bank.name: - name += CHARSET[i & 0x7F] - banks.append(name.rstrip()) - - return banks - - # Return channels for a bank. Bank given as number - def get_bank_channels(self, bank): - nchannels = 0 - size = self._memobj.bank_sizes[bank] - if size <= 198: - nchannels = 1 + size/2 - _channels = self._memobj.bank_channels[bank] - channels = [] - for i in range(0, nchannels): - channels.append(int(_channels.channel[i])) - - return channels - diff -r db82df47f205 -r f805c420592f chirp/vx7.py --- a/chirp/vx7.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/vx7.py Fri Apr 27 14:35:41 2012 -0700 @@ -13,10 +13,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/.
-from chirp import chirp_common, yaesu_clone, util, directory +from chirp import chirp_common, yaesu_clone, directory from chirp import bitwise
-mem_format = """ +MEM_FORMAT = """ #seekto 0x0611; u8 checksum1;
@@ -96,6 +96,7 @@ chirp_common.PowerLevel("L1", watts=0.05)]
class VX7BankModel(chirp_common.BankModel): + """A VX-7 Bank model""" def get_num_banks(self): return 9
@@ -130,8 +131,8 @@ remaining_members += 1
if not found: - raise Exception(_("Memory {num} not in " - "bank {bank}").format(num=memory.number, + raise Exception("Memory {num} not in " + + "bank {bank}".format(num=memory.number, bank=bank)) if not remaining_members: _bank_used.in_use = 0xFFFF @@ -154,12 +155,19 @@ def get_memory_banks(self, memory): banks = [] for bank in self.get_banks(): - if memory.number in [x.number for x in self.get_bank_memories(bank)]: - banks.append(bank) + if memory.number in [x.number for x in + self.get_bank_memories(bank)]: + banks.append(bank) return banks
+def _wipe_memory(mem): + mem.set_raw("\x00" * (mem.size() / 8)) + mem.unknown1 = 0x05 + mem.ones = 0x03 + @directory.register class VX7Radio(yaesu_clone.YaesuCloneModeRadio): + """Yaesu VX-7""" BAUD_RATE = 19200 VENDOR = "Yaesu" MODEL = "VX-7" @@ -176,7 +184,7 @@ ]
def process_mmap(self): - self._memobj = bitwise.parse(mem_format, self._mmap) + self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
def get_features(self): rf = chirp_common.RadioFeatures() @@ -243,11 +251,6 @@
return mem
- def _wipe_memory(self, mem): - mem.set_raw("\x00" * (mem.size() / 8)) - mem.unknown1 = 0x05 - mem.ones = 0x03 - def set_memory(self, mem): _mem = self._memobj.memory[mem.number-1] _flag = self._memobj.flags[(mem.number-1)/2] @@ -258,7 +261,7 @@ used = _flag["%s_masked" % nibble]
if not mem.empty and not valid: - self._wipe_memory(_mem) + _wipe_memory(_mem) self._wipe_memory_banks(mem)
if mem.empty and valid and not used: @@ -294,7 +297,8 @@ if mem.freq >= 222000000 and mem.freq <= 225000000: if mem.power not in POWER_LEVELS_220: msgs.append(chirp_common.ValidationError(\ - "Power level %s not supported on 220MHz band" % mem.power)) + "Power level %s not supported on 220MHz band" % \ + mem.power))
return msgs
diff -r db82df47f205 -r f805c420592f chirp/vx8.py --- a/chirp/vx8.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/vx8.py Fri Apr 27 14:35:41 2012 -0700 @@ -16,7 +16,7 @@ from chirp import chirp_common, yaesu_clone, directory from chirp import bitwise
-mem_format = """ +MEM_FORMAT = """ #seekto 0x54a; struct { u16 in_use; @@ -88,6 +88,8 @@ chirp_common.PowerLevel("L1", watts=0.05)]
class VX8Bank(chirp_common.NamedBank): + """A VX-8 bank""" + def get_name(self): _bank = self._model._radio._memobj.bank_info[self.index] _bank_used = self._model._radio._memobj.bank_used[self.index] @@ -104,6 +106,7 @@ _bank.name = [CHARSET.index(x) for x in name.ljust(16)[:16]]
class VX8BankModel(chirp_common.BankModel): + """A VX-8 bank model""" def get_num_banks(self): return 24
@@ -172,8 +175,13 @@
return banks
+def _wipe_memory(mem): + mem.set_raw("\x00" * (mem.size() / 8)) + mem.unknown1 = 0x05 + @directory.register class VX8Radio(yaesu_clone.YaesuCloneModeRadio): + """Yaesu VX-8""" BAUD_RATE = 38400 VENDOR = "Yaesu" MODEL = "VX-8" @@ -185,7 +193,7 @@ _block_size = 32
def process_mmap(self): - self._memobj = bitwise.parse(mem_format, self._mmap) + self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
def get_features(self): rf = chirp_common.RadioFeatures() @@ -242,10 +250,6 @@
return mem
- def _wipe_memory(self, mem): - mem.set_raw("\x00" * (mem.size() / 8)) - mem.unknown1 = 0x05 - def _debank(self, mem): bm = self.get_bank_model() for bank in bm.get_memory_banks(mem): @@ -256,7 +260,7 @@ flag = self._memobj.flag[mem.number-1]
if not mem.empty and not flag.valid: - self._wipe_memory(_mem) + _wipe_memory(_mem)
if mem.empty and flag.valid and not flag.used: flag.valid = False @@ -300,5 +304,6 @@
@directory.register class VX8DRadio(VX8Radio): + """Yaesu VX-8DR""" _model = "AH29D" VARIANT = "DR" diff -r db82df47f205 -r f805c420592f chirp/vxa700.py --- a/chirp/vxa700.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/vxa700.py Fri Apr 27 14:35:41 2012 -0700 @@ -19,21 +19,21 @@ import time import struct
-def debug(string): +def _debug(string): pass print string
-def send(radio, data): - debug("Sending %s" % repr(data)) +def _send(radio, data): + _debug("Sending %s" % repr(data)) radio.pipe.write(data) radio.pipe.flush() echo = radio.pipe.read(len(data)) if len(echo) != len(data): raise errors.RadioError("Invalid echo")
-def spoonfeed(radio, data): - count = 0 - debug("Writing %i:\n%s" % (len(data), util.hexprint(data))) +def _spoonfeed(radio, data): + #count = 0 + _debug("Writing %i:\n%s" % (len(data), util.hexprint(data))) for byte in data: radio.pipe.write(byte) radio.pipe.flush() @@ -45,12 +45,12 @@ if echo != byte: print "%02x != %02x" % (ord(echo), ord(byte)) raise errors.RadioError("No echo?") - count += 1 + #count += 1
-def download(radio): +def _download(radio): count = 0 data = "" - while len(data) < radio._memsize: + while len(data) < radio.get_memsize(): count += 1 chunk = radio.pipe.read(133) if len(chunk) == 0 and len(data) == 0 and count < 30: @@ -58,10 +58,9 @@ if len(chunk) != 132: raise errors.RadioError("Got short block (length %i)" % len(chunk))
- flag, length, block = struct.unpack("BBB", chunk[:3]) checksum = ord(chunk[-1]) - - flag, length, block, _data, checksum = struct.unpack("BBB128sB", chunk) + _flag, _length, _block, _data, checksum = \ + struct.unpack("BBB128sB", chunk)
cs = 0 for byte in chunk[:-1]: @@ -70,32 +69,31 @@ raise errors.RadioError("Invalid checksum at 0x%02x" % len(data))
data += _data - send(radio, "\x06") + _send(radio, "\x06")
if radio.status_fn: status = chirp_common.Status() status.msg = "Cloning from radio" status.cur = len(data) - status.max = radio._memsize + status.max = radio.get_memsize() radio.status_fn(status)
return memmap.MemoryMap(data)
-def upload(radio): - for i in range(0, radio._memsize, 128): - chunk = radio._mmap[i:i+128] +def _upload(radio): + for i in range(0, radio.get_memsize(), 128): + chunk = radio.get_mmap()[i:i+128] cs = 0x20 + 130 + (i / 128) for byte in chunk: cs += ord(byte) - spoonfeed(radio, - struct.pack("BBB128sB", - 0x20, - 130, - i / 128, - chunk, - cs % 256)) + _spoonfeed(radio, + struct.pack("BBB128sB", + 0x20, + 130, + i / 128, + chunk, + cs % 256)) radio.pipe.write("") - start = time.time() # This is really unreliable for some reason, so just # blindly proceed # ack = radio.pipe.read(1) @@ -109,10 +107,10 @@ status = chirp_common.Status() status.msg = "Cloning to radio" status.cur = i - status.max = radio._memsize + status.max = radio.get_memsize() radio.status_fn(status)
-mem_format = """ +MEM_FORMAT = """ struct memory_struct { u8 unknown1; u8 unknown2:2, @@ -158,19 +156,24 @@ chirp_common.PowerLevel("Low3", watts=2.500), chirp_common.PowerLevel("High", watts=5.000)]
+def _wipe_memory(_mem): + _mem.set_raw("\x00" * (_mem.size() / 8)) + @directory.register class VXA700Radio(chirp_common.CloneModeRadio): + """Vertex Standard VXA-700""" VENDOR = "Vertex Standard" MODEL = "VXA-700" _memsize = 4096
def sync_in(self): try: - self._mmap = download(self) + self._mmap = _download(self) except errors.RadioError: raise except Exception, e: - raise errors.RadioError("Failed to communicate with the radio: %s" % e) + raise errors.RadioError("Failed to communicate " + + "with the radio: %s" % e) self.process_mmap()
def sync_out(self): @@ -180,14 +183,15 @@ # 0x02 <- air band only try: self.pipe.setTimeout(2) - upload(self) + _upload(self) except errors.RadioError: raise except Exception, e: - raise errors.RadioError("Failed to communicate with the radio: %s" % e) + raise errors.RadioError("Failed to communicate " + + "with the radio: %s" % e)
def process_mmap(self): - self._memobj = bitwise.parse(mem_format, self._mmap) + self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
def get_features(self): rf = chirp_common.RadioFeatures() @@ -203,7 +207,7 @@ rf.valid_tuning_steps = [5.0, 10.0, 12.5, 15.0, 20.0, 25.0, 50.0, 100.0] rf.valid_modes = ["AM", "FM"] rf.valid_power_levels = POWER - rf.memory_bounds = (1,100) + rf.memory_bounds = (1, 100) return rf
def _get_mem(self, number): @@ -215,8 +219,8 @@
def get_memory(self, number): _mem = self._get_mem(number) - byte = (number - 1) / 8; - bit = 1 << ((number - 1) % 8); + byte = (number - 1) / 8 + bit = 1 << ((number - 1) % 8)
mem = chirp_common.Memory() mem.number = number @@ -251,13 +255,10 @@
return mem
- def _wipe_memory(self, _mem): - _mem.set_raw("\x00" * (_mem.size() / 8)) - def set_memory(self, mem): _mem = self._get_mem(mem.number) - byte = (mem.number - 1) / 8; - bit = 1 << ((mem.number - 1) % 8); + byte = (mem.number - 1) / 8 + bit = 1 << ((mem.number - 1) % 8)
if mem.empty and self._memobj.invisible_bits[byte] & bit: self._memobj.invalid_bits[byte] |= bit @@ -267,7 +268,7 @@ return
if self._memobj.invalid_bits[byte] & bit: - self._wipe_memory(_mem) + _wipe_memory(_mem)
self._memobj.invisible_bits[byte] &= ~bit self._memobj.invalid_bits[byte] &= ~bit @@ -293,7 +294,7 @@ _mem.skip = mem.skip == "S" try: _mem.power = POWER.index(mem.power) - except: + except ValueError: _mem.power = 3 # High
for i in range(0, 8): diff -r db82df47f205 -r f805c420592f chirp/wouxun.py --- a/chirp/wouxun.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/wouxun.py Fri Apr 27 14:35:41 2012 -0700 @@ -23,7 +23,7 @@ else: DEBUG = False
-wouxun_mem_format = """ +WOUXUN_MEM_FORMAT = """ #seekto 0x0010; struct { lbcd rx_freq[4]; @@ -50,22 +50,24 @@ """
def wouxun_identify(radio): - for i in range(0, 5): + """Do the original wouxun identification dance""" + for _i in range(0, 5): radio.pipe.write("HiWOUXUN\x02") - r = radio.pipe.read(9) - if len(r) != 9: + resp = radio.pipe.read(9) + if len(resp) != 9: print "Retrying identification..." time.sleep(1) continue - if r[2:8] != radio._model: + if resp[2:8] != radio._model: raise Exception("I can't talk to this model") return - if len(r) == 0: + if len(resp) == 0: raise Exception("Radio not responding") else: raise Exception("Unable to identify radio")
def wouxun_start_transfer(radio): + """Tell the radio to go into transfer mode""" radio.pipe.write("\x02\x06") time.sleep(0.05) ack = radio.pipe.read(1) @@ -73,6 +75,7 @@ raise Exception("Radio refused transfer mode")
def do_download(radio, start, end, blocksize): + """Initiate a download of @radio between @start and @end""" image = "" for i in range(start, end, blocksize): cmd = struct.pack(">cHb", "R", i, blocksize) @@ -80,30 +83,32 @@ print util.hexprint(cmd) radio.pipe.write(cmd) length = len(cmd) + blocksize - r = radio.pipe.read(length) - if len(r) != (len(cmd) + blocksize): - print util.hexprint(r) - raise Exception("Failed to read full block (%i!=%i)" % (len(r), - len(cmd)+blocksize)) + resp = radio.pipe.read(length) + if len(resp) != (len(cmd) + blocksize): + print util.hexprint(resp) + raise Exception("Failed to read full block (%i!=%i)" % \ + (len(resp), + len(cmd) + blocksize))
radio.pipe.write("\x06") radio.pipe.read(1) - image += r[4:] + image += resp[4:]
if radio.status_fn: - s = chirp_common.Status() - s.cur = i - s.max = end - s.msg = "Cloning from radio" - radio.status_fn(s) + status = chirp_common.Status() + status.cur = i + status.max = end + status.msg = "Cloning from radio" + radio.status_fn(status)
return memmap.MemoryMap(image)
def do_upload(radio, start, end, blocksize): + """Initiate an upload of @radio between @start and @end""" ptr = start for i in range(start, end, blocksize): cmd = struct.pack(">cHb", "W", i, blocksize) - chunk = radio._mmap[ptr:ptr+blocksize] + chunk = radio.get_mmap()[ptr:ptr+blocksize] ptr += blocksize radio.pipe.write(cmd + chunk) if DEBUG: @@ -115,13 +120,14 @@ #radio.pipe.write(ack)
if radio.status_fn: - s = chirp_common.Status() - s.cur = i - s.max = end - s.msg = "Cloning to radio" - radio.status_fn(s) + status = chirp_common.Status() + status.cur = i + status.max = end + status.msg = "Cloning to radio" + radio.status_fn(status)
def wouxun_download(radio): + """Talk to an original wouxun and do a download""" try: wouxun_identify(radio) wouxun_start_transfer(radio) @@ -132,6 +138,7 @@ raise errors.RadioError("Failed to communicate with radio: %s" % e)
def wouxun_upload(radio): + """Talk to an original wouxun and do an upload""" try: wouxun_identify(radio) wouxun_start_transfer(radio) @@ -147,8 +154,12 @@ POWER_LEVELS = [chirp_common.PowerLevel("High", watts=5.00), chirp_common.PowerLevel("Low", watts=1.00)]
+def wipe_memory(_mem, byte): + _mem.set_raw(byte * (_mem.size() / 8)) + @directory.register class KGUVD1PRadio(chirp_common.CloneModeRadio): + """Wouxun KG-UVD1P,UV2,UV3""" VENDOR = "Wouxun" MODEL = "KG-UVD1P" _model = "KG669V" @@ -172,7 +183,7 @@ # format, padding 16 bytes of 0xFF in front. self._mmap = memmap.MemoryMap(("\xFF" * 16) + \ self._mmap.get_packed()[8:8184]) - self._memobj = bitwise.parse(wouxun_mem_format, self._mmap) + self._memobj = bitwise.parse(WOUXUN_MEM_FORMAT, self._mmap)
def get_features(self): rf = chirp_common.RadioFeatures() @@ -194,14 +205,14 @@ def get_raw_memory(self, number): return repr(self._memobj.memory[number - 1])
- def get_tone(self, _mem, mem): - def get_dcs(val): + def _get_tone(self, _mem, mem): + def _get_dcs(val): code = int("%03o" % (val & 0x07FF)) pol = (val & 0x8000) and "R" or "N" return code, pol
if _mem.tx_tone != 0xFFFF and _mem.tx_tone > 0x2800: - tcode, tpol = get_dcs(_mem.tx_tone) + tcode, tpol = _get_dcs(_mem.tx_tone) mem.dtcs = tcode txmode = "DTCS" elif _mem.tx_tone != 0xFFFF: @@ -211,7 +222,7 @@ txmode = ""
if _mem.rx_tone != 0xFFFF and _mem.rx_tone > 0x2800: - rcode, rpol = get_dcs(_mem.rx_tone) + rcode, rpol = _get_dcs(_mem.rx_tone) mem.dtcs = rcode rxmode = "DTCS" elif _mem.rx_tone != 0xFFFF: @@ -268,7 +279,7 @@ if not _mem.iswide: mem.mode = "NFM"
- self.get_tone(_mem, mem) + self._get_tone(_mem, mem)
mem.power = POWER_LEVELS[not _mem.power_high]
@@ -279,11 +290,8 @@
return mem
- def wipe_memory(self, _mem, byte): - _mem.set_raw(byte * (_mem.size() / 8)) - - def set_tone(self, mem, _mem): - def set_dcs(code, pol): + def _set_tone(self, mem, _mem): + def _set_dcs(code, pol): val = int("%i" % code, 8) + 0x2800 if pol == "R": val += 0xA000 @@ -299,7 +307,7 @@
if tx_mode == "DTCS": - _mem.tx_tone = set_dcs(mem.dtcs, mem.dtcs_polarity[0]) + _mem.tx_tone = _set_dcs(mem.dtcs, mem.dtcs_polarity[0]) elif tx_mode: _mem.tx_tone = tx_mode == "Tone" and \ int(mem.rtone * 10) or int(mem.ctone * 10) @@ -307,7 +315,7 @@ _mem.tx_tone = 0xFFFF
if rx_mode == "DTCS": - _mem.rx_tone = set_dcs(mem.dtcs, mem.dtcs_polarity[1]) + _mem.rx_tone = _set_dcs(mem.dtcs, mem.dtcs_polarity[1]) elif rx_mode: _mem.rx_tone = int(mem.ctone * 10) else: @@ -322,11 +330,11 @@ _nam = self._memobj.names[mem.number - 1]
if mem.empty: - self.wipe_memory(_mem, "\xFF") + wipe_memory(_mem, "\xFF") return
if _mem.get_raw() == ("\xFF" * 16): - self.wipe_memory(_mem, "\x00") + wipe_memory(_mem, "\x00")
_mem.rx_freq = int(mem.freq / 10) if mem.duplex == "split": @@ -341,7 +349,7 @@ _mem.skip = mem.skip != "S" _mem.iswide = mem.mode != "NFM"
- self.set_tone(mem, _mem) + self._set_tone(mem, _mem)
if mem.power: _mem.power_high = not POWER_LEVELS.index(mem.power) @@ -386,7 +394,8 @@ raise Exception("Radio did not ACK ident")
def puxing_prep(radio): - for i in range(0, 10): + """Do the Puxing PX-777 identification dance""" + for _i in range(0, 10): try: return _puxing_prep(radio) except Exception, e: @@ -395,6 +404,7 @@ raise e
def puxing_download(radio): + """Talk to a Puxing PX-777 and do a download""" try: puxing_prep(radio) return do_download(radio, 0x0000, 0x0C60, 0x0008) @@ -404,6 +414,7 @@ raise errors.RadioError("Failed to communicate with radio: %s" % e)
def puxing_upload(radio): + """Talk to a Puxing PX-777 and do an upload""" try: puxing_prep(radio) return do_upload(radio, 0x0000, 0x0C40, 0x0008) @@ -412,7 +423,7 @@ except Exception, e: raise errors.RadioError("Failed to communicate with radio: %s" % e)
-puxing_mem_format = """ +PUXING_MEM_FORMAT = """ #seekto 0x0000; struct { lbcd rx_freq[4]; @@ -477,6 +488,7 @@
@directory.register class Puxing777Radio(KGUVD1PRadio): + """Puxing PX-777""" VENDOR = "Puxing" MODEL = "PX-777"
@@ -513,7 +525,7 @@ return rf
def process_mmap(self): - self._memobj = bitwise.parse(puxing_mem_format, self._mmap) + self._memobj = bitwise.parse(PUXING_MEM_FORMAT, self._mmap)
@classmethod def match_model(cls, filedata, filename): @@ -526,16 +538,16 @@ _mem = self._memobj.memory[number - 1] _nam = self._memobj.names[number - 1]
- def is_empty(): - for i in range(0,4): + def _is_empty(): + for i in range(0, 4): if _mem.rx_freq[i].get_raw() != "\xFF": return False return True
- def is_no_tone(field): + def _is_no_tone(field): return field[0].get_raw() == "\xFF"
- def get_dtcs(value): + def _get_dtcs(value): # Upper nibble 0x80 -> DCS, 0xC0 -> Inv. DCS if value > 12000: return "R", value - 12000 @@ -544,19 +556,19 @@ else: raise Exception("Unable to convert DCS value")
- def do_dtcs(mem, txfield, rxfield): + def _do_dtcs(mem, txfield, rxfield): if int(txfield) < 8000 or int(rxfield) < 8000: raise Exception("Split tone not supported")
if txfield[0].get_raw() == "\xFF": tp, tx = "N", None else: - tp, tx = get_dtcs(int(txfield)) + tp, tx = _get_dtcs(int(txfield))
if rxfield[0].get_raw() == "\xFF": rp, rx = "N", None else: - rp, rx = get_dtcs(int(rxfield)) + rp, rx = _get_dtcs(int(rxfield))
if not rx: rx = tx @@ -572,7 +584,7 @@ mem = chirp_common.Memory() mem.number = number
- if is_empty(): + if _is_empty(): mem.empty = True return mem
@@ -588,15 +600,15 @@ if not _mem.iswide: mem.mode = "NFM"
- if is_no_tone(_mem.tx_tone): + if _is_no_tone(_mem.tx_tone): pass # No tone elif int(_mem.tx_tone) > 8000 or \ - (not is_no_tone(_mem.rx_tone) and int(_mem.rx_tone) > 8000): + (not _is_no_tone(_mem.rx_tone) and int(_mem.rx_tone) > 8000): mem.tmode = "DTCS" - do_dtcs(mem, _mem.tx_tone, _mem.rx_tone) + _do_dtcs(mem, _mem.tx_tone, _mem.rx_tone) else: mem.rtone = int(_mem.tx_tone) / 10.0 - mem.tmode = is_no_tone(_mem.rx_tone) and "Tone" or "TSQL" + mem.tmode = _is_no_tone(_mem.rx_tone) and "Tone" or "TSQL"
mem.power = POWER_LEVELS[not _mem.power_high]
@@ -612,7 +624,7 @@ _nam = self._memobj.names[mem.number - 1]
if mem.empty: - self.wipe_memory(_mem, "\xFF") + wipe_memory(_mem, "\xFF") return
_mem.rx_freq = mem.freq / 10 @@ -666,6 +678,7 @@ raise Exception("Character `%s' not supported")
def puxing_2r_prep(radio): + """Do the Puxing 2R identification dance""" radio.pipe.setTimeout(0.2) radio.pipe.write("PROGRAM\x02") ack = radio.pipe.read(1) @@ -677,6 +690,7 @@ print "Radio ident: %s (%i)" % (repr(ident), len(ident))
def puxing_2r_download(radio): + """Talk to a Puxing 2R and do a download""" try: puxing_2r_prep(radio) return do_download(radio, 0x0000, 0x0FE0, 0x0010) @@ -686,6 +700,7 @@ raise errors.RadioError("Failed to communicate with radio: %s" % e)
def puxing_2r_upload(radio): + """Talk to a Puxing 2R and do an upload""" try: puxing_2r_prep(radio) return do_upload(radio, 0x0000, 0x0FE0, 0x0010) @@ -694,7 +709,7 @@ except Exception, e: raise errors.RadioError("Failed to communicate with radio: %s" % e)
-puxing_2r_mem_format = """ +PUXING_2R_MEM_FORMAT = """ #seekto 0x0010; struct { lbcd freq[4]; @@ -719,6 +734,7 @@
@directory.register class Puxing2RRadio(KGUVD1PRadio): + """Puxing PX-2R""" VENDOR = "Puxing" MODEL = "PX-2R" _memsize = 0x0FE0 @@ -753,7 +769,7 @@ puxing_2r_upload(self)
def process_mmap(self): - self._memobj = bitwise.parse(puxing_2r_mem_format, self._mmap) + self._memobj = bitwise.parse(PUXING_2R_MEM_FORMAT, self._mmap)
def get_memory(self, number): _mem = self._memobj.memory[number-1] @@ -780,16 +796,17 @@ mem.rtone = chirp_common.TONES[_mem.tx_tone - 1] mem.tmode = _mem.rx_tone and "TSQL" or "Tone"
- c = 0 + count = 0 for i in _mem.name: if i == 0xFF: break try: mem.name += PX2R_CHARSET[i] - except: - print "Unknown name char %i: 0x%02x (mem %i)" % (c, i, number) + except Exception: + print "Unknown name char %i: 0x%02x (mem %i)" % (count, + i, number) mem.name += " " - c += 1 + count += 1 mem.name = mem.name.rstrip()
return mem @@ -845,7 +862,8 @@ raise errors.RadioError("Radio did not ACK ident")
def uv3r_prep(radio): - for i in range(0, 10): + """Do the UV3R identification dance""" + for _i in range(0, 10): try: return _uv3r_prep(radio) except errors.RadioError, e: @@ -854,6 +872,7 @@ raise e
def uv3r_download(radio): + """Talk to a UV3R and do a download""" try: uv3r_prep(radio) return do_download(radio, 0x0000, 0x0E40, 0x0010) @@ -863,6 +882,7 @@ raise errors.RadioError("Failed to communicate with radio: %s" % e)
def uv3r_upload(radio): + """Talk to a UV3R and do an upload""" try: uv3r_prep(radio) return do_upload(radio, 0x0000, 0x0E40, 0x0010) @@ -871,7 +891,7 @@ except Exception, e: raise errors.RadioError("Failed to communicate with radio: %s" % e)
-uv3r_mem_format = """ +UV3R_MEM_FORMAT = """ #seekto 0x0010; struct { lbcd rx_freq[4]; @@ -920,6 +940,7 @@
@directory.register class UV3RRadio(KGUVD1PRadio): + """Baofeng UV-3R""" VENDOR = "Baofeng" MODEL = "UV-3R"
@@ -950,7 +971,7 @@ uv3r_upload(self)
def process_mmap(self): - self._memobj = bitwise.parse(uv3r_mem_format, self._mmap) + self._memobj = bitwise.parse(UV3R_MEM_FORMAT, self._mmap)
def get_memory(self, number): _mem = self._memobj.rx_memory[number - 1] @@ -962,7 +983,7 @@ return mem
mem.freq = int(_mem.rx_freq) * 10 - mem.offset = int(_mem.offset) * 10; + mem.offset = int(_mem.offset) * 10 mem.duplex = UV3R_DUPLEX[_mem.duplex] if mem.offset > 60000000: if mem.duplex == "+": diff -r db82df47f205 -r f805c420592f chirp/xml_ll.py --- a/chirp/xml_ll.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/xml_ll.py Fri Apr 27 14:35:41 2012 -0700 @@ -13,12 +13,12 @@ # 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 errors import re
-from chirp import chirp_common +from chirp import chirp_common, errors
def get_memory(doc, number): + """Extract a Memory object from @doc""" ctx = doc.xpathNewContext()
base = "//radio/memories/memory[@location=%i]" % number @@ -98,6 +98,7 @@ return mem
def set_memory(doc, mem): + """Set @mem in @doc""" ctx = doc.xpathNewContext()
base = "//radio/memories/memory[@location=%i]" % mem.number @@ -105,7 +106,7 @@ fields = ctx.xpathEval(base) if len(fields) > 1: raise errors.RadioError("%i memories claiming to be %i" % (len(fields), - number)) + mem.number)) elif len(fields) == 1: fields[0].unlinkNode()
@@ -197,6 +198,7 @@ dc.addContent(str(mem.dv_code))
def del_memory(doc, number): + """Remove memory @number from @doc""" path = "//radio/memories/memory[@location=%i]" % number ctx = doc.xpathNewContext() fields = ctx.xpathEval(path) @@ -206,11 +208,12 @@
def _get_bank(node): bank = chirp_common.Bank(node.prop("label")) - id = int(node.prop("id")) + ident = int(node.prop("id"))
- return id, bank + return ident, bank
def get_banks(doc): + """Return a list of banks from @doc""" path = "//radio/banks/bank" ctx = doc.xpathNewContext() fields = ctx.xpathEval(path) @@ -219,14 +222,15 @@ for field in fields: banks.append(_get_bank(field))
- def cmp(x, y): - return x[0] - y[0] + def _cmp(itema, itemb): + return itema[0] - itemb[0]
- banks.sort(cmp=cmp) + banks.sort(cmp=_cmp)
return [x[1] for x in banks]
def set_banks(doc, banklist): + """Set the list of banks in @doc""" path = "//radio/banks/bank" ctx = doc.xpathNewContext() fields = ctx.xpathEval(path) diff -r db82df47f205 -r f805c420592f chirp/yaesu_clone.py --- a/chirp/yaesu_clone.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirp/yaesu_clone.py Fri Apr 27 14:35:41 2012 -0700 @@ -18,10 +18,10 @@ from chirp import chirp_common, util, memmap, errors import time, os
-def safe_read(pipe, count, times=60): +def _safe_read(pipe, count): buf = "" first = True - for i in range(0, 60): + for _i in range(0, 60): buf += pipe.read(count - len(buf)) #print "safe_read: %i/%i\n" % (len(buf), count) if buf: @@ -34,17 +34,15 @@ print util.hexprint(buf) return buf
-def chunk_read(pipe, count, status_fn): +def _chunk_read(pipe, count, status_fn): block = 32 data = "" - first = True - for i in range(0, count, block): + for _i in range(0, count, block): data += pipe.read(block) if data: if data[0] == chr(CMD_ACK): data = data[1:] # Chew an echo'd ack if using a 2-pin cable #print "Chewed an ack" - first = False status = chirp_common.Status() status.msg = "Cloning from radio" status.max = count @@ -54,7 +52,7 @@ print "Read %i/%i" % (len(data), count) return data
-def _clone_in(radio): +def __clone_in(radio): pipe = radio.pipe
start = time.time() @@ -64,28 +62,28 @@ for block in radio._block_lengths: blocks += 1 if blocks == len(radio._block_lengths): - chunk = chunk_read(pipe, block, radio.status_fn) + chunk = _chunk_read(pipe, block, radio.status_fn) else: - chunk = safe_read(pipe, block) + chunk = _safe_read(pipe, block) pipe.write(chr(CMD_ACK)) if not chunk: raise errors.RadioError("No response from radio") data += chunk
- if len(data) != radio._memsize: + if len(data) != radio.get_memsize(): raise errors.RadioError("Received incomplete image from radio")
print "Clone completed in %i seconds" % (time.time() - start)
return memmap.MemoryMap(data)
-def clone_in(radio): +def _clone_in(radio): try: - return _clone_in(radio) + return __clone_in(radio) except Exception, e: raise errors.RadioError("Failed to communicate with the radio: %s" % e)
-def chunk_write(pipe, data, status_fn, block): +def _chunk_write(pipe, data, status_fn, block): delay = 0.03 count = 0 for i in range(0, len(data), block): @@ -101,15 +99,15 @@ status.cur = count status_fn(status)
-def _clone_out(radio): +def __clone_out(radio): pipe = radio.pipe - l = radio._block_lengths + block_lengths = radio._block_lengths total_written = 0
- def status(): + def _status(): status = chirp_common.Status() status.msg = "Cloning to radio" - status.max = l[0] + l[1] + l[2] + status.max = block_lengths[0] + block_lengths[1] + block_lengths[2] status.cur = total_written radio.status_fn(status)
@@ -121,28 +119,29 @@ blocks += 1 if blocks != len(radio._block_lengths): #print "Sending %i-%i" % (pos, pos+block) - pipe.write(radio._mmap[pos:pos+block]) + pipe.write(radio.get_mmap()[pos:pos+block]) buf = pipe.read(1) if buf and buf[0] != chr(CMD_ACK): buf = pipe.read(block) if not buf or buf[-1] != chr(CMD_ACK): raise Exception("Radio did not ack block %i" % blocks) else: - chunk_write(pipe, radio._mmap[pos:], - radio.status_fn, radio._block_size) + _chunk_write(pipe, radio.get_mmap()[pos:], + radio.status_fn, radio._block_size) pos += block
pipe.read(pos) # Chew the echo if using a 2-pin cable
print "Clone completed in %i seconds" % (time.time() - start)
-def clone_out(radio): +def _clone_out(radio): try: - return _clone_out(radio) + return __clone_out(radio) except Exception, e: raise errors.RadioError("Failed to communicate with the radio: %s" % e)
class YaesuChecksum: + """A Yaesu Checksum Object""" def __init__(self, start, stop, address=None): self._start = start self._stop = stop @@ -156,12 +155,14 @@ return ord(mmap[self._address])
def get_calculated(self, mmap): + """Return the calculated value of the checksum""" cs = 0 for i in range(self._start, self._stop+1): cs += ord(mmap[i]) return cs % 256
def update(self, mmap): + """Update the checksum with the data in @mmap""" mmap[self._address] = self.get_calculated(mmap)
def __str__(self): @@ -170,6 +171,7 @@ self._address)
class YaesuCloneModeRadio(chirp_common.CloneModeRadio): + """Base class for all Yaesu clone-mode radios""" _block_lengths = [8, 65536] _block_size = 8
@@ -181,10 +183,12 @@ return []
def update_checksums(self): + """Update the radio's checksums from the current memory map""" for checksum in self._checksums(): checksum.update(self._mmap)
def check_checksums(self): + """Validate the checksums stored in the memory map""" for checksum in self._checksums(): if checksum.get_existing(self._mmap) != \ checksum.get_calculated(self._mmap): @@ -192,13 +196,13 @@ print "Checksum %s: OK" % checksum
def sync_in(self): - self._mmap = clone_in(self) + self._mmap = _clone_in(self) self.check_checksums() self.process_mmap()
def sync_out(self): self.update_checksums() - clone_out(self) + _clone_out(self)
@classmethod def match_model(cls, filedata, filename): @@ -209,24 +213,3 @@ bm = self.get_bank_model() for bank in bm.get_memory_banks(mem): bm.remove_memory_from_bank(mem, bank) - - -if __name__ == "__main__": - import sys, serial - s = serial.Serial(port=sys.argv[1], baudrate=19200, timeout=5) - - d = s.read(20) - print util.hexprint(d) - - s.write(chr(0x06)) - - d = "" - while True: - c = s.read(32) - if not c: - break - d += c - - print len(d) - - diff -r db82df47f205 -r f805c420592f chirpui/clone.py --- a/chirpui/clone.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirpui/clone.py Fri Apr 27 14:35:41 2012 -0700 @@ -191,7 +191,7 @@ class CloneCancelledException(Exception): pass
-class CloneThread(chirp_common.KillableThread): +class CloneThread(threading.Thread): def __status(self, status): gobject.idle_add(self.__progw.status, status)
diff -r db82df47f205 -r f805c420592f chirpui/mainapp.py --- a/chirpui/mainapp.py Fri Apr 27 14:35:40 2012 -0700 +++ b/chirpui/mainapp.py Fri Apr 27 14:35:41 2012 -0700 @@ -887,7 +887,7 @@ else: from chirp import rfinder radio = rfinder.RFinderRadio(None) - radio.set_params(lat, lon, miles, email, passwd) + radio.set_params((lat, lon), miles, email, passwd) self.do_open_live(radio, read_only=True)
self.window.set_cursor(None)