[hamradio-commits] [chirp] 01/04: Imported Upstream version 20160110

Iain R. Learmonth irl at moszumanska.debian.org
Fri Jan 15 16:58:28 UTC 2016


This is an automated email from the git hooks/post-receive script.

irl pushed a commit to branch master
in repository chirp.

commit f7a4d19cb59d14b4895f25a3ced3c3b257593410
Author: Iain R. Learmonth <irl at debian.org>
Date:   Wed Jan 13 12:57:58 2016 +0000

    Imported Upstream version 20160110
---
 PKG-INFO                                           |    2 +-
 chirp/__init__.py                                  |    2 +-
 chirp/drivers/icomciv.py                           |   80 +-
 chirp/drivers/icw32.py                             |   43 +
 chirp/drivers/tk760.py                             |  851 +++++++++++
 chirp/drivers/tk760g.py                            | 1557 ++++++++++++++++++++
 chirp/drivers/ts2000.py                            |    8 +-
 stock_configs/DE Freenet Frequencies.csv           |    7 +
 stock_configs/EU LPD and PMR Channels.csv          |  156 +-
 stock_configs/FR Marine VHF Channels.csv           |  114 +-
 .../UK Business Radio Simple Light Frequencies.csv |   16 +
 stock_configs/US 60 meter channels (Center).csv    |    2 +-
 stock_configs/US 60 meter channels (Dial).csv      |    2 +-
 stock_configs/US Calling Frequencies.csv           |    2 +-
 stock_configs/US FRS and GMRS Channels.csv         |   46 +-
 stock_configs/US MURS Channels.csv                 |   10 +-
 stock_configs/US Marine VHF Channels.csv           |  120 +-
 17 files changed, 2764 insertions(+), 254 deletions(-)

diff --git a/PKG-INFO b/PKG-INFO
index 1a8ca68..599b43a 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.0
 Name: chirp
-Version: daily-20151225
+Version: daily-20160110
 Summary: UNKNOWN
 Home-page: UNKNOWN
 Author: UNKNOWN
diff --git a/chirp/__init__.py b/chirp/__init__.py
index 1fd94d9..9121671 100644
--- a/chirp/__init__.py
+++ b/chirp/__init__.py
@@ -17,7 +17,7 @@ import os
 import sys
 from glob import glob
 
-CHIRP_VERSION="daily-20151225"
+CHIRP_VERSION="daily-20160110"
 
 module_dir = os.path.dirname(sys.modules["chirp"].__file__)
 __all__ = []
diff --git a/chirp/drivers/icomciv.py b/chirp/drivers/icomciv.py
index bcb7c40..60e8b19 100644
--- a/chirp/drivers/icomciv.py
+++ b/chirp/drivers/icomciv.py
@@ -14,25 +14,31 @@ lbcd freq[5];
 u8   unknown2:5,
      mode:3;
 """
+# http://www.vk4adc.com/
+#     web/index.php/reference-information/49-general-ref-info/182-civ7400
 MEM_IC7000_FORMAT = """
 u8   bank;
 bbcd number[2];
-u8   skip;
+u8   spl:4,
+     skip:4;
 lbcd freq[5];
-u8   unknown2:5,
-     mode:3;
-u8   unknown1;
-u8   unknown2:2,
-     duplex:2,
-     unknown3:1,
-     tmode:3;
-u8   unknown4;
-bbcd rtone[2];
-u8   unknown5;
-bbcd ctone[2];
+u8   mode;
+u8   filter;
+u8   duplex:4,
+     tmode:4;
+bbcd rtone[3];
+bbcd ctone[3];
 u8   dtcs_polarity;
 bbcd dtcs[2];
-u8   unknown[17];
+lbcd freq_tx[5];
+u8   mode_tx;
+u8   filter_tx;
+u8   duplex_tx:4,
+     tmode_tx:4;
+bbcd rtone_tx[3];
+bbcd ctone_tx[3];
+u8   dtcs_polarity_tx;
+bbcd dtcs_tx[2];
 char name[9];
 """
 mem_duptone_format = """
