[chirp_devel] [PATCH 0 of 4] Add import support for Kenwood *.hmk files. Feature #102
Here is, hopefully, a final version of the hmk file import patch.
The first two patches are changes to CSVRadio that make it easier to inherit.
HMKRadio has been modified so it no longer relies on the broken set_tx_freq() scheme. Because Chirp expects the transmit frequency for odd-split channels to be in the offset field, HMKRadio::load() copies the Tx. Freq field to the Offset field when needed before parsing each field.
Finally, I've included an example hmk file as an independent patch. You can use this for testing and then choose whether you not you'd like to keep it.
Tom KD7LXL
# HG changeset patch # User Tom Hayward tom@tomh.us # Date 1333641862 21600 # Node ID 3f4a778cc0bbe4117ca88842a9e59c4fd237de91 # Parent 69c66e533b3ada0f8f9b7ca9336fb560fd899604 Make CSVRadio::match_model() more generic so it works with HMKRadio. #102
diff -r 69c66e533b3a -r 3f4a778cc0bb chirp/generic_csv.py --- a/chirp/generic_csv.py Wed Apr 04 18:30:58 2012 -0700 +++ b/chirp/generic_csv.py Thu Apr 05 10:04:22 2012 -0600 @@ -242,4 +242,4 @@
@classmethod def match_model(cls, filedata, filename): - return filename.lower().endswith(".csv") + return filename.lower().endswith("." + cls.FILE_EXTENSION)
# HG changeset patch # User Tom Hayward tom@tomh.us # Date 1333642033 21600 # Node ID dff9491d46eba6a3e50f17c63af21f7c65b8a424 # Parent 3f4a778cc0bbe4117ca88842a9e59c4fd237de91 Make CSVRadio::__grow() accessible from inherited classes, such as HMKRadio. #102
diff -r 3f4a778cc0bb -r dff9491d46eb chirp/generic_csv.py --- a/chirp/generic_csv.py Thu Apr 05 10:04:22 2012 -0600 +++ b/chirp/generic_csv.py Thu Apr 05 10:07:13 2012 -0600 @@ -166,7 +166,7 @@ self.errors.append("Line %i: %s" % (lineno, e)) continue
- self.__grow(mem.number) + self._grow(mem.number) self.memories[mem.number] = mem good += 1
@@ -212,7 +212,7 @@ except: raise errors.InvalidMemoryLocation("No such memory %s" % number)
- def __grow(self, target): + def _grow(self, target): delta = target - len(self.memories) if delta < 0: return @@ -226,7 +226,7 @@ self.memories.append(m)
def set_memory(self, newmem): - self.__grow(newmem.number) + self._grow(newmem.number) self.memories[newmem.number] = newmem
def erase_memory(self, number):
# HG changeset patch # User Tom Hayward tom@tomh.us # Date 1333642041 21600 # Node ID 29d6d9465751b8b6047282ddea4e236d9e7efab7 # Parent dff9491d46eba6a3e50f17c63af21f7c65b8a424 Add import support for Kenwood *.hmk files. Feature #102
diff -r dff9491d46eb -r 29d6d9465751 chirp/kenwood_hmk.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/chirp/kenwood_hmk.py Thu Apr 05 10:07:21 2012 -0600 @@ -0,0 +1,121 @@ +# 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 + +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"), + "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 + + # hmk stores Tx Freq. in its own field, but Chirp expects the Tx + # Freq. for odd-split channels to be in the Offset field. + # If channel is odd-split, copy Tx Freq. field to Offset field. + if line[header.index('Shift/Split')] == "S": + line[header.index('Offset')] = line[header.index('Tx Freq.')] + + # fix EU decimal + line = [i.replace(',','.') for i in line] + + try: + mem = self._parse_csv_data_line(header, line) + 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") diff -r dff9491d46eb -r 29d6d9465751 chirpui/mainapp.py --- a/chirpui/mainapp.py Thu Apr 05 10:07:13 2012 -0600 +++ b/chirpui/mainapp.py Thu Apr 05 10:07:21 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)
# HG changeset patch # User Tom Hayward tom@tomh.us # Date 1333642102 21600 # Node ID 48e4bb5a51dd1391701c26aa81d5b8565b977582 # Parent 29d6d9465751b8b6047282ddea4e236d9e7efab7 Add example .hmk file to test images. #102
diff -r 29d6d9465751 -r 48e4bb5a51dd tests/images/Marine-VHF-Channels.hmk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/images/Marine-VHF-Channels.hmk Thu Apr 05 10:08:22 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"
participants (1)
-
Tom Hayward