[chirp_devel] [PATCH 0 of 1] Add import support for Kenwood *.hmk files. Feature #102
This is significantly cleaned up since the first version. It now inherits from CSVRadio. The Dstar features are not a problem during import.
I've included an example hmk file for you to test with.
Tom KD7LXL
# HG changeset patch # User Tom Hayward tom@tomh.us # Date 1333578314 21600 # Node ID 7ddbd9d7f5ffff4a2008f1712bf851d622f67044 # Parent f4e83f90b8eefb38264e2596001eda403a8945f9 Add import support for Kenwood *.hmk files. Feature #102
diff -r f4e83f90b8ee -r 7ddbd9d7f5ff chirp/kenwood_hmk.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chirp/kenwood_hmk.py Wed Apr 04 16:25:14 2012 -0600 @@ -0,0 +1,138 @@ +# Copyright 2008 Dan Smith dsmith@danplanet.com +# Copyright 2012 Tom Haywward tom@tomh.us +# +# 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/. + +import os +import csv + +from chirp import chirp_common, errors, directory, generic_csv + +tx_freq = None +def set_tx_freq(val): + global tx_freq + tx_freq = chirp_common.parse_freq(val) + return None + +class OmittedHeaderError(Exception): + pass + +@directory.register +class HMKRadio(generic_csv.CSVRadio): + VENDOR = "Kenwood" + MODEL = "HMK" + FILE_EXTENSION = "hmk" + + DUPLEX_MAP = { + " ": "", + "S": "split", + "+": "+", + "-": "-", + } + + SKIP_MAP = { + "Off": "", + "On": "S", + } + + TMODE_MAP = { + "Off": "", + "T": "Tone", + "CT": "TSQL", + "DCS": "DTCS", + "": "Cross", + } + + ATTR_MAP = { + "!!Ch" : (int, "number"), + "M.Name" : (str, "name"), + "Rx Freq." : (chirp_common.parse_freq, "freq"), + "Shift/Split" : (lambda v: HMKRadio.DUPLEX_MAP[v], "duplex"), + "Offset" : (chirp_common.parse_freq, "offset"), + "T/CT/DCS" : (lambda v: HMKRadio.TMODE_MAP[v], "tmode"), + "TO Freq." : (float, "rtone"), + "CT Freq." : (float, "ctone"), + "DCS Code" : (int, "dtcs"), + "Mode" : (str, "mode"), + "Tx Freq." : (set_tx_freq, "txfreq"), + "Rx Step" : (float, "tuning_step"), + "L.Out" : (lambda v: HMKRadio.SKIP_MAP[v], "skip"), + } + + def load(self, filename=None): + if filename is None and self._filename is None: + raise errors.RadioError("Need a location to load from") + + if filename: + self._filename = filename + + self._blank() + + f = file(self._filename, "r") + for line in f: + if line.strip() == "// Memory Channels": + break + + reader = csv.reader(f, delimiter=chirp_common.SEPCHAR, quotechar='"') + + good = 0 + lineno = 0 + for line in reader: + lineno += 1 + if lineno == 1: + header = line + continue + + if len(header) > len(line): + print "Line %i has %i columns, expected %i" % (lineno, + len(line), + len(header)) + self.errors.append("Column number mismatch on line %i" % lineno) + continue + + try: + mem = self._parse_csv_data_line(header, [i.replace(',','.') for i in line]) + if mem.duplex == "split": + mem.offset = tx_freq + if mem.number is None: + raise Exception("Invalid Location field" % lineno) + except Exception, e: + print "Line %i: %s" % (lineno, e) + self.errors.append("Line %i: %s" % (lineno, e)) + continue + + self.__grow(mem.number) + self.memories[mem.number] = mem + good += 1 + + if not good: + print self.errors + raise errors.InvalidDataError("No channels found") + + def __grow(self, target): + delta = target - len(self.memories) + if delta < 0: + return + + 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) + + @classmethod + def match_model(cls, filedata, filename): + return filename.endswith(cls.FILE_EXTENSION) diff -r f4e83f90b8ee -r 7ddbd9d7f5ff chirpui/mainapp.py --- a/chirpui/mainapp.py Wed Apr 04 13:10:17 2012 -0700 +++ b/chirpui/mainapp.py Wed Apr 04 16:25:14 2012 -0600 @@ -667,6 +667,7 @@ (_("CSV Files") + " (*.csv)", "*.csv"), (_("EVE Files (VX5)") + " (*.eve)", "*.eve"), (_("ICF Files") + " (*.icf)", "*.icf"), + (_("Kenwood HMK Files") + " (*.hmk)", "*.hmk"), (_("VX5 Commander Files") + " (*.vx5)", "*.vx5"), (_("VX7 Commander Files") + " (*.vx7)", "*.vx7")] filen = platform.get_platform().gui_open_file(types=types) diff -r f4e83f90b8ee -r 7ddbd9d7f5ff tests/images/Marine-VHF-Channels.hmk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/images/Marine-VHF-Channels.hmk Wed Apr 04 16:25:14 2012 -0600 @@ -0,0 +1,71 @@ +KENWOOD MCP FOR AMATEUR MOBILE TRANSCEIVER +[Export Software]=MCP-2A Version 3.02 +[Export File Version]=1 +[Type]=E +[Language]=English + +// Comments +!!Comments= + +// Memory Channels +!!Ch,Rx Freq.,Rx Step,Offset,T/CT/DCS,TO Freq.,CT Freq.,DCS Code,Shift/Split,Rev.,L.Out,Mode,Tx Freq.,Tx Step,M.Name +"900","00155,500000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","155,500000","025,00","MVHF L1" +"901","00155,525000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","155,525000","025,00","MVHF L2" +"902","00155,625000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","155,625000","025,00","MVHF F1" +"903","00155,775000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","155,775000","025,00","MVHF F2" +"904","00155,825000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","155,825000","025,00","MVHF F3" +"905","00156,300000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","156,300000","025,00","MVHF K06" +"906","00156,375000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","156,375000","025,00","MVHF K67" +"907","00156,400000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","156,400000","025,00","MVHF K08" +"908","00156,425000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","156,425000","025,00","MVHF K68" +"909","00156,450000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","156,450000","025,00","MVHF K09" +"910","00156,475000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","156,475000","025,00","MVHF K69" +"911","00156,500000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","156,500000","025,00","MVHF K10" +"912","00156,525000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","156,525000","025,00","MDSC K70" +"913","00156,550000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","156,550000","025,00","MVHF K11" +"914","00156,575000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","156,575000","025,00","MVHF K71" +"915","00156,600000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","156,600000","025,00","MVHF K12" +"916","00156,625000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","156,625000","025,00","MVHF K72" +"917","00156,650000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","156,650000","025,00","MVHF K13" +"918","00156,675000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","156,675000","025,00","MVHF K73" +"919","00156,700000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","156,700000","025,00","MVHF K14" +"920","00156,725000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","156,725000","025,00","MVHF K74" +"921","00156,750000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","156,750000","025,00","MVHF K15" +"922","00156,800000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","156,800000","025,00","MVHF K16" +"923","00156,850000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","156,850000","025,00","MVHF K17" +"924","00156,875000","025,00","00,000000","Off","88,5","88,5","023"," ","Off","Off","FM","156,875000","025,00","MVHF K77" +"925","00160,625000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","160,625000","025,00","MVHF K60" +"926","00160,650000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","160,650000","025,00","MVHF K01" +"927","00160,675000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","160,675000","025,00","MVHF K61" +"928","00160,700000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","160,700000","025,00","MVHF K02" +"929","00160,725000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","160,725000","025,00","MVHF K62" +"930","00160,750000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","160,750000","025,00","MVHF K03" +"931","00160,775000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","160,775000","025,00","MVHF K63" +"932","00160,800000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","160,800000","025,00","MVHF K04" +"933","00160,825000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","160,825000","025,00","MVHF K64" +"934","00160,850000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","160,850000","025,00","MVHF K05" +"935","00160,875000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","160,875000","025,00","MVHF K65" +"936","00160,925000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","160,925000","025,00","MVHF K66" +"937","00160,950000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","160,950000","025,00","MVHF K07" +"938","00161,500000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","161,500000","025,00","MVHF K18" +"939","00161,525000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","161,525000","025,00","MVHF K78" +"940","00161,550000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","161,550000","025,00","MVHF K19" +"941","00161,575000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","161,575000","025,00","MVHF K79" +"942","00161,600000","025,00","04,600000","Off","88,5","88,5","023","-","Off","Off","FM","161,600000","025,00","MVHF K20" +"943","00161,625000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","161,625000","025,00","MVHF K80" +"944","00161,650000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","161,650000","025,00","MVHF K21" +"945","00161,675000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","161,675000","025,00","MVHF K81" +"946","00161,700000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","161,700000","025,00","MVHF K22" +"947","00161,725000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","161,725000","025,00","MVHF K82" +"948","00161,750000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","161,750000","025,00","MVHF K23" +"949","00161,775000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","161,775000","025,00","MVHF K83" +"950","00161,800000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","161,800000","025,00","MVHF K24" +"951","00161,825000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","161,825000","025,00","MVHF K84" +"952","00161,850000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","161,850000","025,00","MVHF K25" +"953","00161,875000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","161,875000","025,00","MVHF K85" +"954","00161,900000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","161,900000","025,00","MVHF K26" +"955","00161,925000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","161,925000","025,00","MVHF K86" +"956","00161,950000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","161,950000","025,00","MVHF K27" +"957","00161,975000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","161,975000","025,00","MAIS K87" +"958","00162,000000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","162,000000","025,00","MVHF K28" +"959","00162,025000","025,00","04,600000","Off","88,5","88,5","023","-","Off","On","FM","162,025000","025,00","MAIS K88"
This makes it non-reentrant, and we can't have that.
Right here, do this:
tx_freq = None def set_tx_freq(val): tx_freq = chirp_common.parse_freq(val) return None self.ATTR_MAP["Tx Freq."] = (set_tx_freq, "txfreq")
so that it's in place before we do this:
Then make sure to avoid modifying the global ATTR_MAP definition:
def __init__(self, *args): self.ATTR_MAP = dict(self.ATTR_MAP) generic_csv.CSVRadio.__init__(self, *args)
Sound okay?
participants (2)
-
Dan Smith
-
Tom Hayward