@@ -56,6 +62,8 @@ u8   unknown[11];
 char name[9];
 """
 
+SPLIT = ["", "spl"]
+
 
 class Frame:
     """Base class for an ICF frame"""
@@ -108,7 +116,7 @@ class Frame:
             raise errors.RadioError("Radio reported error")
 
         src, dst = struct.unpack("BB", data[2:4])
-        LOG.debug("%02x <- %02x:\n%s" % (src, dst, util.hexprint(data)))
+        LOG.debug("%02x <- %02x:\n%s" % (dst, src, util.hexprint(data)))
 
         self._cmd = ord(data[4])
         self._sub = ord(data[5])
@@ -248,10 +256,19 @@ class IcomCIVRadio(icf.IcomLiveRadio):
 
     def get_raw_memory(self, number):
         f = self._classes["mem"]()
-        f.set_location(number)
+        if self._rf.has_bank:
+            ch, bnk = self.mem_to_ch_bnk(number)
+            f.set_location(ch, bnk)
+            loc = "bank %i, channel %02i" % (bnk, ch)
+        else:
+            f.set_location(number)
+            loc = "number %i" % number
         self._send_frame(f)
         f.read(self.pipe)
-        return repr(f.get_obj())
+        if f.get_data() and f.get_data()[-1] == "\xFF":
+            return "Memory " + loc + " empty."
+        else:
+            return repr(f.get_obj())
 
 # We have a simple mapping between the memory location in the frequency
 # editor and (bank, channel) of the radio.  The mapping doesn't
@@ -277,12 +294,14 @@ class IcomCIVRadio(icf.IcomLiveRadio):
 
         mem = chirp_common.Memory()
         mem.number = number
+        mem.immutable = []
 
         f = self._recv_frame(f)
         if len(f.get_data()) == 0:
             raise errors.RadioError("Radio reported error")
         if f.get_data() and f.get_data()[-1] == "\xFF":
             mem.empty = True
+            LOG.debug("Found %i empty" % mem.number)
             return mem
 
         memobj = f.get_obj()
@@ -323,10 +342,17 @@ class IcomCIVRadio(icf.IcomLiveRadio):
         if self._rf.valid_duplexes:
             mem.duplex = self._rf.valid_duplexes[memobj.duplex]
 
+        if self._rf.can_odd_split and memobj.spl:
+            mem.duplex = "split"
+            mem.offset = int(memobj.freq_tx)
+            mem.immutable = []
+        else:
+            mem.immutable = ["offset"]
+
         return mem
 
     def set_memory(self, mem):
-        LOG.debug("Setting %i" % mem.number)
+        LOG.debug("Setting %i(%s)" % (mem.number, mem.extd_number))
         if self._rf.has_bank:
             ch, bnk = self.mem_to_ch_bnk(mem.number)
             LOG.debug("Bank %i, Channel %02i" % (bnk, ch))
@@ -369,9 +395,6 @@ class IcomCIVRadio(icf.IcomLiveRadio):
         if self._rf.valid_tmodes:
             memobj.tmode = self._rf.valid_tmodes.index(mem.tmode)
 
-        if self._rf.valid_duplexes:
-            memobj.duplex = self._rf.valid_duplexes.index(mem.duplex)
-
         if self._rf.has_ctone:
             memobj.ctone = int(mem.ctone * 10)
             memobj.rtone = int(mem.rtone * 10)
@@ -389,6 +412,18 @@ class IcomCIVRadio(icf.IcomLiveRadio):
         if self._rf.has_dtcs:
             bitwise.int_to_bcd(memobj.dtcs, mem.dtcs)
 
+        if self._rf.can_odd_split and mem.duplex == "split":
+            memobj.spl = 1
+            memobj.duplex = 0
+            memobj.freq_tx = int(mem.offset)
+            memobj.tmode_tx = memobj.tmode
+            memobj.ctone_tx = memobj.ctone
+            memobj.rtone_tx = memobj.rtone
+            memobj.dtcs_polarity_tx = memobj.dtcs_polarity
+            memobj.dtcs_tx = memobj.dtcs
+        elif self._rf.valid_duplexes:
+            memobj.duplex = self._rf.valid_duplexes.index(mem.duplex)
+
         LOG.debug(repr(memobj))
         self._send_frame(f)
 
@@ -438,18 +473,19 @@ class Icom7000Radio(IcomCIVRadio):
         self._rf.has_dtcs_polarity = True
         self._rf.has_dtcs = True
         self._rf.has_ctone = True
-        self._rf.has_offset = False
+        self._rf.has_offset = True
         self._rf.has_name = True
         self._rf.has_tuning_step = False
         self._rf.valid_modes = ["LSB", "USB", "AM", "CW", "RTTY", "FM", "WFM"]
         self._rf.valid_tmodes = ["", "Tone", "TSQL", "DTCS"]
-        self._rf.valid_duplexes = ["", "-", "+"]
+        self._rf.valid_duplexes = ["", "-", "+", "split"]
         self._rf.valid_bands = [(30000, 199999999), (400000000, 470000000)]
         self._rf.valid_tuning_steps = []
         self._rf.valid_skips = ["S", ""]
         self._rf.valid_name_length = 9
         self._rf.valid_characters = chirp_common.CHARSET_ASCII
         self._rf.memory_bounds = (0, 99 * self._num_banks - 1)
+        self._rf.can_odd_split = True
 
 
 @directory.register
diff --git a/chirp/drivers/icw32.py b/chirp/drivers/icw32.py
index dc08ea0..fd11bd7 100644
--- a/chirp/drivers/icw32.py
+++ b/chirp/drivers/icw32.py
@@ -206,3 +206,46 @@ class ICW32ARadioUHF(ICW32ARadio):
     VARIANT = "UHF"
     _limits = (400000000, 470000000)
     _mem_positions = (0x06E0, 0x0E2E)
+
+
+# IC-W32E are the very same as IC-W32A but have a different _model
+ at directory.register
+class ICW32ERadio(ICW32ARadio):
+    """Icom IC-W32E"""
+    MODEL = "IC-W32E"
+
+    _model = "\x18\x82\x00\x02"
+
+    # an extra byte is added to distinguish file images from IC-W32A
+    # it will be allocated and initialized to 0x00 in _clone_from_radio
+    # (icf.py) but radio will not send it
+    # That byte is not sent to radio because the _clone_to_radio use _ranges
+    # for the send cycle
+    _memsize = ICW32ARadio._memsize + 1
+
+    def get_sub_devices(self):
+        # this is needed because sub devices must be of a child class
+        return [ICW32ERadioVHF(self._mmap), ICW32ERadioUHF(self._mmap)]
+
+    @classmethod
+    def match_model(cls, filedata, filename):
+        if not len(filedata) == cls._memsize:
+            return False
+        return filedata[-16 - 1: -1] == "IcomCloneFormat3" and \
+            filedata[-1] == chr(0x00)
+
+
+# this is the very same as ICW32ARadioVHF but have ICW32ERadio as parent class
+class ICW32ERadioVHF(ICW32ERadio):
+    """ICW32 VHF subdevice"""
+    VARIANT = "VHF"
+    _limits = (118000000, 174000000)
+    _mem_positions = (0x0000, 0x0DC0)
+
+
+# this is the very same as ICW32ARadioUHF but have ICW32ERadio as parent class
+class ICW32ERadioUHF(ICW32ERadio):
+    """ICW32 UHF subdevice"""
+    VARIANT = "UHF"
+    _limits = (400000000, 470000000)
+    _mem_positions = (0x06E0, 0x0E2E)
diff --git a/chirp/drivers/tk760.py b/chirp/drivers/tk760.py
new file mode 100644
index 0000000..5fb46a4
--- /dev/null
+++ b/chirp/drivers/tk760.py
@@ -0,0 +1,851 @@
+# Copyright 2016 Dan Smith <dsmith at danplanet.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Driver author: Pavel CO7WT, co7wt at frcuba.co.cu, pavelmc at gmail.com
+
+import time
+import struct
+import logging
+
+LOG = logging.getLogger(__name__)
+
+from chirp import chirp_common, directory, memmap
+from chirp import bitwise, errors, util
+from chirp.settings import RadioSettingGroup, RadioSetting, \
+    RadioSettingValueBoolean, RadioSettingValueList, \
+    RadioSettingValueString, RadioSettingValueInteger, \
+    RadioSettings
+from textwrap import dedent
+
+MEM_FORMAT = """
+#seekto 0x0000;
+struct {
+  lbcd rxfreq[4];
+  lbcd txfreq[4];
+} memory[32];
+
+#seekto 0x0100;
+struct {
+  lbcd rx_tone[2];
+  lbcd tx_tone[2];
+} tone[32];
+
+#seekto 0x0180;
+struct {
+  u8 unknown0:1,
+     unknown1:1,
+     wide:1,            // wide: 1 = wide, 0 = narrow
+     power:1,           // power: 1 = high, 0 = low
+     busy_lock:1,       // busy lock:  1 = off, 0 = on
+     pttid:1,           // ptt id:  1 = off, 0 = on
+     dtmf:1,            // dtmf signaling:  1 = off, 0 = on
+     twotone:1;         // 2-tone signaling:  1 = off, 0 = on
+} ch_settings[32];
+
+#seekto 0x02B0;
+struct {
+    u8 unknown10[16];      // x02b0
+    u8 unknown11[16];      // x02c0
+    u8 active[4];            // x02d0
+    u8 scan[4];              // x02d4
+    u8 unknown12[8];         // x02d8
+    u8 unknown13;          // x02e0
+    u8 kMON;                 // 0x02d1 MON Key
+    u8 kA;                   // 0x02d2 A Key
+    u8 kSCN;                 // 0x02d3 SCN Key
+    u8 kDA;                  // 0x02d4 D/A Key
+    u8 unknown14;            // x02e5
+    u8 min_vol;              // x02e6 byte 0-31 0 = off
+    u8 poweron_tone;         // x02e7 power on tone 0 = off, 1 = on
+    u8 tot;                  // x02e8 Time out Timer 0 = off, 1 = 30s (max 300)
+    u8 unknown15[3];         // x02e9-x02eb
+    u8 dealer_tuning;        // x02ec ? bit 0? 0 = off, 1 = on
+    u8 clone;                // x02ed ? bit 0? 0 = off, 1 = on
+    u8 unknown16[2];         // x02ee-x2ef
+    u8 unknown17[16];      // x02f0
+    u8 unknown18[5];       // x0300
+    u8 clear2transpond;      // x0305 byte 0 = off, 1 = on
+    u8 off_hook_decode;      // x0306 byte 0 = off, 1 = on
+    u8 off_hook_hornalert;   // x0307 byte 0 = off, 1 = on
+    u8 unknown19[8];         // x0308-x030f
+    u8 unknown20[16];      // x0310
+} settings;
+"""
+
+KEYS = {
+    0x00: "Disabled",
+    0x01: "Monitor",
+    0x02: "Talk Around",
+    0x03: "Horn Alert",
+    0x04: "Public Adress",
+    0x05: "Auxiliary",
+    0x06: "Scan",
+    0x07: "Scan Del/Add",
+    0x08: "Home Channel",
+    0x09: "Operator Selectable Tone"
+}
+
+MEM_SIZE = 0x400
+BLOCK_SIZE = 8
+MEM_BLOCKS = range(0, (MEM_SIZE / BLOCK_SIZE))
+ACK_CMD = "\x06"
+TIMEOUT = 0.05  # from 0.03 up it' s safe, we set in 0.05 for a margin
+
+POWER_LEVELS = [chirp_common.PowerLevel("Low", watts=1),
+                chirp_common.PowerLevel("High", watts=5)]
+MODES = ["NFM", "FM"]
+SKIP_VALUES = ["", "S"]
+TONES = chirp_common.TONES
+#TONES.remove(254.1)
+DTCS_CODES = chirp_common.DTCS_CODES
+
+TOT = ["off"] + ["%s" % x for x in range(30, 330, 30)]
+VOL = ["off"] + ["%s" % x for x in range(1, 32)]
+
+
+def rawrecv(radio, amount):
+    """Raw read from the radio device"""
+    data = ""
+    try:
+        data = radio.pipe.read(amount)
+        #print("<= %02i: %s" % (len(data), util.hexprint(data)))
+    except:
+        raise errors.RadioError("Error reading data from radio")
+
+    return data
+
+
+def rawsend(radio, data):
+    """Raw send to the radio device"""
+    try:
+        radio.pipe.write(data)
+        #print("=> %02i: %s" % (len(data), util.hexprint(data)))
+    except:
+        raise errors.RadioError("Error sending data from radio")
+
+
+def send(radio, frame):
+    """Generic send data to the radio"""
+    rawsend(radio, frame)
+
+
+def make_frame(cmd, addr, data=""):
+    """Pack the info in the format it likes"""
+    ts = struct.pack(">BHB", ord(cmd), addr, 8)
+    if data == "":
+        return ts
+    else:
+        if len(data) == 8:
+            return ts + data
+        else:
+            raise errors.InvalidValueError("Data length of unexpected length")
+
+
+def handshake(radio, msg="", full=False):
+    """Make a full handshake, if not full just hals"""
+    # send ACK if commandes
+    if full is True:
+        rawsend(radio, ACK_CMD)
+    # receive ACK
+    ack = rawrecv(radio, 1)
+    # check ACK
+    if ack != ACK_CMD:
+        #close_radio(radio)
+        mesg = "Handshake failed: " + msg
+        raise errors.RadioError(mesg)
+
+
+def recv(radio):
+    """Receive data from the radio, 12 bytes, 4 in the header, 8 as data"""
+    rxdata = rawrecv(radio, 12)
+
+    if len(rxdata) != 12:
+        raise errors.RadioError(
+            "Received a length of data that is not possible")
+        return
+
+    cmd, addr, length = struct.unpack(">BHB", rxdata[0:4])
+    data = ""
+    if length == 8:
+        data = rxdata[4:]
+
+    return data
+
+
+def open_radio(radio):
+    """Open the radio into program mode and check if it's the correct model"""
+    # Set serial discipline
+    try:
+        radio.pipe.setParity("N")
+        radio.pipe.setTimeout(TIMEOUT)
+        radio.pipe.flushOutput()
+        radio.pipe.flushInput()
+    except:
+        msg = "Serial error: Can't set serial line discipline"
+        raise errors.RadioError(msg)
+
+    magic = "PROGRAM"
+    for i in range(0, len(magic)):
+        ack = rawrecv(radio, 1)
+        time.sleep(0.05)
+        send(radio, magic[i])
+
+    handshake(radio, "Radio not entering Program mode")
+    rawsend(radio, "\x02")
+    ident = rawrecv(radio, 8)
+    handshake(radio, "Comm error after ident", True)
+
+    if not (radio.TYPE in ident):
+        LOG.debug("Incorrect model ID, got %s" % util.hexprint(ident))
+        msg = "Incorrect model ID, got %s, it not contains %s" % \
+            (ident[0:5], radio.TYPE)
+        raise errors.RadioError(msg)
+
+    # DEBUG
+    #print("Full ident string is %s" % util.hexprint(ident))
+
+    # this is needed, I don't know why, yet
+    send(radio, make_frame("W", 0x03e1, "\xff\x01" + "\xff" * 6))
+    handshake(radio, "Comm error  after setup", True)
+
+
+def do_download(radio):
+    """This is your download function"""
+    open_radio(radio)
+
+     # UI progress
+    status = chirp_common.Status()
+    status.cur = 0
+    status.max = MEM_SIZE / BLOCK_SIZE
+    status.msg = "Cloning from radio..."
+    radio.status_fn(status)
+
+    data = ""
+    for addr in MEM_BLOCKS:
+        send(radio, make_frame("R", addr * BLOCK_SIZE))
+        data += recv(radio)
+        handshake(radio, "Rx error in block %03i" % addr, True)
+        # DEBUG
+        #print("Block: %04x, Pos: %06x" % (addr, addr * BLOCK_SIZE))
+
+        # UI Update
+        status.cur = addr
+        status.msg = "Cloning from radio..."
+        radio.status_fn(status)
+
+    return memmap.MemoryMap(data)
+
+
+def do_upload(radio):
+    """Upload info to radio"""
+    open_radio(radio)
+
+     # UI progress
+    status = chirp_common.Status()
+    status.cur = 0
+    status.max = MEM_SIZE / BLOCK_SIZE
+    status.msg = "Cloning to radio..."
+    radio.status_fn(status)
+    count = 0
+
+    for addr in MEM_BLOCKS:
+        # UI Update
+        status.cur = addr
+        status.msg = "Cloning to radio..."
+        radio.status_fn(status)
+
+        block = addr * BLOCK_SIZE
+        if block > 0x0378:
+            # it seems that from this point forward is read only !?!?!?
+            continue
+
+        send(radio, make_frame("W", block,
+                               radio.get_mmap()[block:block + BLOCK_SIZE]))
+
+        # DEBUG
+        #print("Block: %04x, Pos: %04x" % (addr, addr * BLOCK_SIZE))
+
+        time.sleep(0.1)
+        handshake(radio, "Rx error in block %03i" % addr)
+
+
+def get_rid(data):
+    """Extract the radio identification from the firmware"""
+    rid = data[0x0378:0x0380]
+    # we have to invert rid
+    nrid = ""
+    for i in range(1, len(rid) + 1):
+        nrid += rid[-i]
+    rid = nrid
+
+    return rid
+
+
+def model_match(cls, data):
+    """Match the opened/downloaded image to the correct version"""
+    rid = get_rid(data)
+
+    # DEBUG
+    #print("Full ident string is %s" % util.hexprint(rid))
+
+    if (rid in cls.VARIANTS):
+        # correct model
+        return True
+    else:
+        return False
+
+
+class Kenwood_M60_Radio(chirp_common.CloneModeRadio):
+    """Kenwood Mobile Family 60 Radios"""
+    VENDOR = "Kenwood"
+    _range = [350000000, 500000000]  # don't mind, it will be overited
+    _upper = 32
+    VARIANT = ""
+    MODEL = ""
+
+    @classmethod
+    def get_prompts(cls):
+        rp = chirp_common.RadioPrompts()
+        rp.experimental = \
+            ('This driver is experimental and for personal use only.'
+             'It has a limited set of features, but the most used.\n'
+             '\n'
+             'The most notorius missing features are this:\n'
+             '=> PTT ID, in fact it is disabled if detected\n'
+             '=> Priority / Home channel\n'
+             '=> DTMF/2-Tone\n'
+             '=> Others\n'
+             '\n'
+             'If you need one of this, get your official software to do it'
+             'and raise and issue on the chirp site about it; maybe'
+             'it will be implemented in the future.'
+             )
+        rp.pre_download = _(dedent("""\
+            Follow this instructions to download your info:
+            1 - Turn off your radio
+            2 - Connect your interface cable
+            3 - Do the download of your radio data
+            """))
+        rp.pre_upload = _(dedent("""\
+            Follow this instructions to download your info:
+            1 - Turn off your radio
+            2 - Connect your interface cable
+            3 - Do the upload of your radio data
+            """))
+        return rp
+
+    def get_features(self):
+        rf = chirp_common.RadioFeatures()
+        rf.has_settings = True
+        rf.has_bank = False
+        rf.has_tuning_step = False
+        rf.has_name = False
+        rf.has_offset = True
+        rf.has_mode = True
+        rf.has_dtcs = True
+        rf.has_rx_dtcs = True
+        rf.has_dtcs_polarity = True
+        rf.has_ctone = True
+        rf.has_cross = True
+        rf.valid_modes = MODES
+        rf.valid_duplexes = ["", "-", "+", "off"]
+        rf.valid_tmodes = ['', 'Tone', 'TSQL', 'DTCS', 'Cross']
+        rf.valid_cross_modes = [
+            "Tone->Tone",
+            "DTCS->",
+            "->DTCS",
+            "Tone->DTCS",
+            "DTCS->Tone",
+            "->Tone",
+            "DTCS->DTCS"]
+        rf.valid_power_levels = POWER_LEVELS
+        rf.valid_skips = SKIP_VALUES
+        rf.valid_dtcs_codes = DTCS_CODES
+        rf.valid_bands = [self._range]
+        rf.memory_bounds = (1, self._upper)
+        return rf
+
+    def sync_in(self):
+        """Download from radio"""
+        self._mmap = do_download(self)
+        self.process_mmap()
+
+    def sync_out(self):
+        """Upload to radio"""
+        # Get the data ready for upload
+        try:
+            self._prep_data()
+        except:
+            raise errors.RadioError("Error processing the radio data")
+
+        # do the upload
+        try:
+            do_upload(self)
+        except:
+            raise errors.RadioError("Error uploading data to radio")
+
+    def set_variant(self):
+        """Select and set the correct variables for the class acording
+        to the correct variant of the radio"""
+        rid = get_rid(self._mmap)
+
+        # indentify the radio variant and set the enviroment to it's values
+        try:
+            self._upper, low, high, self._kind = self.VARIANTS[rid]
+            self._range = [low * 1000000, high * 1000000]
+
+            # put the VARIANT in the class, clean the model / CHs / Type
+            # in the same layout as the KPG program
+            self._VARIANT = self.MODEL + " [" + str(self._upper) + "CH]: "
+            self._VARIANT += self._kind + ", "
+            self._VARIANT += str(self._range[0]/1000000) + "-"
+            self._VARIANT += str(self._range[1]/1000000) + " Mhz"
+
+        except KeyError:
+            LOG.debug("Wrong Kenwood radio, ID or unknown variant")
+            LOG.debug(util.hexprint(rid))
+            raise errors.RadioError(
+                "Wrong Kenwood radio, ID or unknown variant, see LOG output.")
+
+    def _prep_data(self):
+        """Prepare the areas in the memmap to do a consistend write
+        it has to make an update on the x200 flag data"""
+        achs = 0
+
+        for i in range(0, self._upper):
+            if self.get_active(i) is True:
+                achs += 1
+
+        # The x0200 area has the settings for the DTMF/2-Tone per channel,
+        # as by default any of this radios has the DTMF IC installed;
+        # we clean this areas
+        fldata = "\x00\xf0\xff\xff\xff" * achs + \
+            "\xff" * (5 * (self._upper - achs))
+        self._fill(0x0200, fldata)
+
+    def _fill(self, offset, data):
+        """Fill an specified area of the memmap with the passed data"""
+        for addr in range(0, len(data)):
+            self._mmap[offset + addr] = data[addr]
+
+    def process_mmap(self):
+        """Process the mem map into the mem object"""
+        self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
+        # to set the vars on the class to the correct ones
+        self.set_variant()
+
+    def get_raw_memory(self, number):
+        return repr(self._memobj.memory[number])
+
+    def decode_tone(self, val):
+        """Parse the tone data to decode from mem, it returns:
+        Mode (''|DTCS|Tone), Value (None|###), Polarity (None,N,R)"""
+        if val.get_raw() == "\xFF\xFF":
+            return '', None, None
+
+        val = int(val)
+        if val >= 12000:
+            a = val - 12000
+            return 'DTCS', a, 'R'
+        elif val >= 8000:
+            a = val - 8000
+            return 'DTCS', a, 'N'
+        else:
+            a = val / 10.0
+            return 'Tone', a, None
+
+    def encode_tone(self, memval, mode, value, pol):
+        """Parse the tone data to encode from UI to mem"""
+        if mode == '':
+            memval[0].set_raw(0xFF)
+            memval[1].set_raw(0xFF)
+        elif mode == 'Tone':
+            memval.set_value(int(value * 10))
+        elif mode == 'DTCS':
+            flag = 0x80 if pol == 'N' else 0xC0
+            memval.set_value(value)
+            memval[1].set_bits(flag)
+        else:
+            raise Exception("Internal error: invalid mode `%s'" % mode)
+
+    def get_scan(self, chan):
+        """Get the channel scan status from the 4 bytes array on the eeprom
+        then from the bits on the byte, return '' or 'S' as needed"""
+        result = "S"
+        byte = int(chan/8)
+        bit = chan % 8
+        res = self._memobj.settings.scan[byte] & (pow(2, bit))
+        if res > 0:
+            result = ""
+
+        return result
+
+    def set_scan(self, chan, value):
+        """Set the channel scan status from UI to the mem_map"""
+        byte = int(chan/8)
+        bit = chan % 8
+
+        # get the actual value to see if I need to change anything
+        actual = self.get_scan(chan)
+        if actual != value:
+            # I have to flip the value
+            rbyte = self._memobj.settings.scan[byte]
+            rbyte = rbyte ^ pow(2, bit)
+            self._memobj.settings.scan[byte] = rbyte
+
+    def get_active(self, chan):
+        """Get the channel active status from the 4 bytes array on the eeprom
+        then from the bits on the byte, return True/False"""
+        byte = int(chan/8)
+        bit = chan % 8
+        res = self._memobj.settings.active[byte] & (pow(2, bit))
+        return bool(res)
+
+    def set_active(self, chan, value=True):
+        """Set the channel active status from UI to the mem_map"""
+        byte = int(chan/8)
+        bit = chan % 8
+
+        # get the actual value to see if I need to change anything
+        actual = self.get_active(chan)
+        if actual != bool(value):
+            # I have to flip the value
+            rbyte = self._memobj.settings.active[byte]
+            rbyte = rbyte ^ pow(2, bit)
+            self._memobj.settings.active[byte] = rbyte
+
+    def get_memory(self, number):
+        """Get the mem representation from the radio image"""
+        _mem = self._memobj.memory[number - 1]
+        _tone = self._memobj.tone[number - 1]
+        _ch = self._memobj.ch_settings[number - 1]
+
+        # Create a high-level memory object to return to the UI
+        mem = chirp_common.Memory()
+
+        # Memory number
+        mem.number = number
+
+        if _mem.get_raw()[0] == "\xFF" or not self.get_active(number - 1):
+            mem.empty = True
+            # but is not enough, you have to crear the memory in the mmap
+            # to get it ready for the sync_out process
+            _mem.set_raw("\xFF" * 8)
+            return mem
+
+        # Freq and offset
+        mem.freq = int(_mem.rxfreq) * 10
+        # tx freq can be blank
+        if _mem.get_raw()[4] == "\xFF":
+            # TX freq not set
+            mem.offset = 0
+            mem.duplex = "off"
+        else:
+            # TX feq set
+            offset = (int(_mem.txfreq) * 10) - mem.freq
+            if offset < 0:
+                mem.offset = abs(offset)
+                mem.duplex = "-"
+            elif offset > 0:
+                mem.offset = offset
+                mem.duplex = "+"
+            else:
+                mem.offset = 0
+
+        # power
+        mem.power = POWER_LEVELS[_ch.power]
+
+        # wide/marrow
+        mem.mode = MODES[_ch.wide]
+
+        # skip
+        mem.skip = self.get_scan(number - 1)
+
+        # tone data
+        rxtone = txtone = None
+        txtone = self.decode_tone(_tone.tx_tone)
+        rxtone = self.decode_tone(_tone.rx_tone)
+        chirp_common.split_tone_decode(mem, txtone, rxtone)
+
+        # Extra
+        # bank and number in the channel
+        mem.extra = RadioSettingGroup("extra", "Extra")
+
+        bl = RadioSetting("busy_lock", "Busy Channel lock",
+                          RadioSettingValueBoolean(
+                              not bool(_ch.busy_lock)))
+        mem.extra.append(bl)
+
+        return mem
+
+    def set_memory(self, mem):
+        """Set the memory data in the eeprom img from the UI
+        not ready yet, so it will return as is"""
+
+        # Get a low-level memory object mapped to the image
+        _mem = self._memobj.memory[mem.number - 1]
+        _tone = self._memobj.tone[mem.number - 1]
+        _ch = self._memobj.ch_settings[mem.number - 1]
+
+        # Empty memory
+        if mem.empty:
+            _mem.set_raw("\xFF" * 8)
+            # empty the active bit
+            self.set_active(mem.number - 1, False)
+            return
+
+        # freq rx
+        _mem.rxfreq = mem.freq / 10
+
+        # freq tx
+        if mem.duplex == "+":
+            _mem.txfreq = (mem.freq + mem.offset) / 10
+        elif mem.duplex == "-":
+            _mem.txfreq = (mem.freq - mem.offset) / 10
+        elif mem.duplex == "off":
+            for i in range(0, 4):
+                _mem.txfreq[i].set_raw("\xFF")
+        else:
+            _mem.txfreq = mem.freq / 10
+
+        # tone data
+        ((txmode, txtone, txpol), (rxmode, rxtone, rxpol)) = \
+            chirp_common.split_tone_encode(mem)
+        self.encode_tone(_tone.tx_tone, txmode, txtone, txpol)
+        self.encode_tone(_tone.rx_tone, rxmode, rxtone, rxpol)
+
+        # power, default power is low
+        if mem.power is None:
+            mem.power = POWER_LEVELS[0]
+
+        _ch.power = POWER_LEVELS.index(mem.power)
+
+        # wide/marrow
+        _ch.wide = MODES.index(mem.mode)
+
+        # skip
+        self.set_scan(mem.number - 1, mem.skip)
+
+        # extra settings
+        for setting in mem.extra:
+            setattr(_mem, setting.get_name(), setting.value)
+
+        # set the mem a active in the _memmap
+        self.set_active(mem.number - 1)
+
+        return mem
+
+    @classmethod
+    def match_model(cls, filedata, filename):
+        match_size = False
+        match_model = False
+
+        # testing the file data size
+        if len(filedata) == MEM_SIZE:
+            match_size = True
+
+        # testing the firmware model fingerprint
+        match_model = model_match(cls, filedata)
+
+        if match_size and match_model:
+            return True
+        else:
+            return False
+
+    def get_settings(self):
+        """Translate the bit in the mem_struct into settings in the UI"""
+        sett = self._memobj.settings
+
+        # basic features of the radio
+        basic = RadioSettingGroup("basic", "Basic Settings")
+        # buttons
+        fkeys = RadioSettingGroup("keys", "Front keys config")
+
+        top = RadioSettings(basic, fkeys)
+
+        # Basic
+        val = RadioSettingValueString(0, 35, self.VARIANT)
+        val.set_mutable(False)
+        mod = RadioSetting("not.mod", "Radio version", val)
+        basic.append(mod)
+
+        tot = RadioSetting("settings.tot", "Time Out Timer (TOT)",
+                           RadioSettingValueList(TOT, TOT[int(sett.tot)]))
+        basic.append(tot)
+
+        minvol = RadioSetting("settings.min_vol", "Minimum volume",
+                              RadioSettingValueList(VOL,
+                                                    VOL[int(sett.min_vol)]))
+        basic.append(minvol)
+
+        ptone = RadioSetting("settings.poweron_tone", "Power On tone",
+                             RadioSettingValueBoolean(
+                                 bool(sett.poweron_tone)))
+        basic.append(ptone)
+
+        sprog = RadioSetting("settings.dealer_tuning", "Dealer Tuning",
+                             RadioSettingValueBoolean(
+                                 bool(sett.dealer_tuning)))
+        basic.append(sprog)
+
+        clone = RadioSetting("settings.clone", "Allow clone",
+                             RadioSettingValueBoolean(
+                                 bool(sett.clone)))
+        basic.append(clone)
+
+        # front keys
+        mon = RadioSetting("settings.kMON", "MON",
+                           RadioSettingValueList(KEYS.values(),
+                           KEYS.values()[KEYS.keys().index(
+                               int(sett.kMON))]))
+        fkeys.append(mon)
+
+        a = RadioSetting("settings.kA", "A",
+                         RadioSettingValueList(KEYS.values(),
+                         KEYS.values()[KEYS.keys().index(
+                             int(sett.kA))]))
+        fkeys.append(a)
+
+        scn = RadioSetting("settings.kSCN", "SCN",
+                           RadioSettingValueList(KEYS.values(),
+                           KEYS.values()[KEYS.keys().index(
+                               int(sett.kSCN))]))
+        fkeys.append(scn)
+
+        da = RadioSetting("settings.kDA", "D/A",
+                          RadioSettingValueList(KEYS.values(),
+                          KEYS.values()[KEYS.keys().index(
+                              int(sett.kDA))]))
+        fkeys.append(da)
+
+        return top
+
+    def set_settings(self, settings):
+        """Translate the settings in the UI into bit in the mem_struct
+        I don't understand well the method used in many drivers
+        so, I used mine, ugly but works ok"""
+
+        mobj = self._memobj
+
+        for element in settings:
+            if not isinstance(element, RadioSetting):
+                self.set_settings(element)
+                continue
+
+            # Let's roll the ball
+            if "." in element.get_name():
+                inter, setting = element.get_name().split(".")
+                # you must ignore the settings with "not"
+                # this are READ ONLY attributes
+                if inter == "not":
+                    continue
+
+                obj = getattr(mobj, inter)
+                value = element.value
+
+                # case keys, with special config
+                if setting[0] == "k":
+                    value = KEYS.keys()[KEYS.values().index(str(value))]
+
+                # integers case + special case
+                if setting in ["tot", "min_vol"]:
+                    # catching the "off" values as zero
+                    try:
+                        value = int(value)
+                    except:
+                        value = 0
+
+                # Bool types + inverted
+                if setting in ["poweron_tone", "dealer_tuning", "clone"]:
+                    value = bool(value)
+
+            # Apply al configs done
+            # DEBUG
+            #print("%s: %s" % (setting, value))
+            setattr(obj, setting, value)
+
+
+# This are the oldest family 60 models (Black keys), just mobiles support here
+
+ at directory.register
+class TK760_Radio(Kenwood_M60_Radio):
+    """Kenwood TK-760 Radios"""
+    MODEL = "TK-760"
+    TYPE = "M0760"
+    VARIANTS = {
+        "M0760\x01\x00\x00": (32, 136, 156, "K2"),
+        "M0760\x00\x00\x00": (32, 148, 174, "K")
+        }
+
+
+ at directory.register
+class TK762_Radio(Kenwood_M60_Radio):
+    """Kenwood TK-762 Radios"""
+    MODEL = "TK-762"
+    TYPE = "M0762"
+    VARIANTS = {
+        "M0762\x01\x00\x00": (2, 136, 156, "K2"),
+        "M0762\x00\x00\x00": (2, 148, 174, "K")
+        }
+
+
+ at directory.register
+class TK768_Radio(Kenwood_M60_Radio):
+    """Kenwood TK-768 Radios"""
+    MODEL = "TK-768"
+    TYPE = "M0768"
+    VARIANTS = {
+        "M0768\x21\x00\x00": (32, 136, 156, "K2"),
+        "M0768\x20\x00\x00": (32, 148, 174, "K")
+        }
+
+
+ at directory.register
+class TK860_Radio(Kenwood_M60_Radio):
+    """Kenwood TK-860 Radios"""
+    MODEL = "TK-860"
+    TYPE = "M0860"
+    VARIANTS = {
+        "M0860\x05\x00\x00": (32, 406, 430, "F4"),
+        "M0860\x04\x00\x00": (32, 488, 512, "F3"),
+        "M0860\x03\x00\x00": (32, 470, 496, "F2"),
+        "M0860\x02\x00\x00": (32, 450, 476, "F1")
+        }
+
+
+ at directory.register
+class TK862_Radio(Kenwood_M60_Radio):
+    """Kenwood TK-862 Radios"""
+    MODEL = "TK-862"
+    TYPE = "M0862"
+    VARIANTS = {
+        "M0862\x05\x00\x00": (2, 406, 430, "F4"),
+        "M0862\x04\x00\x00": (2, 488, 512, "F3"),
+        "M0862\x03\x00\x00": (2, 470, 496, "F2"),
+        "M0862\x02\x00\x00": (2, 450, 476, "F1")
+        }
+
+
+ at directory.register
+class TK868_Radio(Kenwood_M60_Radio):
+    """Kenwood TK-868 Radios"""
+    MODEL = "TK-868"
+    TYPE = "M0868"
+    VARIANTS = {
+        "M0868\x25\x00\x00": (2, 406, 430, "F4"),
+        "M0868\x24\x00\x00": (2, 488, 512, "F3"),
+        "M0868\x23\x00\x00": (2, 470, 496, "F2"),
+        "M0868\x22\x00\x00": (2, 450, 476, "F1")
+        }
diff --git a/chirp/drivers/tk760g.py b/chirp/drivers/tk760g.py
new file mode 100644
index 0000000..94ccd69
--- /dev/null
+++ b/chirp/drivers/tk760g.py
@@ -0,0 +1,1557 @@
+# Copyright 2012 Dan Smith <dsmith at danplanet.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# driver author Pavel Milanes, CO7WT, pavelmc at gmail.com, co7wt at frcuba.co.cu
+
+import logging
+import struct
+from chirp import chirp_common, directory, memmap, errors, util, bitwise
+from textwrap import dedent
+from chirp.settings import RadioSettingGroup, RadioSetting, \
+    RadioSettingValueBoolean, RadioSettingValueList, \
+    RadioSettingValueString, RadioSettingValueInteger, \
+    RadioSettings
+
+LOG = logging.getLogger(__name__)
+
+##### IMPORTANT DATA ##########################################
+# This radios have a span of
+# 0x00000 - 0x08000 => Radio Memory / Settings data
+# 0x08000 - 0x10000 => FIRMWARE... hum...
+###############################################################
+
+MEM_FORMAT = """
+#seekto 0x0000;
+struct {
+  u8 unknown0[14];          // x00-x0d unknown
+  u8 banks;                 // x0e how many banks are programmed
+  u8 channels;              // x0f how many total channels are programmed
+  // --
+  ul16 tot;                 // x10 TOT value: range(15, 600, 15); x04b0 = off
+  u8 tot_rekey;             // x12 TOT Re-key value range(0, 60); off= 0
+  u8 unknown1;              // x13 unknown
+  u8 tot_reset;             // x14 TOT Re-key value range(0, 60); off= 0
+  u8 unknown2;              // x15 unknows
+  u8 tot_alert;             // x16 TOT pre alert: range(0,10); 0 = off
+  u8 unknown3[7];           // x17-x1d unknown
+  u8 sql_level;             // x1e  SQ reference level
+  u8 battery_save;          // Only for portable: FF = off, x32 = on
+  // --
+  u8 unknown4[10];          // x20
+  u8 unknown5:3,            // x2d
+     c2t:1,                 // 1 bit clear to transpond: 1-off
+                            // This is relative to DTMF / 2-Tone settings
+     unknown6:4;
+  u8 unknown7[5];           // x2b-x2f
+  // --
+  u8 unknown8[16];          // x30 ?
+  u8 unknown9[16];          // x40 ?
+  u8 unknown10[16];          // x50 ?
+  u8 unknown11[16];         // x60 ?
+  // --
+  u8 add[16];               // x70-x7f 128 bits corresponding add/skip values
+  // --
+  u8 unknown12:4,           // x80
+     off_hook_decode:1,     // 1 bit off hook decode enabled: 1-off
+     off_hook_horn_alert:1, // 1 bit off hook horn alert: 1-off
+     unknown13:2;
+  u8 unknown14;             // x81
+  u8 unknown15:3,           // x82
+     self_prog:1,           // 1 bit Self programming enabled: 1-on
+     clone:1,               // 1 bit clone enabled: 1-on
+     firmware_prog:1,       // 1 bit firmware programming enabled: 1-on
+     unknown16:1,
+     panel_test:1;          // 1 bit panel test enabled
+  u8 unknown17;             // x83
+  u8 unknown18:5,           // x84
+     warn_tone:1,           // 1 bit warning tone, enabled: 1-on
+     control_tone:1,        // 1 bit control tone (key tone), enabled: 1-on
+     poweron_tone:1;        // 1 bit power on tone, enabled: 1-on
+  u8 unknown19[5];          // x85-x89
+  u8 min_vol;               // minimum volume posible: range(0,32); 0 = off
+  u8 tone_vol;              // minimum tone volume posible:
+                                // xff = continous, range(0, 31)
+  u8 unknown20[4];          // x8c-x8f
+  // --
+  u8 unknown21[4];          // x90-x93
+  char poweronmesg[8];      // x94-x9b power on mesg 8 bytes, off is "\FF" * 8
+  u8 unknown22[4];          // x9c-x9f
+  // --
+  u8 unknown23[7];          // xa0-xa6
+  char ident[8];            // xa7-xae radio identification string
+  u8 unknown24;             // xaf
+  // --
+  u8 unknown26[11];         // xaf-xba
+  char lastsoftversion[5];  // software version employed to program the radio
+} settings;
+
+#seekto 0xd0;
+struct {
+  u8 unknown[4];
+  char radio[6];
+  char data[6];
+} passwords;
+
+#seekto 0x0110;
+struct {
+  u8 kA;                // Portable > Closed circle
+  u8 kDA;               // Protable > Triangle to Left
+  u8 kGROUP_DOWN;       // Protable > Triangle to Right
+  u8 kGROUP_UP;         // Protable > Side 1
+  u8 kSCN;              // Portable > Open Circle
+  u8 kMON;              // Protable > Side 2
+  u8 kFOOT;
+  u8 kCH_UP;
+  u8 kCH_DOWN;
+  u8 kVOL_UP;
+  u8 kVOL_DOWN;
+  u8 unknown30[5];
+  // --
+  u8 unknown31[4];
+  u8 kP_KNOB;           // Just portable: channel knob
+  u8 unknown32[11];
+} keys;
+
+#seekto 0x0140;
+struct {
+  lbcd tf01_rx[4];
+  lbcd tf01_tx[4];
+  u8 tf01_u_rx;
+  u8 tf01_u_tx;
+  lbcd tf02_rx[4];
+  lbcd tf02_tx[4];
+  u8 tf02_u_rx;
+  u8 tf02_u_tx;
+  lbcd tf03_rx[4];
+  lbcd tf03_tx[4];
+  u8 tf03_u_rx;
+  u8 tf03_u_tx;
+  lbcd tf04_rx[4];
+  lbcd tf04_tx[4];
+  u8 tf04_u_rx;
+  u8 tf04_u_tx;
+  lbcd tf05_rx[4];
+  lbcd tf05_tx[4];
+  u8 tf05_u_rx;
+  u8 tf05_u_tx;
+  lbcd tf06_rx[4];
+  lbcd tf06_tx[4];
+  u8 tf06_u_rx;
+  u8 tf06_u_tx;
+  lbcd tf07_rx[4];
+  lbcd tf07_tx[4];
+  u8 tf07_u_rx;
+  u8 tf07_u_tx;
+  lbcd tf08_rx[4];
+  lbcd tf08_tx[4];
+  u8 tf08_u_rx;
+  u8 tf08_u_tx;
+  lbcd tf09_rx[4];
+  lbcd tf09_tx[4];
+  u8 tf09_u_rx;
+  u8 tf09_u_tx;
+  lbcd tf10_rx[4];
+  lbcd tf10_tx[4];
+  u8 tf10_u_rx;
+  u8 tf10_u_tx;
+  lbcd tf11_rx[4];
+  lbcd tf11_tx[4];
+  u8 tf11_u_rx;
+  u8 tf11_u_tx;
+  lbcd tf12_rx[4];
+  lbcd tf12_tx[4];
+  u8 tf12_u_rx;
+  u8 tf12_u_tx;
+  lbcd tf13_rx[4];
+  lbcd tf13_tx[4];
+  u8 tf13_u_rx;
+  u8 tf13_u_tx;
+  lbcd tf14_rx[4];
+  lbcd tf14_tx[4];
+  u8 tf14_u_rx;
+  u8 tf14_u_tx;
+  lbcd tf15_rx[4];
+  lbcd tf15_tx[4];
+  u8 tf15_u_rx;
+  u8 tf15_u_tx;
+  lbcd tf16_rx[4];
+  lbcd tf16_tx[4];
+  u8 tf16_u_rx;
+  u8 tf16_u_tx;
+} test_freq;
+
+#seekto 0x200;
+struct {
+  char line1[32];
+  char line2[32];
+} message;
+
+#seekto 0x2000;
+struct {
+  u8 bnumb;             // mem number
+  u8 bank;              // to which bank it belongs
+  char name[8];         // name 8 chars
+  u8 unknown20[2];      // unknown yet
+  lbcd rxfreq[4];       // rx freq
+  // --
+  lbcd txfreq[4];       // tx freq
+  u8 rx_unkw;           // unknown yet
+  u8 tx_unkw;           // unknown yet
+  ul16 rx_tone;         // rx tone
+  ul16 tx_tone;         // tx tone
+  u8 unknown23[5];      // unknown yet
+  u8 signaling;         // xFF = off, x30 DTMF, x31 2-Tone
+                        // See the zone on x7000
+  // --
+  u8 ptt_id:2,       // ??? BOT = 0, EOT = 1, Both = 2, NONE = 3
+     beat_shift:1,      // 1 = off
+     unknown26:2        // ???
+     power:1,           // power: 0 low / 1 high
+     compander:1,       // 1 = off
+     wide:1;            // wide 1 / 0 narrow
+  u8 unknown27:6,       // ???
+     busy_lock:1,       // 1 = off
+     unknown28:1;       // ???
+  u8 unknown29[14];     // unknown yet
+} memory[128];
+
+#seekto 0x5900;
+struct {
+  char model[8];
+  u8 unknown50[4];
+  char type[2];
+  u8 unknown51[2];
+    // --
+  char serial[8];
+  u8 unknown52[8];
+} id;
+
+#seekto 0x6000;
+struct {
+  u8 code[8];
+  u8 unknown60[7];
+  u8 count;
+} bot[128];
+
+#seekto 0x6800;
+struct {
+  u8 code[8];
+  u8 unknown61[7];
+  u8 count;
+} eot[128];
+
+#seekto 0x7000;
+struct {
+  lbcd dt2_id[5];       // DTMF lbcd ID (000-9999999999)
+                        // 2-Tone = "11 f1 ff ff ff" ???
+                        // None = "00 f0 ff ff ff"
+} dtmf;
+"""
+
+MEM_SIZE = 0x8000  # 32,768 bytes
+BLOCK_SIZE = 256
+BLOCKS = MEM_SIZE / BLOCK_SIZE
+MEM_BLOCKS = range(0, BLOCKS)
+
+# define and empty block of data, as it will be used a lot in this code
+EMPTY_BLOCK = "\xFF" * 256
+
+RO_BLOCKS = range(0x10, 0x1F) + range(0x59, 0x5f)
+ACK_CMD = "\x06"
+
+POWER_LEVELS = [chirp_common.PowerLevel("Low", watts=1),
+                chirp_common.PowerLevel("High", watts=5)]
+
+MODES = ["NFM", "FM"]  # 12.5 / 25 Khz
+VALID_CHARS = chirp_common.CHARSET_UPPER_NUMERIC + "_-*()/\-+=)"
+SKIP_VALUES = ["", "S"]
+
+TONES = chirp_common.TONES
+TONES.remove(254.1)
+DTCS_CODES = chirp_common.DTCS_CODES
+
+TOT = ["off"] + ["%s" % x for x in range(15, 615, 15)]
+TOT_PRE = ["off"] + ["%s" % x for x in range(1, 11)]
+TOT_REKEY = ["off"] + ["%s" % x for x in range(1, 61)]
+TOT_RESET = ["off"] + ["%s" % x for x in range(1, 16)]
+VOL = ["off"] + ["%s" % x for x in range(1, 32)]
+TVOL = ["%s" % x for x in range(0, 33)]
+TVOL[32] = "Continous"
+SQL = ["off"] + ["%s" % x for x in range(1, 10)]
+
+## BOT = 0, EOT = 1, Both = 2, NONE = 3
+#PTTID = ["BOT", "EOT", "Both", "none"]
+
+KEYS = {
+    0x33: "Display character",
+    0x35: "Home Channel",                   # Posible portable only, chek it
+    0x37: "CH down",
+    0x38: "CH up",
+    0x39: "Key lock",
+    0x3a: "Lamp",                           # Portable only
+    0x3b: "Public address",
+    0x3c: "Reverse",                        # Just in updated firmwares (768G)
+    0x3d: "Horn alert",
+    0x3e: "Selectable QT",                  # Just in updated firmwares (768G)
+    0x3f: "2-tone encode",
+    0x40: "Monitor A: open mommentary",
+    0x41: "Monitor B: Open Toggle",
+    0x42: "Monitor C: Carrier mommentary",
+    0x43: "Monitor D: Carrier toogle",
+    0x44: "Operator selectable tone",
+    0x45: "Redial",
+    0x46: "RF Power Low",                   # portable only ?
+    0x47: "Scan",
+    0x48: "Scan del/add",
+    0x4a: "GROUP down",
+    0x4b: "GROUP up",
+    #0x4e: "Tone off (Experimental)",       # undocumented !!!!
+    0x4f: "None",
+    0x50: "VOL down",
+    0x51: "VOL up",
+    0x52: "Talk around",
+    0x5d: "AUX",
+    0xa1: "Channel Up/Down"                 # Knob for portables only
+    }
+
+
+def _raw_recv(radio, amount):
+    """Raw read from the radio device"""
+    data = ""
+    try:
+        data = radio.pipe.read(amount)
+    except:
+        raise errors.RadioError("Error reading data from radio")
+
+    return data
+
+
+def _raw_send(radio, data):
+    """Raw send to the radio device"""
+    try:
+        radio.pipe.write(data)
+    except:
+        raise errors.RadioError("Error sending data to radio")
+
+
+def _close_radio(radio):
+    """Get the radio out of program mode"""
+    # 3 times, it will don't harm in normal work,
+    # but it help's a lot in the developer process
+    _raw_send(radio, "\x45\x45\x45")
+
+
+def _checksum(data):
+    """the radio block checksum algorithm"""
+    cs = 0
+    for byte in data:
+            cs += ord(byte)
+    return cs % 256
+
+
+def _send(radio, frame):
+    """Generic send data to the radio"""
+    _raw_send(radio, frame)
+
+
+def _make_frame(cmd, addr):
+    """Pack the info in the format it likes"""
+    return struct.pack(">BH", ord(cmd), addr)
+
+
+def _handshake(radio, msg=""):
+    """Make a full handshake"""
+    # send ACK
+    _raw_send(radio, ACK_CMD)
+    # receive ACK
+    ack = _raw_recv(radio, 1)
+    # check ACK
+    if ack != ACK_CMD:
+        _close_radio(radio)
+        mesg = "Handshake failed " + msg
+        raise Exception(mesg)
+
+
+def _check_write_ack(r, ack, addr):
+    """Process the ack from the flock write process
+    this is half handshake needed in tx data block"""
+    # all ok
+    if ack == ACK_CMD:
+        return
+
+    # Explicit BAD checksum
+    if ack == "\x15":
+        _close_radio(r)
+        raise errors.RadioError(
+            "Bad checksum in block %02x write" % addr)
+
+    # everything else
+    _close_radio(r)
+    raise errors.RadioError(
+        "Problem with the ack to block %02x write, ack %03i" %
+        (addr, int(ack)))
+
+
+def _recv(radio):
+    """Receive data from the radio, 258 bytes split in (cmd, data, checksum)
+    checking the checksum to be correct, and returning just
+    256 bytes of data or false if short empty block"""
+    rxdata = _raw_recv(radio, BLOCK_SIZE + 2)
+    # when the RX block has two bytes and the first is \x5A
+    # then the block is all \xFF
+    if len(rxdata) == 2 and rxdata[0] == "\x5A":
+        _handshake(radio, "short block")
+        return False
+    else:
+        rcs = ord(rxdata[-1])
+        data = rxdata[1:-1]
+        ccs = _checksum(data)
+
+        if rcs != ccs:
+            _close_radio(radio)
+            raise errors.RadioError(
+                "Block Checksum Error! real %02x, calculated %02x" %
+                (rcs, ccs))
+
+        _handshake(radio, "after checksum")
+        return data
+
+
+def _open_radio(radio):
+    """Open the radio into program mode and check if it's the correct model"""
+    radio.pipe.setTimeout(0.25)  # only works in the range 0.2 - 0.3
+    radio.pipe.setParity("E")
+
+    _raw_send(radio, "PROGRAM")
+    ack = _raw_recv(radio, 1)
+
+    if ack != ACK_CMD:
+        # bad response, properly close the radio before exception
+        _close_radio(radio)
+        raise errors.RadioError("The radio doesn't accept program mode")
+
+    _raw_send(radio, "\x02")
+    rid = _raw_recv(radio, 8)
+
+    if not (radio.TYPE in rid):
+        # bad response, properly close the radio before exception
+        _close_radio(radio)
+        # LOG.debug("Incorrect model ID, got %s" % util.hexprint(rid))
+        raise errors.RadioError(
+            "Incorrect model ID, got %s, it not contains %s" %
+            (rid.strip("\xff"), radio.TYPE))
+
+    # DEBUG
+    LOG.debug("Full ident string is: %s" % util.hexprint(rid))
+    _handshake(radio)
+
+
+def do_download(radio):
+    """ The download function """
+    _open_radio(radio)
+
+    # speed up the reading
+    radio.pipe.setTimeout(0.03)  # only works in the range 0.25 and up
+
+    # UI progress
+    status = chirp_common.Status()
+    status.cur = 0
+    status.max = MEM_SIZE / 256
+    status.msg = "Cloning from radio..."
+    radio.status_fn(status)
+    data = ""
+    count = 0
+
+    for addr in MEM_BLOCKS:
+        _send(radio, _make_frame("R", addr))
+        d = _recv(radio)
+        # if empty block, it return false
+        # aka we asume a empty 256 xFF block
+        if d is False:
+            d = EMPTY_BLOCK
+
+        data += d
+
+        # UI Update
+        status.cur = count
+        status.msg = "Cloning from radio..."
+        radio.status_fn(status)
+
+        count += 1
+
+    _close_radio(radio)
+    return memmap.MemoryMap(data)
+
+
+def do_upload(radio):
+    """ The upload function """
+    _open_radio(radio)
+
+    # Radio need time to write data to eeprom
+    # 0.55 seconds as per the original software...
+    radio.pipe.setTimeout(0.55)
+
+    # UI progress
+    status = chirp_common.Status()
+    status.cur = 0
+    status.max = BLOCKS
+    status.msg = "Cloning to radio..."
+    radio.status_fn(status)
+
+    count = 0
+    raddr = 0
+
+    for addr in MEM_BLOCKS:
+        # this is the data block to write
+        data = radio.get_mmap()[raddr:raddr+BLOCK_SIZE]
+
+        # The blocks from x59-x5F are NOT programmable
+        # The blocks from x11-x1F are writed only if not empty
+        if addr in RO_BLOCKS:
+            # checking if in the range of optional blocks
+            if addr >= 0x10 and addr <= 0x1F:
+                # block is empty ?
+                if data == EMPTY_BLOCK:
+                    # no write of this block
+                    # but we have to continue updating the counters
+                    count += 1
+                    raddr = count * 256
+                    continue
+            else:
+                count += 1
+                raddr = count * 256
+                continue
+
+        if data == EMPTY_BLOCK:
+            frame = _make_frame("Z", addr) + "\xFF"
+        else:
+            cs = _checksum(data)
+            frame = _make_frame("W", addr) + data + chr(cs)
+
+        _send(radio, frame)
+        ack = _raw_recv(radio, 1)
+        _check_write_ack(radio, ack, addr)
+
+        # UI Update
+        status.cur = count
+        status.msg = "Cloning to radio..."
+        radio.status_fn(status)
+
+        count += 1
+        raddr = count * 256
+
+    _close_radio(radio)
+
+
+def model_match(cls, data):
+    """Match the opened/downloaded image to the correct version"""
+    rid = data[0xA7:0xAE]
+    if (rid in cls.VARIANTS):
+        # correct model
+        return True
+    else:
+        return False
+
+
+class Kenwood60GBankModel(chirp_common.BankModel):
+    """Testing the bank model on kennwood"""
+    channelAlwaysHasBank = True
+
+    def get_num_mappings(self):
+        return self._radio._num_banks
+
+    def get_mappings(self):
+        banks = []
+        for i in range(0, self._radio._num_banks):
+            bindex = i + 1
+            bank = self._radio._bclass(self, i, "%03i" % bindex)
+            bank.index = i
+            banks.append(bank)
+        return banks
+
+    def add_memory_to_mapping(self, memory, bank):
+        self._radio._set_bank(memory.number, bank.index)
+
+    def remove_memory_from_mapping(self, memory, bank):
+        if self._radio._get_bank(memory.number) != bank.index:
+            raise Exception("Memory %i not in bank %s. Cannot remove." %
+                            (memory.number, bank))
+
+        # Warning about removing a channel on bank 0
+        #if bank.index == self._radio._get_bank(memory.number) == 0:
+            #mesg = "Can't remove, this is the default bank for "
+            #mesg += "all channels"
+            #raise Exception(mesg)
+
+        # We can't "Remove" it for good
+        # the kenwood paradigm don't allow it
+        # instead we move it to bank 0
+        self._radio._set_bank(memory.number, 0)
+
+    def get_mapping_memories(self, bank):
+        memories = []
+        for i in range(0, self._radio._upper):
+            if self._radio._get_bank(i) == bank.index:
+                memories.append(self._radio.get_memory(i))
+        return memories
+
+    def get_memory_mappings(self, memory):
+        index = self._radio._get_bank(memory.number)
+        return [self.get_mappings()[index]]
+
+
+class memBank(chirp_common.Bank):
+    """A bank model for kenwood"""
+    # Integral index of the bank (not to be confused with per-memory
+    # bank indexes
+    index = 0
+
+
+class Kenwood_Serie_60G(chirp_common.CloneModeRadio):
+    """Kenwood Serie 60G Radios base class"""
+    VENDOR = "Kenwood"
+    BAUD_RATE = 9600
+    _memsize = MEM_SIZE
+    NAME_LENGTH = 8
+    _range = [136000000, 162000000]
+    _upper = 128
+    _chs_progs = 0
+    _num_banks = 128
+    _bclass = memBank
+    _kind = ""
+    VARIANT = ""
+    MODEL = ""
+
+    @classmethod
+    def get_prompts(cls):
+        rp = chirp_common.RadioPrompts()
+        rp.experimental = \
+            ('This driver is experimental and for personal use only.'
+             'It has a limited set of features, but the most used.'
+             ''
+             'The most notorius missing features are this:'
+             '=> PTT ID, in fact it is disabled if detected'
+             '=> Priority / Home channel'
+             '=> Bank names'
+             '=> Others'
+             ''
+             'If you need one of this, get your official software to do it'
+             'and raise and issue on the chirp site about it and maybe'
+             'it will be implemented in the future.'
+             )
+        rp.pre_download = _(dedent("""\
+            Follow this instructions to download your info:
+            1 - Turn off your radio
+            2 - Connect your interface cable
+            3 - Turn on your radio (unblock it if password protected)
+            4 - Do the download of your radio data
+            """))
+        rp.pre_upload = _(dedent("""\
+            Follow this instructions to download your info:
+            1 - Turn off your radio
+            2 - Connect your interface cable
+            3 - Turn on your radio (unblock it if password protected)
+            4 - Do the download of your radio data
+            """))
+        return rp
+
+    def get_features(self):
+        """Return information about this radio's features"""
+        rf = chirp_common.RadioFeatures()
+        rf.has_settings = True
+        rf.has_bank = True
+        rf.has_tuning_step = False
+        rf.has_name = True
+        rf.has_offset = True
+        rf.has_mode = True
+        rf.has_dtcs = True
+        rf.has_rx_dtcs = True
+        rf.has_dtcs_polarity = True
+        rf.has_ctone = True
+        rf.has_cross = True
+        rf.valid_modes = MODES
+        rf.valid_duplexes = ["", "-", "+", "off"]
+        rf.valid_tmodes = ['', 'Tone', 'TSQL', 'DTCS', 'Cross']
+        rf.valid_cross_modes = [
+            "Tone->Tone",
+            "DTCS->",
+            "->DTCS",
+            "Tone->DTCS",
+            "DTCS->Tone",
+            "->Tone",
+            "DTCS->DTCS"]
+        rf.valid_power_levels = POWER_LEVELS
+        rf.valid_characters = VALID_CHARS
+        rf.valid_skips = SKIP_VALUES
+        rf.valid_dtcs_codes = DTCS_CODES
+        rf.valid_bands = [self._range]
+        rf.valid_name_length = 8
+        rf.memory_bounds = (1, self._upper)
+        return rf
+
+    def _fill(self, offset, data):
+        """Fill an specified area of the memmap with the passed data"""
+        for addr in range(0, len(data)):
+            self._mmap[offset + addr] = data[addr]
+
+    def _prep_data(self):
+        """Prepare the areas in the memmap to do a consistend write
+        it has to make an update on the x300 area with banks and channel
+        info; other in the x1000 with banks and channel counts
+        and a last one in x7000 with flog data"""
+        rchs = 0
+        data = dict()
+
+        # sorting the data
+        for ch in range(0, self._upper):
+            mem = self._memobj.memory[ch]
+            bnumb = int(mem.bnumb)
+            bank = int(mem.bank)
+            if bnumb != 255 and (bank != 255 and bank != 0):
+                try:
+                    data[bank].append(ch)
+                except:
+                    data[bank] = list()
+                    data[bank].append(ch)
+                data[bank].sort()
+                # counting the real channels
+                rchs = rchs + 1
+
+        # updating the channel/bank count
+        self._memobj.settings.channels = rchs
+        self._chs_progs = rchs
+        self._memobj.settings.banks = len(data)
+
+        # building the data for the memmap
+        fdata = ""
+
+        for k, v in data.iteritems():
+            # posible bad data
+            if k == 0:
+                k = 1
+                raise errors.InvalidValueError(
+                    "Invalid bank value '%k', bad data in the image? \
+                    Triying to fix this, review your bank data!" % k)
+            c = 1
+            for i in v:
+                fdata += chr(k) + chr(c) + chr(k - 1) + chr(i)
+                c = c + 1
+
+        # fill to match a full 256 bytes block
+        fdata += (len(fdata) % 256) * "\xFF"
+
+        # updating the data in the memmap [x300]
+        self._fill(0x300, fdata)
+
+        # update the info in x1000; it has 2 bytes with
+        # x00 = bank , x01 = bank's channel count
+        # the rest of the 14 bytes are \xff
+        bdata = ""
+        for i in range(1, len(data) + 1):
+            line = chr(i) + chr(len(data[i]))
+            line += "\xff" * 14
+            bdata += line
+
+        # fill to match a full 256 bytes block
+        bdata += (256 - (len(bdata)) % 256) * "\xFF"
+
+        # fill to match the whole area
+        bdata += (16 - len(bdata) / 256) * EMPTY_BLOCK
+
+        # updating the data in the memmap [x1000]
+        self._fill(0x1000, bdata)
+
+        # DTMF id for each channel, 5 bytes lbcd at x7000
+        # ############## TODO ###################
+        fldata = "\x00\xf0\xff\xff\xff" * self._chs_progs + \
+            "\xff" * (5 * (self._upper - self._chs_progs))
+
+        # write it
+        # updating the data in the memmap [x7000]
+        self._fill(0x7000, fldata)
+
+    def _set_variant(self):
+        """Select and set the correct variables for the class acording
+        to the correct variant of the radio"""
+        rid = self._mmap[0xA7:0xAE]
+
+        # indentify the radio variant and set the enviroment to it's values
+        try:
+            self._upper, low, high, self._kind = self.VARIANTS[rid]
+            self._range = [low * 1000000, high * 1000000]
+
+            # setting the bank data in the features, 8 & 16 CH dont have banks
+            if self._upper < 32:
+                rf = chirp_common.RadioFeatures()
+                rf.has_bank = False
+
+            # put the VARIANT in the class, clean the model / CHs / Type
+            # in the same layout as the KPG program
+            self._VARIANT = self.MODEL + " [" + str(self._upper) + "CH]: "
+            self._VARIANT += self._kind + ", " + str(self._range[0]/1000000) + "-"
+            self._VARIANT += str(self._range[1]/1000000) + " Mhz"
+
+        except KeyError:
+            LOG.debug("Wrong Kenwood radio, ID or unknown variant")
+            LOG.debug(util.hexprint(rid))
+            raise errors.RadioError(
+                "Wrong Kenwood radio, ID or unknown variant, see LOG output.")
+            return False
+
+    def sync_in(self):
+        """Do a download of the radio eeprom"""
+        self._mmap = do_download(self)
+        self.process_mmap()
+
+    def sync_out(self):
+        """Do an upload to the radio eeprom"""
+
+        # chirp signature on the eprom ;-)
+        sign = "Chirp"
+        self._fill(0xbb, sign)
+
+        try:
+            self._prep_data()
+            do_upload(self)
+        except errors.RadioError:
+            raise
+        except Exception, e:
+            raise errors.RadioError("Failed to communicate with radio: %s" % e)
+
+    def process_mmap(self):
+        """Process the memory object"""
+        # how many channels are programed
+        self._chs_progs = ord(self._mmap[15])
+        # load the memobj
+        self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
+        # to ser the vars on the class to the correct ones
+        self._set_variant()
+
+    def get_raw_memory(self, number):
+        """Return a raw representation of the memory object, which
+        is very helpful for development"""
+        return repr(self._memobj.memory[number])
+
+    def _decode_tone(self, val):
+        """Parse the tone data to decode from mem, it returns:
+        Mode (''|DTCS|Tone), Value (None|###), Polarity (None,N,R)"""
+        val = int(val)
+        if val == 65535:
+            return '', None, None
+        elif val >= 0x2800:
+            code = int("%03o" % (val & 0x07FF))
+            pol = (val & 0x8000) and "R" or "N"
+            return 'DTCS', code, pol
+        else:
+            a = val / 10.0
+            return 'Tone', a, None
+
+    def _encode_tone(self, memval, mode, value, pol):
+        """Parse the tone data to encode from UI to mem"""
+        if mode == '':
+            memval.set_raw("\xff\xff")
+        elif mode == 'Tone':
+            memval.set_value(int(value * 10))
+        elif mode == 'DTCS':
+            val = int("%i" % value, 8) + 0x2800
+            if pol == "R":
+                val += 0xA000
+            memval.set_value(val)
+        else:
+            raise Exception("Internal error: invalid mode `%s'" % mode)
+
+    def _get_scan(self, chan):
+        """Get the channel scan status from the 16 bytes array on the eeprom
+        then from the bits on the byte, return '' or 'S' as needed"""
+        result = "S"
+        byte = int(chan/8)
+        bit = chan % 8
+        res = self._memobj.settings.add[byte] & (pow(2, bit))
+        if res > 0:
+            result = ""
+
+        return result
+
+    def _set_scan(self, chan, value):
+        """Set the channel scan status from UI to the mem_map"""
+        byte = int(chan/8)
+        bit = chan % 8
+
+        # get the actual value to see if I need to change anything
+        actual = self._get_scan(chan)
+        if actual != value:
+            # I have to flip the value
+            rbyte = self._memobj.settings.add[byte]
+            rbyte = rbyte ^ pow(2, bit)
+            self._memobj.settings.add[byte] = rbyte
+
+    def get_memory(self, number):
+        # Get a low-level memory object mapped to the image
+        _mem = self._memobj.memory[number - 1]
+
+        # Create a high-level memory object to return to the UI
+        mem = chirp_common.Memory()
+
+        # Memory number
+        mem.number = number
+
+        # this radio has a setting about the amount of real chans of the 128
+        # olso in the channel has xff on the Rx freq it's empty
+        if (number > (self._chs_progs + 1)) or (_mem.get_raw()[0] == "\xFF"):
+            mem.empty = True
+            # but is not enough, you have to crear the memory in the mmap
+            # to get it ready for the sync_out process
+            _mem.set_raw("\xFF" * 48)
+            return mem
+
+        # Freq and offset
+        mem.freq = int(_mem.rxfreq) * 10
+        # tx freq can be blank
+        if _mem.get_raw()[16] == "\xFF":
+            # TX freq not set
+            mem.offset = 0
+            mem.duplex = "off"
+        else:
+            # TX feq set
+            offset = (int(_mem.txfreq) * 10) - mem.freq
+            if offset < 0:
+                mem.offset = abs(offset)
+                mem.duplex = "-"
+            elif offset > 0:
+                mem.offset = offset
+                mem.duplex = "+"
+            else:
+                mem.offset = 0
+
+        # name TAG of the channel
+        mem.name = str(_mem.name).rstrip()
+
+        # power
+        mem.power = POWER_LEVELS[_mem.power]
+
+        # wide/marrow
+        mem.mode = MODES[_mem.wide]
+
+        # skip
+        mem.skip = self._get_scan(number - 1)
+
+        # tone data
+        rxtone = txtone = None
+        txtone = self._decode_tone(_mem.tx_tone)
+        rxtone = self._decode_tone(_mem.rx_tone)
+        chirp_common.split_tone_decode(mem, txtone, rxtone)
+
+        # Extra
+        # bank and number in the channel
+        mem.extra = RadioSettingGroup("extra", "Extra")
+
+        # validate bank
+        b = int(_mem.bank)
+        if b > 127 or b == 0:
+            _mem.bank = b = 1
+
+        bank = RadioSetting("bank", "Bank it belongs",
+                            RadioSettingValueInteger(1, 128, b))
+        mem.extra.append(bank)
+
+        # validate bnumb
+        if int(_mem.bnumb) > 127:
+            _mem.bank = mem.number
+
+        bnumb = RadioSetting("bnumb", "Ch number in the bank",
+                             RadioSettingValueInteger(0, 127, _mem.bnumb))
+        mem.extra.append(bnumb)
+
+        bs = RadioSetting("beat_shift", "Beat shift",
+                          RadioSettingValueBoolean(
+                              not bool(_mem.beat_shift)))
+        mem.extra.append(bs)
+
+        cp = RadioSetting("compander", "Compander",
+                          RadioSettingValueBoolean(
+                              not bool(_mem.compander)))
+        mem.extra.append(cp)
+
+        bl = RadioSetting("busy_lock", "Busy Channel lock",
+                          RadioSettingValueBoolean(
+                              not bool(_mem.busy_lock)))
+        mem.extra.append(bl)
+
+        return mem
+
+    def set_memory(self, mem):
+        """Set the memory data in the eeprom img from the UI
+        not ready yet, so it will return as is"""
+
+        # get the eprom representation of this channel
+        _mem = self._memobj.memory[mem.number - 1]
+
+        # if empty memmory
+        if mem.empty:
+            _mem.set_raw("\xFF" * 48)
+            return
+
+        # frequency
+        _mem.rxfreq = mem.freq / 10
+
+        # this are a mistery yet, but so falr there is no impact
+        # whit this default values for new channels
+        if int(_mem.rx_unkw) == 0xff:
+            _mem.rx_unkw = 0x35
+            _mem.tx_unkw = 0x32
+
+        # duplex
+        if mem.duplex == "+":
+            _mem.txfreq = (mem.freq + mem.offset) / 10
+        elif mem.duplex == "-":
+            _mem.txfreq = (mem.freq - mem.offset) / 10
+        else:
+            _mem.txfreq = mem.freq / 10
+
+        # tone data
+        ((txmode, txtone, txpol), (rxmode, rxtone, rxpol)) = \
+            chirp_common.split_tone_encode(mem)
+        self._encode_tone(_mem.tx_tone, txmode, txtone, txpol)
+        self._encode_tone(_mem.rx_tone, rxmode, rxtone, rxpol)
+
+        # name TAG of the channel
+        _namelength = self.get_features().valid_name_length
+        for i in range(_namelength):
+            try:
+                _mem.name[i] = mem.name[i]
+            except IndexError:
+                _mem.name[i] = "\x20"
+
+        # power
+        # default power is low
+        if mem.power is None:
+            mem.power = POWER_LEVELS[0]
+
+        _mem.power = POWER_LEVELS.index(mem.power)
+
+        # wide/marrow
+        _mem.wide = MODES.index(mem.mode)
+
+        # scan add property
+        self._set_scan(mem.number - 1, mem.skip)
+
+        # bank and number in the channel
+        if int(_mem.bnumb) == 0xff:
+            _mem.bnumb = mem.number - 1
+            _mem.bank = 1
+
+        # extra settings
+        for setting in mem.extra:
+            if setting != "bank" or setting != "bnumb":
+                setattr(_mem, setting.get_name(), not bool(setting.value))
+
+        # all data get sync after channel mod
+        #self._prep_data()
+
+        return mem
+
+    @classmethod
+    def match_model(cls, filedata, filename):
+        match_size = False
+        match_model = False
+
+        # testing the file data size
+        if len(filedata) == MEM_SIZE:
+            match_size = True
+
+        # testing the firmware model fingerprint
+        match_model = model_match(cls, filedata)
+
+        if match_size and match_model:
+            return True
+        else:
+            return False
+
+    def get_settings(self):
+        """Translate the bit in the mem_struct into settings in the UI"""
+        sett = self._memobj.settings
+        mess = self._memobj.message
+        keys = self._memobj.keys
+        idm = self._memobj.id
+        passwd = self._memobj.passwords
+
+        # basic features of the radio
+        basic = RadioSettingGroup("basic", "Basic Settings")
+        # dealer settings
+        dealer = RadioSettingGroup("dealer", "Dealer Settings")
+        # buttons
+        fkeys = RadioSettingGroup("keys", "Front keys config")
+
+        # TODO / PLANED
+        # adjust feqs
+        #freqs = RadioSettingGroup("freqs", "Adjust Frequencies")
+
+        top = RadioSettings(basic, dealer, fkeys)
+
+        # Basic
+        tot = RadioSetting("settings.tot", "Time Out Timer (TOT)",
+                           RadioSettingValueList(TOT, TOT[
+                           TOT.index(str(int(sett.tot)))]))
+        basic.append(tot)
+
+        totalert = RadioSetting("settings.tot_alert", "TOT pre alert",
+                                RadioSettingValueList(TOT_PRE,
+                                TOT_PRE[int(sett.tot_alert)]))
+        basic.append(totalert)
+
+        totrekey = RadioSetting("settings.tot_rekey", "TOT re-key time",
+                                RadioSettingValueList(TOT_REKEY,
+                                TOT_REKEY[int(sett.tot_rekey)]))
+        basic.append(totrekey)
+
+        totreset = RadioSetting("settings.tot_reset", "TOT reset time",
+                                RadioSettingValueList(TOT_RESET,
+                                TOT_RESET[int(sett.tot_reset)]))
+        basic.append(totreset)
+
+        # this feature is for mobile only
+        if self.TYPE[0] == "M":
+            minvol = RadioSetting("settings.min_vol", "Minimum volume",
+                                  RadioSettingValueList(VOL,
+                                  VOL[int(sett.min_vol)]))
+            basic.append(minvol)
+
+            tv = int(sett.tone_vol)
+            if tv == 255:
+                tv = 32
+            tvol = RadioSetting("settings.tone_vol", "Minimum tone volume",
+                                RadioSettingValueList(TVOL, TVOL[tv]))
+            basic.append(tvol)
+
+        sql = RadioSetting("settings.sql_level", "SQL Ref Level",
+                           RadioSettingValueList(
+                           SQL, SQL[int(sett.sql_level)]))
+        basic.append(sql)
+
+        #c2t = RadioSetting("settings.c2t", "Clear to Transpond",
+                           #RadioSettingValueBoolean(not sett.c2t))
+        #basic.append(c2t)
+
+        ptone = RadioSetting("settings.poweron_tone", "Power On tone",
+                             RadioSettingValueBoolean(sett.poweron_tone))
+        basic.append(ptone)
+
+        ctone = RadioSetting("settings.control_tone", "Control (key) tone",
+                             RadioSettingValueBoolean(sett.control_tone))
+        basic.append(ctone)
+
+        wtone = RadioSetting("settings.warn_tone", "Warning tone",
+                             RadioSettingValueBoolean(sett.warn_tone))
+        basic.append(wtone)
+
+        # Save Battery only for portables?
+        if self.TYPE[0] == "P":
+            bs = int(sett.battery_save) == 0x32 and True or False
+            bsave = RadioSetting("settings.battery_save", "Battery Saver",
+                                 RadioSettingValueBoolean(bs))
+            basic.append(bsave)
+
+        ponm = str(sett.poweronmesg).strip("\xff")
+        pom = RadioSetting("settings.poweronmesg", "Power on message",
+                           RadioSettingValueString(0, 8, ponm, False))
+        basic.append(pom)
+
+        # dealer
+        mstr = ""
+        valid_chars = [32, 44, 45, 47, 58, 91, 93] + range(48, 58) + \
+            range(65, 91) + range(97, 123)
+
+        for i in range(0, len(self._VARIANT)):
+            if ord(self._VARIANT[i]) in valid_chars:
+                mstr += self._VARIANT[i]
+
+        val = RadioSettingValueString(0, 35, mstr)
+        val.set_mutable(False)
+        mod = RadioSetting("not.mod", "Radio Version", val)
+        dealer.append(mod)
+
+        sn = str(idm.serial).strip(" \xff")
+        val = RadioSettingValueString(0, 8, sn)
+        val.set_mutable(False)
+        serial = RadioSetting("not.serial", "Serial number", val)
+        dealer.append(serial)
+
+        svp = str(sett.lastsoftversion).strip(" \xff")
+        val = RadioSettingValueString(0, 5, svp)
+        val.set_mutable(False)
+        sver = RadioSetting("not.softver", "Software Version", val)
+        dealer.append(sver)
+
+        l1 = str(mess.line1).strip(" \xff")
+        line1 = RadioSetting("message.line1", "Comment 1",
+                           RadioSettingValueString(0, 32, l1))
+        dealer.append(line1)
+
+        l2 = str(mess.line2).strip(" \xff")
+        line2 = RadioSetting("message.line2", "Comment 2",
+                             RadioSettingValueString(0, 32, l2))
+        dealer.append(line2)
+
+        sprog = RadioSetting("settings.self_prog", "Self program",
+                             RadioSettingValueBoolean(sett.self_prog))
+        dealer.append(sprog)
+
+        clone = RadioSetting("settings.clone", "Allow clone",
+                             RadioSettingValueBoolean(sett.clone))
+        dealer.append(clone)
+
+        panel = RadioSetting("settings.panel_test", "Panel Test",
+                             RadioSettingValueBoolean(sett.panel_test))
+        dealer.append(panel)
+
+        fmw = RadioSetting("settings.firmware_prog", "Firmware program",
+                           RadioSettingValueBoolean(sett.firmware_prog))
+        dealer.append(fmw)
+
+        # front keys
+        # The Mobile only parameters are wraped here
+        if self.TYPE[0] == "M":
+            vu = RadioSetting("keys.kVOL_UP", "VOL UP",
+                              RadioSettingValueList(KEYS.values(),
+                              KEYS.values()[KEYS.keys().index(
+                                  int(keys.kVOL_UP))]))
+            fkeys.append(vu)
+
+            vd = RadioSetting("keys.kVOL_DOWN", "VOL DOWN",
+                              RadioSettingValueList(KEYS.values(),
+                              KEYS.values()[KEYS.keys().index(
+                                  int(keys.kVOL_DOWN))]))
+            fkeys.append(vd)
+
+            chu = RadioSetting("keys.kCH_UP", "CH UP",
+                               RadioSettingValueList(KEYS.values(),
+                               KEYS.values()[KEYS.keys().index(
+                                   int(keys.kCH_UP))]))
+            fkeys.append(chu)
+
+            chd = RadioSetting("keys.kCH_DOWN", "CH DOWN",
+                               RadioSettingValueList(KEYS.values(),
+                               KEYS.values()[KEYS.keys().index(
+                                   int(keys.kCH_DOWN))]))
+            fkeys.append(chd)
+
+            foot = RadioSetting("keys.kFOOT", "Foot switch",
+                               RadioSettingValueList(KEYS.values(),
+                               KEYS.values()[KEYS.keys().index(
+                                   int(keys.kCH_DOWN))]))
+            fkeys.append(foot)
+
+        # this is the common buttons for all
+
+        # 260G model don't have the front keys
+        if not "P2600" in self.TYPE:
+            scn_name = "SCN"
+            if self.TYPE[0] == "P":
+                scn_name = "Open Circle"
+
+            scn = RadioSetting("keys.kSCN", scn_name,
+                               RadioSettingValueList(KEYS.values(),
+                               KEYS.values()[KEYS.keys().index(
+                                   int(keys.kSCN))]))
+            fkeys.append(scn)
+
+            a_name = "A"
+            if self.TYPE[0] == "P":
+                a_name = "Closed circle"
+
+            a = RadioSetting("keys.kA", a_name,
+                             RadioSettingValueList(KEYS.values(),
+                             KEYS.values()[KEYS.keys().index(
+                                 int(keys.kA))]))
+            fkeys.append(a)
+
+            da_name = "D/A"
+            if self.TYPE[0] == "P":
+                da_name = "< key"
+
+            da = RadioSetting("keys.kDA", da_name,
+                              RadioSettingValueList(KEYS.values(),
+                              KEYS.values()[KEYS.keys().index(
+                                  int(keys.kDA))]))
+            fkeys.append(da)
+
+            gu_name = "Triangle up"
+            if self.TYPE[0] == "P":
+                gu_name = "Side 1"
+
+            gu = RadioSetting("keys.kGROUP_UP", gu_name,
+                              RadioSettingValueList(KEYS.values(),
+                              KEYS.values()[KEYS.keys().index(
+                                  int(keys.kGROUP_UP))]))
+            fkeys.append(gu)
+
+        # Side keys on portables
+        gd_name = "Triangle Down"
+        if self.TYPE[0] == "P":
+            gd_name = "> key"
+
+        gd = RadioSetting("keys.kGROUP_DOWN", gd_name,
+                          RadioSettingValueList(KEYS.values(),
+                          KEYS.values()[KEYS.keys().index(
+                              int(keys.kGROUP_DOWN))]))
+        fkeys.append(gd)
+
+        mon_name = "MON"
+        if self.TYPE[0] == "P":
+            mon_name = "Side 2"
+
+        mon = RadioSetting("keys.kMON", mon_name,
+                           RadioSettingValueList(KEYS.values(),
+                           KEYS.values()[KEYS.keys().index(
+                               int(keys.kMON))]))
+        fkeys.append(mon)
+
+        return top
+
+    def set_settings(self, settings):
+        """Translate the settings in the UI into bit in the mem_struct
+        I don't understand well the method used in many drivers
+        so, I used mine, ugly but works ok"""
+
+        mobj = self._memobj
+
+        for element in settings:
+            if not isinstance(element, RadioSetting):
+                self.set_settings(element)
+                continue
+
+            # Let's roll the ball
+            if "." in element.get_name():
+                inter, setting = element.get_name().split(".")
+                # you must ignore the settings with "not"
+                # this are READ ONLY attributes
+                if inter == "not":
+                    continue
+
+                obj = getattr(mobj, inter)
+                value = element.value
+
+                # integers case + special case
+                if setting in ["tot", "tot_alert", "min_vol", "tone_vol",
+                               "sql_level", "tot_rekey", "tot_reset"]:
+                    # catching the "off" values as zero
+                    try:
+                        value = int(value)
+                    except:
+                        value = 0
+
+                    # tot case step 15
+                    if setting == "tot":
+                        value = value * 15
+                        # off is special
+                        if value == 0:
+                            value = 0x4b0
+
+                    # Caso tone_vol
+                    if setting == "tone_vol":
+                        # off is special
+                        if value == 32:
+                            value = 0xff
+
+                # Bool types + inverted
+                if setting in ["c2t", "poweron_tone", "control_tone",
+                               "warn_tone", "battery_save", "self_prog",
+                               "clone", "panel_test"]:
+                    value = bool(value)
+
+                    # this cases are inverted
+                    if setting == "c2t":
+                        value = not value
+
+                    # case battery save is special
+                    if setting == "battery_save":
+                        if bool(value) is True:
+                            value = 0x32
+                        else:
+                            value = 0xff
+
+                # String cases
+                if setting in ["poweronmesg", "line1", "line2"]:
+                    # some vars
+                    value = str(value)
+                    just = 8
+                    # lines with 32
+                    if "line" in setting:
+                        just = 32
+
+                    # empty case
+                    if len(value) == 0:
+                        value = "\xff" * just
+                    else:
+                        value = value.ljust(just)
+
+                ## password with special case
+                #if setting == "radio" or setting == "data":
+                    #pass
+
+                # case keys, with special config
+                if inter == "keys":
+                    value = KEYS.keys()[KEYS.values().index(str(value))]
+
+            # Apply al configs done
+            setattr(obj, setting, value)
+
+    def get_bank_model(self):
+        """Pass the bank model to the UI part"""
+        rf = self.get_features()
+        if rf.has_bank is True:
+            return Kenwood60GBankModel(self)
+        else:
+            return None
+
+    def _get_bank(self, loc):
+        """Get the bank data for a specific channel"""
+        mem = self._memobj.memory[loc - 1]
+        bank = int(mem.bank) - 1
+
+        if bank > self._num_banks or bank < 1:
+            # all channels must belong to a bank, even with just 1 bank
+            return 0
+        else:
+            return bank
+
+    def _set_bank(self, loc, bank):
+        """Set the bank data for a specific channel"""
+        try:
+            b = int(bank)
+            if b > 127:
+                b = 0
+            mem = self._memobj.memory[loc - 1]
+            mem.bank = b + 1
+        except:
+            msg = "You can't have a channel without a bank, click another bank"
+            raise errors.InvalidDataError(msg)
+
+
+# This kenwwood family is known as "60-G Serie"
+# all this radios ending in G are compatible:
+#
+# Portables VHF TK-260/270/272/278
+# Portables UHF TK-360/370/372/378/388
+#
+# Mobiles VHF TK-760/762/768
+# Mobiles VHF TK-860/862/868
+#
+# Just dealing with VHF models at moment,
+# this are the radios I can get in hand
+
+# WARNING !!!! Radios With Password in the data section <=###############
+#
+# when a radio has a data password (aka to program it) the last byte (#8)
+# in the id code change from \xf1 to \xb1; so we remove this last byte
+# from the identification procedures and variants.
+#
+# this effectively render the data password USELESS even if set.
+# this can change if user request it with high priority
+
+ at directory.register
+class TK768G_Radios(Kenwood_Serie_60G):
+    """Kenwood TK-768G Radios [M/C]"""
+    MODEL = "TK-768G"
+    TYPE = "M7680"
+    # Note that 8 CH don't have banks
+    VARIANTS = {
+        "M7680\x15\xff": (8, 136, 162, "M2"),
+        "M7680\x14\xff": (8, 148, 174, "M"),
+        "M76805\xff":    (128, 136, 162, "C2"),
+        "M76804\xff":    (128, 148, 174, "C"),
+        }
+
+
+ at directory.register
+class TK762G_Radios(Kenwood_Serie_60G):
+    """Kenwood TK-762G Radios [K/E/NE]"""
+    MODEL = "TK-762G"
+    TYPE = "M7620"
+    # Note that 8 CH don't have banks
+    VARIANTS = {
+        "M7620\x05\xff": (8, 136, 162, "K2"),
+        "M7620\x04\xff": (8, 148, 172, "K"),
+        "M7620$\xff":    (8, 148, 172, "E"),
+        "M7620T\xff":    (8, 148, 172, "NE"),
+        }
+
+
+ at directory.register
+class TK760G_Radios(Kenwood_Serie_60G):
+    """Kenwood TK-760G Radios [K/M/(N)E]"""
+    MODEL = "TK-760G"
+    TYPE = "M7600"
+    VARIANTS = {
+        "M7600\x05\xff": (128, 136, 162, "K2"),
+        "M7600\x04\xff": (128, 148, 174, "K"),
+        "M7600\x14\xff": (128, 146, 174, "M"),
+        "M7600T\xff":    (128, 146, 174, "NE")
+        }
+
+
+ at directory.register
+class TK278G_Radios(Kenwood_Serie_60G):
+    """Kenwood TK-278G Radio C/C1/M/M1"""
+    MODEL = "TK-278G"
+    TYPE = "P2780"
+    # Note that 16 CH don't have banks
+    VARIANTS = {
+        "P27805\xff":    (128, 136, 150, "C1"),
+        "P27804\xff":    (128, 150, 174, "C"),
+        "P2780\x15\xff": (16,  136, 150, "M1"),
+        "P2780\x14\xff": (16,  150, 174, "M")
+        }
+
+
+ at directory.register
+class TK272G_Radios(Kenwood_Serie_60G):
+    """Kenwood TK-272G Radio K/K1"""
+    MODEL = "TK-272G"
+    TYPE = "P2720"
+    VARIANTS = {
+        "P2720\x05\xfb": (32, 136, 150, "K1"),
+        "P2720\x04\xfb": (32, 150, 174, "K")
+        }
+
+
+ at directory.register
+class TK270G_Radios(Kenwood_Serie_60G):
+    """Kenwood TK-270G Radio K/K1/M/E/NE/NT"""
+    MODEL = "TK-270G"
+    TYPE = "P2700"
+    VARIANTS = {
+        "P2700T\xff":    (128, 146, 174, "NE/NT"),
+        "P2700$\xff":    (128, 146, 174, "E"),
+        "P2700\x14\xff": (128, 150, 174, "M"),
+        "P2700\x05\xff": (128, 136, 150, "K1"),
+        "P2700\x04\xff": (128, 150, 174, "K"),
+        }
+
+
+ at directory.register
+class TK260G_Radios(Kenwood_Serie_60G):
+    """Kenwood TK-260G Radio K/K1/M/E/NE/NT"""
+    MODEL = "TK-260G"
+    _hasbanks = False
+    TYPE = "P2600"
+    VARIANTS = {
+        "P2600U\xff":    (8, 136, 150, "N1"),
+        "P2600T\xff":    (8, 146, 174, "N"),
+        "P2600$\xff":    (8, 146, 174, "E"),
+        "P2600\x14\xff": (8, 150, 174, "M"),
+        "P2600\x05\xff": (8, 136, 150, "K1"),
+        "P2600\x04\xff": (8, 150, 174, "K")
+        }
diff --git a/chirp/drivers/ts2000.py b/chirp/drivers/ts2000.py
index a47ef88..970c021 100644
--- a/chirp/drivers/ts2000.py
+++ b/chirp/drivers/ts2000.py
@@ -25,7 +25,7 @@ TS2000_DUPLEX = dict(kenwood_live.DUPLEX)
 TS2000_DUPLEX[3] = "="
 TS2000_DUPLEX[4] = "split"
 TS2000_MODES = ["?", "LSB", "USB", "CW", "FM", "AM",
-                "FSK", "CR-R", "?", "FSK-R"]
+                "FSK", "CW-R", "?", "FSK-R"]
 TS2000_TMODES = ["", "Tone", "TSQL", "DTCS"]
 TS2000_TONES = list(chirp_common.OLD_TONES)
 TS2000_TONES.remove(69.3)
@@ -125,7 +125,7 @@ class TS2000Radio(KenwoodLiveRadio):
         spec = " " + spec
 
         # use the same variable names as the Kenwood docs
-        #_p1 = spec[3]
+        # _p1 = spec[3]
         _p2 = spec[4]
         _p3 = spec[5:7]
         _p4 = spec[7:18]
@@ -135,11 +135,11 @@ class TS2000Radio(KenwoodLiveRadio):
         _p8 = spec[21:23]
         _p9 = spec[23:25]
         _p10 = spec[25:28]
-        #_p11 = spec[28]
+        # _p11 = spec[28]
         _p12 = spec[29]
         _p13 = spec[30:39]
         _p14 = spec[39:41]
-        #_p15 = spec[41]
+        # _p15 = spec[41]
         _p16 = spec[42:49]
 
         mem.number = int(_p2 + _p3)     # concat bank num and chan num
diff --git a/stock_configs/DE Freenet Frequencies.csv b/stock_configs/DE Freenet Frequencies.csv
new file mode 100644
index 0000000..e9ec9bc
--- /dev/null
+++ b/stock_configs/DE Freenet Frequencies.csv	
@@ -0,0 +1,7 @@
+Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,Comment,URCALL,RPT1CALL,RPT2CALL
+1,FRNET1,149.025000,,0.000000,,88.5,88.5,023,NN,NFM,5.00,,,,,
+2,FRNET2,149.037500,,0.000000,,88.5,88.5,023,NN,NFM,5.00,,,,,
+3,FRNET3,149.050000,,0.000000,,88.5,88.5,023,NN,NFM,5.00,,,,,
+4,FRNET4,149.087500,,0.000000,,88.5,88.5,023,NN,NFM,5.00,,,,,
+5,FRNET5,149.100000,,0.000000,,88.5,88.5,023,NN,NFM,5.00,,,,,
+6,FRNET6,149.112500,,0.000000,,88.5,88.5,023,NN,NFM,5.00,,,,,
diff --git a/stock_configs/EU LPD and PMR Channels.csv b/stock_configs/EU LPD and PMR Channels.csv
index 0595902..57eab2e 100644
--- a/stock_configs/EU LPD and PMR Channels.csv	
+++ b/stock_configs/EU LPD and PMR Channels.csv	
@@ -1,78 +1,78 @@
-Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,Comment,URCALL,RPT1CALL,RPT2CALL
-1,LPD 01,433.075000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-2,LPD 02,433.100000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-3,LPD 03,433.125000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-4,LPD 04,433.150000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-5,LPD 05,433.175000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-6,LPD 06,433.200000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-7,LPD 07,433.225000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-8,LPD 08,433.250000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-9,LPD 09,433.275000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-10,LPD 10,433.300000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-11,LPD 11,433.325000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-12,LPD 12,433.350000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-13,LPD 13,433.375000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-14,LPD 14,433.400000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-15,LPD 15,433.425000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-16,LPD 16,433.450000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-17,LPD 17,433.475000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-18,LPD 18,433.500000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-19,LPD 19,433.525000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-20,LPD 20,433.550000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-21,LPD 21,433.575000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-22,LPD 22,433.600000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-23,LPD 23,433.625000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-24,LPD 24,433.650000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-25,LPD 25,433.675000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-26,LPD 26,433.700000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-27,LPD 27,433.725000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-28,LPD 28,433.750000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-29,LPD 29,433.775000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-30,LPD 30,433.800000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-31,LPD 31,433.825000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-32,LPD 32,433.850000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-33,LPD 33,433.875000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-34,LPD 34,433.900000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-35,LPD 35,433.925000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-36,LPD 36,433.950000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-37,LPD 37,433.975000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-38,LPD 38,434.000000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-39,LPD 39,434.025000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-40,LPD 40,434.050000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-41,LPD 41,434.075000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-42,LPD 42,434.100000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-43,LPD 43,434.125000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-44,LPD 44,434.150000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-45,LPD 45,434.175000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-46,LPD 46,434.200000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-47,LPD 47,434.225000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-48,LPD 48,434.250000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-49,LPD 49,434.275000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-50,LPD 50,434.300000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-51,LPD 51,434.325000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-52,LPD 52,434.350000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-53,LPD 53,434.375000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-54,LPD 54,434.400000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-55,LPD 55,434.425000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-56,LPD 56,434.450000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-57,LPD 57,434.475000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-58,LPD 58,434.500000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-59,LPD 59,434.525000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-60,LPD 60,434.550000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-61,LPD 61,434.575000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-62,LPD 62,434.600000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-63,LPD 63,434.625000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-64,LPD 64,434.650000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-65,LPD 65,434.675000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-66,LPD 66,434.700000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-67,LPD 67,434.725000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-68,LPD 68,434.750000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-69,LPD 69,434.775000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-71,PMR 1,446.006250,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,,
-72,PMR 2,446.018750,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,,
-73,PMR 3,446.031250,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,,
-74,PMR 4,446.043750,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,,
-75,PMR 5,446.056250,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,,
-76,PMR 6,446.068750,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,,
-77,PMR 7,446.081250,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,,
-78,PMR 8,446.093750,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,,
+Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,Comment,URCALL,RPT1CALL,RPT2CALL
+1,LPD 01,433.075000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+2,LPD 02,433.100000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+3,LPD 03,433.125000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+4,LPD 04,433.150000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+5,LPD 05,433.175000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+6,LPD 06,433.200000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+7,LPD 07,433.225000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+8,LPD 08,433.250000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+9,LPD 09,433.275000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+10,LPD 10,433.300000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+11,LPD 11,433.325000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+12,LPD 12,433.350000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+13,LPD 13,433.375000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+14,LPD 14,433.400000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+15,LPD 15,433.425000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+16,LPD 16,433.450000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+17,LPD 17,433.475000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+18,LPD 18,433.500000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+19,LPD 19,433.525000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+20,LPD 20,433.550000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+21,LPD 21,433.575000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+22,LPD 22,433.600000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+23,LPD 23,433.625000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+24,LPD 24,433.650000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+25,LPD 25,433.675000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+26,LPD 26,433.700000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+27,LPD 27,433.725000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+28,LPD 28,433.750000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+29,LPD 29,433.775000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+30,LPD 30,433.800000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+31,LPD 31,433.825000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+32,LPD 32,433.850000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+33,LPD 33,433.875000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+34,LPD 34,433.900000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+35,LPD 35,433.925000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+36,LPD 36,433.950000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+37,LPD 37,433.975000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+38,LPD 38,434.000000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+39,LPD 39,434.025000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+40,LPD 40,434.050000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+41,LPD 41,434.075000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+42,LPD 42,434.100000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+43,LPD 43,434.125000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+44,LPD 44,434.150000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+45,LPD 45,434.175000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+46,LPD 46,434.200000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+47,LPD 47,434.225000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+48,LPD 48,434.250000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+49,LPD 49,434.275000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+50,LPD 50,434.300000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+51,LPD 51,434.325000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+52,LPD 52,434.350000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+53,LPD 53,434.375000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+54,LPD 54,434.400000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+55,LPD 55,434.425000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+56,LPD 56,434.450000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+57,LPD 57,434.475000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+58,LPD 58,434.500000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+59,LPD 59,434.525000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+60,LPD 60,434.550000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+61,LPD 61,434.575000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+62,LPD 62,434.600000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+63,LPD 63,434.625000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+64,LPD 64,434.650000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+65,LPD 65,434.675000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+66,LPD 66,434.700000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+67,LPD 67,434.725000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+68,LPD 68,434.750000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+69,LPD 69,434.775000,,0.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+71,PMR 1,446.006250,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,
+72,PMR 2,446.018750,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,
+73,PMR 3,446.031250,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,
+74,PMR 4,446.043750,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,
+75,PMR 5,446.056250,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,
+76,PMR 6,446.068750,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,
+77,PMR 7,446.081250,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,
+78,PMR 8,446.093750,,0.600000,,88.5,88.5,023,NN,NFM,6.25,,,,,
diff --git a/stock_configs/FR Marine VHF Channels.csv b/stock_configs/FR Marine VHF Channels.csv
index 02bc3ee..da8bac7 100644
--- a/stock_configs/FR Marine VHF Channels.csv	
+++ b/stock_configs/FR Marine VHF Channels.csv	
@@ -1,58 +1,58 @@
 Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,Comment,URCALL,RPT1CALL,RPT2CALL
-1,SEA 01,160.650000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-2,SEA 02,160.700000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-3,SEA 03,160.750000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-4,SEA 04,160.800000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-5,SEA 05,160.850000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-6,SEA 06,156.300000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-7,SEA 07,160.950000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-8,SEA 08,156.400000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-9,SEA 09,156.450000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-10,SEA 10,156.500000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-11,SEA 11,156.550000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-12,SEA 12,156.600000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-13,SEA 13,156.650000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-14,SEA 14,156.700000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-15,SEA 15,156.750000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-16,SEA 16,156.800000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-17,SEA 17,156.850000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-18,SEA 18,161.500000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-19,SEA 19,161.550000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-20,SEA 20,161.600000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-21,SEA 21,161.650000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-22,SEA 22,161.700000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-23,SEA 23,161.750000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-24,SEA 24,161.800000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-25,SEA 25,161.850000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-26,SEA 26,161.900000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-27,SEA 27,161.950000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-28,SEA 28,162.000000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-29,SEA 60,160.625000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-30,SEA 61,160.675000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-31,SEA 62,160.725000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-32,SEA 63,160.775000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-33,SEA 64,160.825000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-34,SEA 65,160.875000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-35,SEA 66,160.925000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-36,SEA 67,156.375000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-37,SEA 68,156.425000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-38,SEA 69,156.475000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-39,SEA 70,156.525000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-40,SEA 71,156.575000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-41,SEA 72,156.625000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-42,SEA 73,156.675000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-43,SEA 74,156.725000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-44,SEA 75,156.775000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-45,SEA 76,156.825000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-46,SEA 77,156.875000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-47,SEA 78,161.525000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-48,SEA 79,161.575000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-49,SEA 80,161.625000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-50,SEA 81,161.675000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-51,SEA 82,161.725000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-52,SEA 83,161.775000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-53,SEA 84,161.825000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-54,SEA 85,161.875000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-55,SEA 86,161.925000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-56,SEA 87,157.375000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-57,SEA 88,157.425000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
+1,SEA 01,160.650000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+2,SEA 02,160.700000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+3,SEA 03,160.750000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+4,SEA 04,160.800000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+5,SEA 05,160.850000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+6,SEA 06,156.300000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+7,SEA 07,160.950000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+8,SEA 08,156.400000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+9,SEA 09,156.450000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+10,SEA 10,156.500000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+11,SEA 11,156.550000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+12,SEA 12,156.600000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+13,SEA 13,156.650000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+14,SEA 14,156.700000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+15,SEA 15,156.750000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+16,SEA 16,156.800000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+17,SEA 17,156.850000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+18,SEA 18,161.500000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+19,SEA 19,161.550000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+20,SEA 20,161.600000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+21,SEA 21,161.650000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+22,SEA 22,161.700000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+23,SEA 23,161.750000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+24,SEA 24,161.800000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+25,SEA 25,161.850000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+26,SEA 26,161.900000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+27,SEA 27,161.950000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+28,SEA 28,162.000000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+29,SEA 60,160.625000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+30,SEA 61,160.675000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+31,SEA 62,160.725000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+32,SEA 63,160.775000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+33,SEA 64,160.825000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+34,SEA 65,160.875000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+35,SEA 66,160.925000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+36,SEA 67,156.375000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+37,SEA 68,156.425000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+38,SEA 69,156.475000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+39,SEA 70,156.525000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+40,SEA 71,156.575000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+41,SEA 72,156.625000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+42,SEA 73,156.675000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+43,SEA 74,156.725000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+44,SEA 75,156.775000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+45,SEA 76,156.825000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+46,SEA 77,156.875000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+47,SEA 78,161.525000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+48,SEA 79,161.575000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+49,SEA 80,161.625000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+50,SEA 81,161.675000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+51,SEA 82,161.725000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+52,SEA 83,161.775000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+53,SEA 84,161.825000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+54,SEA 85,161.875000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+55,SEA 86,161.925000,-,4.600000,,88.5,88.5,023,NN,FM,5.00,,,,,
+56,SEA 87,157.375000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+57,SEA 88,157.425000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
diff --git a/stock_configs/UK Business Radio Simple Light Frequencies.csv b/stock_configs/UK Business Radio Simple Light Frequencies.csv
new file mode 100644
index 0000000..803995b
--- /dev/null
+++ b/stock_configs/UK Business Radio Simple Light Frequencies.csv	
@@ -0,0 +1,16 @@
+Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,Comment,URCALL,RPT1CALL,RPT2CALL
+1,BRSL1,77.687500,,0.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+2,BRSL2,86.337500,,0.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+3,BRSL3,86.350000,,0.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+4,BRSL4,86.362500,,0.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+5,BRSL5,86.375000,,0.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+6,BRSL6,164.050000,,0.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+7,BRSL7,164.062500,,0.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+8,BRSL8,169.087500,,0.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+9,BRSL9,169.312500,,0.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+10,BRSL10,173.050000,,0.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+11,BRSL11,173.062500,,0.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+12,BRSL12,173.087500,,0.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+13,BRSL13,449.312500,,0.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+14,BRSL14,449.400000,,0.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+15,BRSL15,449.475000,,0.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
diff --git a/stock_configs/US 60 meter channels (Center).csv b/stock_configs/US 60 meter channels (Center).csv
index c650a3b..df22f65 100644
--- a/stock_configs/US 60 meter channels (Center).csv	
+++ b/stock_configs/US 60 meter channels (Center).csv	
@@ -1,4 +1,4 @@
-Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,URCALL,RPT1CALL,RPT2CALL
+Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,Comment,URCALL,RPT1CALL,RPT2CALL
 1,60m CH1,5.332000,,0.600000,,88.5,88.5,023,NN,USB,5.00,,,,,
 2,60m CH2,5.348000,,0.600000,,88.5,88.5,023,NN,USB,5.00,,,,,
 3,60m CH3,5.358500,,0.600000,,88.5,88.5,023,NN,USB,5.00,,,,,
diff --git a/stock_configs/US 60 meter channels (Dial).csv b/stock_configs/US 60 meter channels (Dial).csv
index db3c13a..ed016f3 100644
--- a/stock_configs/US 60 meter channels (Dial).csv	
+++ b/stock_configs/US 60 meter channels (Dial).csv	
@@ -1,4 +1,4 @@
-Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,URCALL,RPT1CALL,RPT2CALL
+Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,Comment,URCALL,RPT1CALL,RPT2CALL
 1,60m CH1,5.330500,,0.600000,,88.5,88.5,023,NN,USB,5.00,,,,,
 2,60m CH2,5.346500,,0.600000,,88.5,88.5,023,NN,USB,5.00,,,,,
 3,60m CH3,5.357000,,0.600000,,88.5,88.5,023,NN,USB,5.00,,,,,
diff --git a/stock_configs/US Calling Frequencies.csv b/stock_configs/US Calling Frequencies.csv
index 4b8b804..d597d86 100644
--- a/stock_configs/US Calling Frequencies.csv	
+++ b/stock_configs/US Calling Frequencies.csv	
@@ -1,4 +1,4 @@
-Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,URCALL,RPT1CALL,RPT2CALL
+Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,Comment,URCALL,RPT1CALL,RPT2CALL
 1,6m Call,52.525000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
 2,2m Call,146.520000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
 3,220 Call,223.500000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
diff --git a/stock_configs/US FRS and GMRS Channels.csv b/stock_configs/US FRS and GMRS Channels.csv
index bfa250a..f32fbc7 100644
--- a/stock_configs/US FRS and GMRS Channels.csv	
+++ b/stock_configs/US FRS and GMRS Channels.csv	
@@ -1,23 +1,23 @@
-Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,Comment,URCALL,RPT1CALL,RPT2CALL
-1,FRS1,462.562500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
-2,FRS2,462.587500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
-3,FRS3,462.612500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
-4,FRS4,462.637500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
-5,FRS5,462.662500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
-6,FRS6,462.687500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
-7,FRS7,462.712500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
-8,FRS8,467.562500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
-9,FRS9,467.587500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
-10,FRS10,467.612500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
-11,FRS11,467.637500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
-12,FRS12,467.662500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
-13,FRS13,467.687500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
-14,FRS14,467.712500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,,
-15,GMRS1,462.550000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-16,GMRS2,462.575000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-17,GMRS3,462.600000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-18,GMRS4,462.625000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-19,GMRS5,462.650000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-20,GMRS6,462.675000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-21,GMRS7,462.700000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-22,GMRS8,462.725000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
+Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,Comment,URCALL,RPT1CALL,RPT2CALL
+1,FRS1,462.562500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+2,FRS2,462.587500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+3,FRS3,462.612500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+4,FRS4,462.637500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+5,FRS5,462.662500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+6,FRS6,462.687500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+7,FRS7,462.712500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+8,FRS8,467.562500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+9,FRS9,467.587500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+10,FRS10,467.612500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+11,FRS11,467.637500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+12,FRS12,467.662500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+13,FRS13,467.687500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+14,FRS14,467.712500,,5.000000,,88.5,88.5,023,NN,NFM,12.50,,,,,
+15,GMRS1,462.550000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+16,GMRS2,462.575000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+17,GMRS3,462.600000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+18,GMRS4,462.625000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+19,GMRS5,462.650000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+20,GMRS6,462.675000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+21,GMRS7,462.700000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+22,GMRS8,462.725000,,5.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
diff --git a/stock_configs/US MURS Channels.csv b/stock_configs/US MURS Channels.csv
index 4e5384c..e6fed17 100644
--- a/stock_configs/US MURS Channels.csv	
+++ b/stock_configs/US MURS Channels.csv	
@@ -1,6 +1,6 @@
 Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,Comment,URCALL,RPT1CALL,RPT2CALL
-1,MURS 1,151.820000,,0.000000,,88.5,88.5,023,NN,NFM,5.00,,,,,,
-2,MURS 2,151.880000,,0.000000,,88.5,88.5,023,NN,NFM,5.00,,,,,,
-3,MURS 3,151.940000,,0.000000,,88.5,88.5,023,NN,NFM,5.00,,,,,,
-4,Blue Dot,154.570000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
-5,Green Dot,154.600000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,,
+1,MURS 1,151.820000,,0.000000,,88.5,88.5,023,NN,NFM,5.00,,,,,
+2,MURS 2,151.880000,,0.000000,,88.5,88.5,023,NN,NFM,5.00,,,,,
+3,MURS 3,151.940000,,0.000000,,88.5,88.5,023,NN,NFM,5.00,,,,,
+4,Blue Dot,154.570000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
+5,Green Dot,154.600000,,0.000000,,88.5,88.5,023,NN,FM,5.00,,,,,
diff --git a/stock_configs/US Marine VHF Channels.csv b/stock_configs/US Marine VHF Channels.csv
index 5dc7369..21a6f79 100644
--- a/stock_configs/US Marine VHF Channels.csv	
+++ b/stock_configs/US Marine VHF Channels.csv	
@@ -1,61 +1,61 @@
 Location,Name,Frequency,Duplex,Offset,Tone,rToneFreq,cToneFreq,DtcsCode,DtcsPolarity,Mode,TStep,Skip,Comment,URCALL,RPT1CALL,RPT2CALL
-1,SEA 01,160.650000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-2,SEA 02,160.700000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-3,SEA 03,160.750000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-4,SEA 04,160.800000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-5,SEA 05,160.850000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-6,SEA 06,156.300000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-7,SEA 07,160.950000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-8,SEA 08,156.400000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-9,SEA 09,156.450000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-10,SEA 10,156.500000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-11,SEA 11,156.550000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-12,SEA 12,156.600000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-13,SEA 13,156.650000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-14,SEA 14,156.700000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-15,SEA 15,156.750000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-16,SEA 16,156.800000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-17,SEA 17,156.850000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-18,SEA 18,161.500000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-19,SEA 19,161.550000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-20,SEA 20,161.600000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-21,SEA 21,161.650000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-22,SEA 22,161.700000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-23,SEA 23,161.750000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-24,SEA 24,161.800000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-25,SEA 25,161.850000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-26,SEA 26,161.900000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-27,SEA 27,161.950000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-28,SEA 28,162.000000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-29,SEA 60,160.625000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-30,SEA 61,160.675000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-31,SEA 62,160.725000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-32,SEA 63,160.775000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-33,SEA 64,160.825000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-34,SEA 65,160.875000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-35,SEA 66,160.925000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-36,SEA 67,156.375000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-37,SEA 68,156.425000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-38,SEA 69,156.475000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-39,DSC 70,156.525000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-40,SEA 71,156.575000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-41,SEA 72,156.625000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-42,SEA 73,156.675000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-43,SEA 74,156.725000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-44,SEA 77,156.875000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-45,SEA 78,161.525000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-46,SEA 79,161.575000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-47,SEA 80,161.625000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-48,SEA 81,161.675000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-49,SEA 82,161.725000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-50,SEA 83,161.775000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-51,SEA 84,161.825000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-52,SEA 85,161.875000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-53,SEA 86,161.925000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-54,AIS 87,161.975000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-55,AIS 88,162.025000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,S,,,,,
-56,SEA F1,155.625000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-57,SEA F2,155.775000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-58,SEA F3,155.825000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-59,SEA L1,155.500000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
-60,SEA L2,155.525000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,,
+1,SEA 01,160.650000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+2,SEA 02,160.700000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+3,SEA 03,160.750000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+4,SEA 04,160.800000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+5,SEA 05,160.850000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+6,SEA 06,156.300000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+7,SEA 07,160.950000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+8,SEA 08,156.400000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+9,SEA 09,156.450000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+10,SEA 10,156.500000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+11,SEA 11,156.550000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+12,SEA 12,156.600000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+13,SEA 13,156.650000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+14,SEA 14,156.700000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+15,SEA 15,156.750000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+16,SEA 16,156.800000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+17,SEA 17,156.850000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+18,SEA 18,161.500000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+19,SEA 19,161.550000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+20,SEA 20,161.600000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+21,SEA 21,161.650000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+22,SEA 22,161.700000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+23,SEA 23,161.750000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+24,SEA 24,161.800000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+25,SEA 25,161.850000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+26,SEA 26,161.900000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+27,SEA 27,161.950000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+28,SEA 28,162.000000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+29,SEA 60,160.625000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+30,SEA 61,160.675000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+31,SEA 62,160.725000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+32,SEA 63,160.775000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+33,SEA 64,160.825000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+34,SEA 65,160.875000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+35,SEA 66,160.925000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+36,SEA 67,156.375000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+37,SEA 68,156.425000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+38,SEA 69,156.475000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+39,DSC 70,156.525000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+40,SEA 71,156.575000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+41,SEA 72,156.625000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+42,SEA 73,156.675000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+43,SEA 74,156.725000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+44,SEA 77,156.875000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+45,SEA 78,161.525000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+46,SEA 79,161.575000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+47,SEA 80,161.625000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+48,SEA 81,161.675000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+49,SEA 82,161.725000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+50,SEA 83,161.775000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+51,SEA 84,161.825000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+52,SEA 85,161.875000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+53,SEA 86,161.925000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+54,AIS 87,161.975000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+55,AIS 88,162.025000,-,4.600000,,88.5,88.5,023,NN,FM,25.00,,,,,
+56,SEA F1,155.625000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+57,SEA F2,155.775000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+58,SEA F3,155.825000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+59,SEA L1,155.500000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,
+60,SEA L2,155.525000,,0.000000,,88.5,88.5,023,NN,FM,25.00,,,,,

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-hamradio/chirp.git



More information about the pkg-hamradio-commits mailing list