[hamradio-commits] [chirp] 01/04: Imported Upstream version 1:20151212
Iain R. Learmonth
irl at moszumanska.debian.org
Sun Dec 13 13:10:08 UTC 2015
This is an automated email from the git hooks/post-receive script.
irl pushed a commit to branch master
in repository chirp.
commit b576aa4a85890b6900af8c1997a66161409ec758
Author: Iain R. Learmonth <irl at debian.org>
Date: Sun Dec 13 13:03:48 2015 +0000
Imported Upstream version 1:20151212
---
PKG-INFO | 2 +-
chirp/__init__.py | 2 +-
chirp/drivers/fd268.py | 923 ++++++++++++++++++++++++++++++++++++++
chirp/drivers/ft857.py | 42 +-
chirp/drivers/icomciv.py | 36 +-
chirp/drivers/th9800.py | 8 +-
chirp/util.py | 13 +
locale/uk_UA/LC_MESSAGES/CHIRP.mo | Bin 0 -> 17917 bytes
8 files changed, 998 insertions(+), 28 deletions(-)
diff --git a/PKG-INFO b/PKG-INFO
index c294215..e706b18 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.0
Name: chirp
-Version: daily-20151023
+Version: daily-20151212
Summary: UNKNOWN
Home-page: UNKNOWN
Author: UNKNOWN
diff --git a/chirp/__init__.py b/chirp/__init__.py
index 8763f2a..2ac332f 100644
--- a/chirp/__init__.py
+++ b/chirp/__init__.py
@@ -17,7 +17,7 @@ import os
import sys
from glob import glob
-CHIRP_VERSION="daily-20151023"
+CHIRP_VERSION="daily-20151212"
module_dir = os.path.dirname(sys.modules["chirp"].__file__)
__all__ = []
diff --git a/chirp/drivers/fd268.py b/chirp/drivers/fd268.py
new file mode 100644
index 0000000..2575fd9
--- /dev/null
+++ b/chirp/drivers/fd268.py
@@ -0,0 +1,923 @@
+# 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, CO7WT, co7wt at frcuba.co.cu
+
+import struct
+import os
+import logging
+
+from chirp import chirp_common, directory, memmap, errors, util
+from chirp import bitwise
+from textwrap import dedent
+from chirp.settings import RadioSettingGroup, RadioSetting, \
+ RadioSettingValueBoolean, RadioSettingValueList, \
+ RadioSettingValueString, RadioSettings
+
+LOG = logging.getLogger(__name__)
+
+MEM_FORMAT = """
+#seekto 0x0010;
+struct {
+ lbcd rx_freq[4];
+ lbcd tx_freq[4];
+ lbcd rx_tone[2];
+ lbcd tx_tone[2];
+ u8 unknown:4,
+ scrambler:1,
+ unknown1:1,
+ unknown2:1,
+ busy_lock:1;
+ u8 unknown3[3];
+} memory[99];
+
+#seekto 0x0640;
+struct {
+ lbcd vrx_freq[4];
+ lbcd vtx_freq[4];
+ lbcd vrx_tone[2];
+ lbcd vtx_tone[2];
+ u8 shift_plus:1,
+ shift_minus:1,
+ unknown11:2,
+ scramble:1,
+ unknown12:1,
+ unknown13:1,
+ busy_lock:1;
+ u8 unknown14[3];
+} vfo;
+
+#seekto 0x07B0;
+struct {
+ u8 ani_mode; // fd-288's family store the any settings here
+ char ani[3]; // str of the any code (200-999) inclusive
+ u8 unknown21[12]; // fill to match the fd-268's start
+ u8 unknown22:5, // x07c0, fd-268's start (LCD icons)
+ bw1:1, // twin setting of bw (LCD "romb")
+ bs1:1, // twin setting of bs (LCD "S")
+ warning1:1; // twin setting of warning (LCD "Tune")
+ u8 sql[1];
+ u8 monitorval;
+ u8 tot[1];
+ u8 powerrank;
+ u8 unknown23[3];
+ u8 unknown24[8];
+ char model[8];
+ u8 unknown26[8];
+ u8 step;
+ u8 unknown27:2,
+ power:1,
+ lamp:1,
+ lamp_auto:1,
+ key:1,
+ monitor:1,
+ bw:1;
+ u8 unknown28:3,
+ warning:1,
+ bs:1,
+ unknown29:1,
+ wmem:1,
+ wvfo:1;
+ u8 active_ch;
+ u8 unknown30[4];
+ u8 unknown31[4];
+ bbcd vfo_shift[4];
+} settings;
+"""
+
+MEM_SIZE=0x0800
+CMD_ACK = "\x06"
+BLOCK_SIZE = 0x08
+POWER_LEVELS = ["Low", "High"]
+LIST_SQL = ["Off"] + ["%s" % x for x in range(1, 10)]
+LIST_TOT = ["Off"] + ["%s" % x for x in range(10, 100, 10)]
+ONOFF = ["Off", "On"]
+STEPF = ["5", "10", "6.25", "12.5", "25"]
+ACTIVE_CH = ["%s" % x for x in range(1, 100)]
+KEY_LOCK =["Automatic", "Manual"]
+BW = ["Narrow", "Wide"]
+W_MODE = ["VFO", "Memory"]
+VSHIFT = ["None", "-", "+"]
+POWER_RANK = ["%s" % x for x in range(0, 28)]
+ANI = ["Off", "BOT", "EOT", "Both"]
+
+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:
+ data = radio.pipe.write(data)
+ except:
+ raise errors.RadioError("Error sending data to radio")
+
+def make_frame(cmd, addr, length = BLOCK_SIZE):
+ """Pack the info in the format it likes"""
+ return struct.pack(">BHB", ord(cmd), addr, length)
+
+def check_ack(r, text):
+ """Check for a correct ACK from radio, rising error 'Text'
+ if something was wrong """
+ ack = raw_recv(r, 1)
+ if ack != CMD_ACK:
+ raise errors.RadioError(text)
+ else:
+ return True
+
+def send(radio, frame, data = ""):
+ """Generic send data to the radio"""
+ raw_send(radio, frame)
+ if data != "":
+ raw_send(radio, data)
+ check_ack(radio, "Radio didn't ack the last block of data")
+
+def recv(radio):
+ """Generic receive data from the radio, return just data"""
+ # you must get it all 12 at once (4 header + 8 data)
+ rxdata = raw_recv(radio, 12)
+ if (len(rxdata) != 12):
+ raise errors.RadioError(
+ "Radio sent %i bytes, we expected 12" % (len(rxdata)))
+ else:
+ data = rxdata[4:]
+ send(radio, CMD_ACK)
+ check_ack(radio, "Radio didn't ack the sended data")
+ return data
+
+def do_program(radio):
+ """Feidaxin program mode and identification dance"""
+ def do_magic():
+ """Try to get the radio in program mode, the factory software
+ (FDX-288) tries up to ~16 times to get the correct response,
+ we will do the same, but with a lower count."""
+ tries = 8
+ # UI information
+ status = chirp_common.Status()
+ status.cur = 0
+ status.max = tries
+ status.msg = "Linking to radio, please wait."
+ radio.status_fn(status)
+
+ # every byte of this magic chain must be send separatedly
+ magic = "\x02PROGRA"
+
+ # start the fun, finger crossed please...
+ for a in range(0, tries):
+ # UI update
+ status.cur = a
+ radio.status_fn(status)
+ for i in range(0, len(magic)):
+ # this is needed due to timming
+ send(radio, magic[i])
+
+ # Now you get a x06 of ACK
+ ack = raw_recv(radio, 1)
+ if ack == CMD_ACK:
+ return True
+
+ return False
+
+ # try to get the radio in program mode
+ ack = do_magic()
+ if not ack:
+ erc = "Radio did not accept program mode, "
+ erc += "check your cable and radio; then try again."
+ raise errors.RadioError(erc)
+
+ # now we request identification
+ send(radio, "M")
+ send(radio, "\x02")
+ ident = raw_recv(radio, 8)
+
+ ################# WARNING ##########################################
+ # Feidaxin radios has a "send id" procedure in the initial handshake
+ # but it's worthless, once you do a hardware reset the ident area
+ # get all 0xFF.
+ #
+ # Even FDX-288 software appears to match the model by any other
+ # mean, so I detected on a few images that the 3 first bytes are
+ # unique to each radio model, so for now we use that method untill
+ # proven otherwise
+ ####################################################################
+
+ LOG.debug("Radio's ID string:")
+ LOG.debug(util.hexprint(ident))
+
+ # final ACK
+ send(radio, CMD_ACK)
+ check_ack(radio, "Radio refused to enter programming mode")
+
+def do_download(radio):
+ """ The download function """
+ do_program(radio)
+ # UI progress
+ status = chirp_common.Status()
+ status.cur = 0
+ status.max = MEM_SIZE
+ status.msg = "Cloning from radio..."
+ radio.status_fn(status)
+ data = ""
+ for addr in range(0x0000, MEM_SIZE, BLOCK_SIZE):
+ send(radio, make_frame("R", addr))
+ d = recv(radio)
+ data += d
+ # UI Update
+ status.cur = addr
+ radio.status_fn(status)
+
+ return memmap.MemoryMap(data)
+
+def do_upload(radio):
+ """The upload function"""
+ do_program(radio)
+ # UI progress
+ status = chirp_common.Status()
+ status.cur = 0
+ status.max = MEM_SIZE
+ status.msg = "Cloning to radio..."
+ radio.status_fn(status)
+
+ for addr in range(0x0000, MEM_SIZE, BLOCK_SIZE):
+ send(radio, make_frame("W",addr), \
+ radio.get_mmap()[addr:addr+BLOCK_SIZE])
+ # UI Update
+ status.cur = addr
+ radio.status_fn(status)
+
+def model_match(cls, data):
+ """Use a experimental guess to determine if the radio you just
+ downloaded or the img opened you is for this model"""
+
+ # Using a few imgs of some FD radio I found that the four first
+ # bytes it's like the model fingerprint, so we have to testing the
+ # model type with this experimental method so far.
+ fp = data[0:4]
+ if fp == cls._IDENT:
+ return True
+ else:
+ LOG.debug("Unknowd Feidaxing radio, ID:")
+ LOG.debug(util.hexprint(fp))
+ print("Unknowd Feidaxing radio, ID:")
+ print util.hexprint(fp)
+ return False
+
+class FeidaxinFD2x8yRadio(chirp_common.CloneModeRadio):
+ """Feidaxin FD-268x & 288x Radios"""
+ VENDOR = "Feidaxin"
+ MODEL = "FD-268A/B & FD-288A/B"
+ BAUD_RATE = 9600
+ _memsize = MEM_SIZE
+ _upper = 99
+ _VFO_DEFAULT = 0
+ _IDENT = ""
+ _active_ch = ACTIVE_CH
+
+ @classmethod
+ def get_prompts(cls):
+ rp = chirp_common.RadioPrompts()
+ rp.experimental = \
+ ('The program mode of this radio has his tricks, '
+ 'so this driver is *completely experimental*.')
+ rp.pre_download = _(dedent("""\
+ This radio has a tricky way of enter into program mode,
+ even the original software has a few tries to get inside.
+
+ I will try 8 times (most the time ~3 will doit) and this
+ can take a few seconds, if don't work, try again a few times.
+
+ If you can get into it, please check the radio and cable.
+ """))
+ rp.pre_upload = _(dedent("""\
+ This radio has a tricky way of enter into program mode,
+ even the original software has a few tries to get inside.
+
+ I will try 8 times (most the time ~3 will doit) and this
+ can take a few seconds, if don't work, try again a few times.
+
+ If you can get into it, please check the radio and cable.
+ """))
+ return rp
+
+ def get_features(self):
+ """Return information about this radio's features"""
+ rf = chirp_common.RadioFeatures()
+ # this feature is READ ONLY by now.
+ rf.has_settings = True
+ rf.has_bank = False
+ rf.has_tuning_step = False
+ rf.has_name = False
+ rf.has_offset =True
+ rf.has_mode = False
+ rf.has_dtcs = True
+ rf.has_rx_dtcs = True
+ rf.has_dtcs_polarity = True
+ rf.has_ctone = True
+ rf.has_cross = True
+ rf.valid_duplexes = ["", "-", "+", "off"]
+ rf.valid_tmodes = ['', 'Tone', 'TSQL', 'DTCS', 'Cross']
+ # we have to remove "Tone->" because this is the same to "TQSL"
+ # I get a few days hitting the wall with my head about this...
+ rf.valid_cross_modes = [
+ "Tone->Tone",
+ "DTCS->",
+ "->DTCS",
+ "Tone->DTCS",
+ "DTCS->Tone",
+ "->Tone",
+ "DTCS->DTCS"]
+ # Power levels are golbal and no per channel, so disabled
+ #rf.valid_power_levels = POWER_LEVELS
+ # this radio has no skips
+ rf.valid_skips = []
+ # this radio modes are global and not per channel, so just FM
+ rf.valid_modes = ["FM"]
+ rf.valid_bands = [self._range]
+ rf.memory_bounds = (1, self._upper)
+ return rf
+
+ def sync_in(self):
+ """Do a download of the radio eeprom"""
+ data = do_download(self)
+
+ # as the radio comm protocol's identification is useless
+ # we test the model after having the img
+ if not model_match(self, data):
+ # ok, wrong model, fire an error
+ erc = "EEPROM fingerprint don't match, check if you "
+ erc += "selected the right radio model."
+ raise errors.RadioError(erc)
+
+ # all ok
+ self._mmap = data
+ self.process_mmap()
+
+ def sync_out(self):
+ """Do an upload to the radio eeprom"""
+ do_upload(self)
+
+ def process_mmap(self):
+ """Process the memory object.
+ Used in the download & interpretation of the eeporm and files"""
+ self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
+
+ def get_raw_memory(self, number):
+ """Return a raw representation of the memory object"""
+ 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_memory(self, number):
+ """Extract a high-level memory object from the low-level
+ memory map, This is called to populate a memory in the UI"""
+ # 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()
+ # number
+ mem.number = number
+
+ # empty
+ if _mem.get_raw()[0] == "\xFF":
+ mem.empty = True
+ return mem
+
+ # rx freq
+ mem.freq = int(_mem.rx_freq) *10
+
+ # checking if tx freq is empty, this is "possible" on the
+ # original soft after a warning, and radio is happy with it
+ if _mem.tx_freq.get_raw() == "\xFF\xFF\xFF\xFF":
+ mem.duplex = "off"
+ mem.offset = 0
+ else:
+ rx = int(_mem.rx_freq) * 10
+ tx = int(_mem.tx_freq) * 10
+ if tx == rx:
+ mem.offset = 0
+ mem.duplex = ""
+ else:
+ mem.duplex = rx > tx and "-" or "+"
+ mem.offset = abs(tx - rx)
+
+ # tone data
+ txtone = self._decode_tone(_mem.tx_tone)
+ rxtone = self._decode_tone(_mem.rx_tone)
+ chirp_common.split_tone_decode(mem, txtone, rxtone)
+
+ # Extra setting group, FD-268 don't uset it at all
+ # FD-288's do?
+ mem.extra = RadioSettingGroup("extra", "Extra")
+ busy = RadioSetting("Busy", "Busy Channel Lockout",
+ RadioSettingValueBoolean(
+ bool(_mem.busy_lock)))
+ mem.extra.append(busy)
+ scramble = RadioSetting("Scrambler", "Scrambler Option",
+ RadioSettingValueBoolean(
+ bool(_mem.scrambler)))
+ mem.extra.append(scramble)
+
+ # return mem
+ return mem
+
+ def set_memory(self, mem):
+ """Store details about a high-level memory to the memory map
+ This is called when a user edits a memory in the UI"""
+ # Get a low-level memory object mapped to the image
+ _mem = self._memobj.memory[mem.number - 1]
+
+ # Empty memory
+ if mem.empty:
+ _mem.set_raw("\xFF" * 16)
+ return
+
+ # freq rx
+ _mem.rx_freq = mem.freq / 10
+
+ # freq tx
+ if mem.duplex == "+":
+ _mem.tx_freq = (mem.freq + mem.offset) / 10
+ elif mem.duplex == "-":
+ _mem.tx_freq = (mem.freq - mem.offset) / 10
+ elif mem.duplex == "off":
+ for i in range(0, 4):
+ _mem.tx_freq[i].set_raw("\xFF")
+ else:
+ _mem.tx_freq = 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)
+
+ # extra settings
+ for setting in mem.extra:
+ setattr(_mem, setting.get_name(), setting.value)
+
+ return mem
+
+ def get_settings(self):
+ """Translate the bit in the mem_struct into settings in the UI"""
+ _mem = self._memobj
+ basic = RadioSettingGroup("basic", "Basic")
+ work = RadioSettingGroup("work", "Work Mode Settings")
+ top = RadioSettings(basic, work)
+
+ # Basic
+ sql = RadioSetting("settings.sql", "Squelch Level",
+ RadioSettingValueList(LIST_SQL,
+ LIST_SQL[_mem.settings.sql]))
+ basic.append(sql)
+
+ tot = RadioSetting("settings.tot", "Time out timer",
+ RadioSettingValueList(LIST_TOT,
+ LIST_TOT[_mem.settings.tot]))
+ basic.append(tot)
+
+ power = RadioSetting("settings.power", "Actual Power",
+ RadioSettingValueList(POWER_LEVELS,
+ POWER_LEVELS[
+ _mem.settings.power]))
+ basic.append(power)
+
+ key_lock = RadioSetting("settings.key", "Keyboard Lock",
+ RadioSettingValueList(KEY_LOCK,
+ KEY_LOCK[_mem.settings.key]))
+ basic.append(key_lock)
+
+ bw = RadioSetting("settings.bw", "Bandwidth",
+ RadioSettingValueList(BW,
+ BW[_mem.settings.bw]))
+ basic.append(bw)
+
+ powerrank = RadioSetting("settings.powerrank", "Power output adjust",
+ RadioSettingValueList(POWER_RANK,
+ POWER_RANK[_mem.settings.powerrank]))
+ basic.append(powerrank)
+
+ lamp = RadioSetting("settings.lamp", "LCD Lamp",
+ RadioSettingValueBoolean(
+ _mem.settings.lamp))
+ basic.append(lamp)
+
+ lamp_auto = RadioSetting("settings.lamp_auto", "LCD Lamp auto on/off",
+ RadioSettingValueBoolean(
+ _mem.settings.lamp_auto))
+ basic.append(lamp_auto)
+
+ bs = RadioSetting("settings.bs", "Battery Save",
+ RadioSettingValueBoolean(
+ _mem.settings.bs))
+ basic.append(bs)
+
+ warning = RadioSetting("settings.warning", "Warning Alerts",
+ RadioSettingValueBoolean(
+ _mem.settings.warning))
+ basic.append(warning)
+
+ monitor = RadioSetting("settings.monitor", "Monitor key",
+ RadioSettingValueBoolean(
+ _mem.settings.monitor))
+ basic.append(monitor)
+
+ # Work mode settings
+ wmset = RadioSetting("settings.wmem", "VFO/MR Mode",
+ RadioSettingValueList(W_MODE,
+ W_MODE[_mem.settings.wmem]))
+ work.append(wmset)
+
+ active_ch = RadioSetting("settings.active_ch", "Work Channel",
+ RadioSettingValueList(ACTIVE_CH,
+ ACTIVE_CH[_mem.settings.active_ch]))
+ work.append(active_ch)
+
+ # vfo rx validation
+ if _mem.vfo.vrx_freq.get_raw()[0] == "\xFF":
+ # if the vfo is not set, the UI cares about the
+ # length of the field, so set a default
+ LOG.debug("VFO freq not set, setting it to default %s" \
+ % self._VFO_DEFAULT)
+ vfo = self._VFO_DEFAULT
+ else:
+ vfo = int(_mem.vfo.vrx_freq) * 10
+
+ vf_freq = RadioSetting("vfo.vrx_freq", "VFO frequency",
+ RadioSettingValueString(0, 10,
+ chirp_common.format_freq(vfo)))
+ work.append(vf_freq)
+
+ # shift works
+ # VSHIFT = ["None", "-", "+"]
+ sset = 0
+ if bool(_mem.vfo.shift_minus) == True:
+ sset = 1
+ elif bool(_mem.vfo.shift_plus) == True:
+ sset = 2
+
+ shift = RadioSetting("shift", "VFO Shift",
+ RadioSettingValueList(VSHIFT,
+ VSHIFT[sset]))
+ work.append(shift)
+
+ # vfo shift validation if none set it to ZERO
+ if _mem.settings.vfo_shift.get_raw()[0] == "\xFF":
+ # if the shift is not set, the UI cares about the
+ # length of the field, so set to zero
+ LOG.debug("VFO shift not set, setting it to zero")
+ vfo_shift = 0
+ else:
+ vfo_shift = int(_mem.settings.vfo_shift) * 10
+
+ offset = RadioSetting("settings.vfo_shift", "VFO Offset",
+ RadioSettingValueString(0, 9,
+ chirp_common.format_freq(vfo_shift)))
+ work.append(offset)
+
+ step = RadioSetting("settings.step", "VFO step",
+ RadioSettingValueList(STEPF,
+ STEPF[_mem.settings.step]))
+ work.append(step)
+
+ # at least for FD-268A/B it doesn't work as stated, so disabled
+ # by now
+ #scamble = RadioSetting("vfo.scramble", "Scramble",
+ #RadioSettingValueList(ONOFF,
+ #ONOFF[int(_mem.vfo.scramble)]))
+ #work.append(scamble)
+
+ #busy_lock = RadioSetting("vfo.busy_lock", "Busy Lock out",
+ #RadioSettingValueList(ONOFF,
+ #ONOFF[int(_mem.vfo.busy_lock)]))
+ #work.append(busy_lock)
+
+ # FD-288 Family ANI settings
+ if "FD-288" in self.MODEL:
+ ani_mode = RadioSetting("settings.ani_mode", "ANI ID",
+ RadioSettingValueList(ANI,
+ ANI[_mem.settings.ani_mode]))
+ work.append(ani_mode)
+
+ # it can't be \xFF
+ ani_value = str(_mem.settings.ani)
+ if ani_value == "\xFF\xFF\xFF":
+ ani_value = "200"
+
+ ani_value = "".join(x for x in ani_value if (int(x) >= 2 and int(x) <= 9))
+
+ ani = RadioSetting("settings.ani", "ANI (200-999)",
+ RadioSettingValueString(0, 3, ani_value))
+ work.append(ani)
+
+ 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"""
+ def _get_shift(obj):
+ """Get the amount of offset in the memmap"""
+ shift = 0
+ sf = str(obj.settings.vfo_shift)
+ if sf[0] != "\xFF":
+ shift = int(mobj.settings.vfo_shift) * 10
+ return shift
+
+ def _get_vrx(obj):
+ """Get the vfo rx freq"""
+ return int(obj.vfo.vrx_freq) * 10
+
+ def _update_vtx(o, rx, offset):
+ """Update the Vfo TX mem from the value of rx & the offset"""
+ # check the shift sign
+ plus = bool(getattr(o, "shift_plus"))
+ minus = bool(getattr(o, "shift_minus"))
+
+ if plus:
+ o.vtx_freq = (rx + offset) / 10
+ elif minus:
+ o.vtx_freq = (rx - offset) / 10
+ else:
+ o.vtx_freq = rx / 10
+
+ mobj = self._memobj
+ flag = False
+ for element in settings:
+ if not isinstance(element, RadioSetting):
+ self.set_settings(element)
+ continue
+
+ # Let's roll the ball
+ if "." in element.get_name():
+ # real properties, more or less mapeable
+ inter, setting = element.get_name().split(".")
+ obj = getattr(mobj, inter)
+ value = element.value
+
+ # test on this cases .......
+ if setting in ["sql", "tot", "powerrank", \
+ "active_ch", "ani_mode"]:
+ value = int(value)
+
+ # test on this cases .......
+ if setting in ["lamp", "lamp_auto", "bs", \
+ "warning","monitor"]:
+ value = bool(value)
+ # warning and bs have a sister setting in LCD
+ if setting == "warning" or setting == "bs":
+ # aditional setting
+ setattr(obj, setting + "1", value)
+
+ # monitorval: monitor = 0 > monitorval = 0
+ # monitorval: monitor = 1 > monitorval = x30
+ if setting == "monitor":
+ # sister setting in LCD
+ if value:
+ setattr(obj, "monitorval", 0x30)
+ else:
+ setattr(obj, "monitorval", 0)
+
+ # case power
+ if setting == "power":
+ value = str(value) == "High" and True or False
+
+ # case key
+ # key => auto = 0, manu = 1
+ if setting == "key":
+ value = str(value) == "Manual" and True or False
+
+ # case bandwidth
+ # bw: 0 = nar, 1 = Wide & must equal bw1
+ if setting == "bw":
+ value = str(value) == "Wide" and True or False
+ # sister attr
+ setattr(obj, "bw1", value)
+
+ # work mem wmem/wvfo
+ if setting == "wmem":
+ if str(value) == "Memory":
+ value = True
+ # sister attr
+ setattr(obj, "wvfo", not value)
+ else:
+ value = False
+ # sister attr
+ setattr(obj, "wvfo", not value)
+
+ # case step
+ # STEPF = ["5", "10", "6.25", "12.5", "25"]
+ if setting == "step":
+ value = STEPF.index(str(value))
+
+ # case vrx_freq
+ if setting == "vrx_freq":
+ value = chirp_common.parse_freq(str(value)) / 10
+ # you must calculate the apropiate txfreq from shift and offset
+ # verify shift
+ shift = _get_shift(mobj)
+ # update the tx vfo freq
+ _update_vtx(obj, value * 10, shift)
+
+ # vfo_shift = offset
+ if setting == "vfo_shift":
+ value = chirp_common.parse_freq(str(value)) / 10
+ # you must calculate the apropiate txfreq from shift and offset
+ # get vfo rx
+ vrx = _get_vrx(mobj)
+ # update the tx vfo freq
+ _update_vtx(mobj.vfo, vrx, value * 10)
+
+ # at least for FD-268A/B it doesn't work as stated, so disabled
+ # by now, does this work on the fd-288s?
+
+ ## case scramble & busy_lock
+ #if setting == "scramble" or setting == "busy_lock":
+ #value = bool(ONOFF.index(str(value)))
+
+ # ani value, only for FD-288
+ if setting == "ani":
+ if "FD-268" in self.MODEL:
+ # 268 doesn't have ani setting
+ continue
+ else:
+ # 288 models, validate the input [200-999] | ""
+ # we will left adjust and zero pad to avoid errors
+ # between inputs in the UI
+ value = str(value).strip().ljust(3, "0")
+ value = int(value)
+ if value == 0:
+ value = 200
+ else:
+ if value > 999 or value < 200:
+ raise errors.InvalidValueError(
+ "The ANI value must be between 200 and 999, not %03i" % value)
+
+ value = str(value)
+
+ else:
+ # Others that are artifact for real values, not than mapeables
+ # selecting the values to work
+ setting = str(element.get_name())
+ value = str(element.value)
+
+ # vfo_shift
+ if setting == "shift":
+ # get shift
+ offset = _get_shift(mobj)
+ # get vfo rx
+ vrx = _get_vrx(mobj)
+
+ # VSHIFT = ["None", "-", "+"]
+ if value == "+":
+ mobj.vfo.shift_plus = True
+ mobj.vfo.shift_minus = False
+ elif value == "-":
+ mobj.vfo.shift_plus = False
+ mobj.vfo.shift_minus = True
+ else:
+ mobj.vfo.shift_plus = False
+ mobj.vfo.shift_minus = False
+
+ # update the tx vfo freq
+ _update_vtx(mobj.vfo, vrx, offset)
+
+ if setting != "shift":
+ setattr(obj, setting, value)
+
+ @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 fingerprint, this experimental
+ match_model = model_match(cls, filedata)
+
+ if match_size and match_model:
+ return True
+ else:
+ return False
+
+##
+## FD-268 family: this are the original tested models, FD-268B UHF
+## was tested "remotely" just have the 268A at hand to test.
+##
+
+ at directory.register
+class FD268ARadio(FeidaxinFD2x8yRadio):
+ """Feidaxin FD-268A Radio"""
+ MODEL = "FD-268A"
+ _range = (136000000, 174000000)
+ _VFO_DEFAULT = 145000000
+ _IDENT = "\xFF\xEE\x46\xFF"
+
+ at directory.register
+class FD268BRadio(FeidaxinFD2x8yRadio):
+ """Feidaxin FD-268B Radio"""
+ MODEL = "FD-268B"
+ _range = (400000000, 470000000)
+ _VFO_DEFAULT = 439000000
+ _IDENT = "\xFF\xEE\x44\xFF"
+
+##
+## FD-288 Family: the only difference from this family to the FD-268's
+## are the ANI settings
+##
+
+ at directory.register
+class FD288ARadio(FeidaxinFD2x8yRadio):
+ """Feidaxin FD-288A Radio"""
+ MODEL = "FD-288A"
+ _range = (136000000, 174000000)
+ _VFO_DEFAULT = 145000000
+ _IDENT = "\xFF\xEE\x4B\xFF"
+
+ at directory.register
+class FD288BRadio(FeidaxinFD2x8yRadio):
+ """Feidaxin FD-288 Radio"""
+ MODEL = "FD-288B"
+ _range = (400000000, 470000000)
+ _VFO_DEFAULT = 439000000
+ _IDENT = "\xFF\xEE\x4C\xFF"
+
+#######################################################################$
+# This is are just rough guesses and must be tested with radios
+# on hand to test it, but, playing with FDX-288 soft & chirp
+# it looks promising
+########################################################################
+
+#@directory.register
+#class FD160ARadio(FeidaxinFD2x8yRadio):
+ #"""Feidaxin FD-160A Radio"""
+ #MODEL = "FD-160A"
+ #_range = (136000000, 174000000)
+ #_VFO_DEFAULT = 145000000
+ #_IDENT = "\xFF\xEE\x48\xFF"
+
+#@directory.register
+#class FD460ARadio(FeidaxinFD2x8yRadio):
+ #"""Feidaxin FD-460A Radio"""
+ #MODEL = "FD-460A"
+ #_range = (400000000, 470000000)
+ #_VFO_DEFAULT = 439000000
+ #_IDENT = "\xFF\xEE\x4A\xFF"
+
+#@directory.register
+#class FD450ARadio(FeidaxinFD2x8yRadio):
+ #"""Feidaxin FD-450A Radio"""
+ #MODEL = "FD-450A"
+ #_range = (400000000, 470000000)
+ #_VFO_DEFAULT = 439000000
+ #_IDENT = "\xFF\xEE\x44\xFF"
diff --git a/chirp/drivers/ft857.py b/chirp/drivers/ft857.py
index ca00e30..dee850e 100644
--- a/chirp/drivers/ft857.py
+++ b/chirp/drivers/ft857.py
@@ -25,6 +25,7 @@ from chirp.settings import RadioSetting, RadioSettingGroup, \
import os
import logging
from textwrap import dedent
+from chirp.util import safe_charset_string
LOG = logging.getLogger(__name__)
@@ -569,29 +570,34 @@ class FT857Radio(ft817.FT817Radio):
RadioSettingValueBoolean(_settings.arts_id))
extended.append(rs)
st = RadioSettingValueString(0, 10,
- ''.join([self._CALLSIGN_CHARSET[x]
- for x in self._memobj.arts_idw]))
+ safe_charset_string(
+ self._memobj.arts_idw,
+ self._CALLSIGN_CHARSET)
+ )
st.set_charset(self._CALLSIGN_CHARSET)
rs = RadioSetting("arts_idw", "ARTS IDW", st)
extended.append(rs)
st = RadioSettingValueString(0, 40,
- ''.join([self._BEACON_CHARSET[x]
- for x in self._memobj.beacon_text1
- ]))
+ safe_charset_string(
+ self._memobj.beacon_text1,
+ self._BEACON_CHARSET)
+ )
st.set_charset(self._BEACON_CHARSET)
rs = RadioSetting("beacon_text1", "Beacon text1", st)
extended.append(rs)
st = RadioSettingValueString(0, 40,
- ''.join([self._BEACON_CHARSET[x]
- for x in
- self._memobj.beacon_text2]))
+ safe_charset_string(
+ self._memobj.beacon_text2,
+ self._BEACON_CHARSET)
+ )
st.set_charset(self._BEACON_CHARSET)
rs = RadioSetting("beacon_text2", "Beacon text2", st)
extended.append(rs)
st = RadioSettingValueString(0, 40,
- ''.join([self._BEACON_CHARSET[x]
- for x in
- self._memobj.beacon_text3]))
+ safe_charset_string(
+ self._memobj.beacon_text3,
+ self._BEACON_CHARSET)
+ )
st.set_charset(self._BEACON_CHARSET)
rs = RadioSetting("beacon_text3", "Beacon text3", st)
extended.append(rs)
@@ -856,16 +862,18 @@ class FT857Radio(ft817.FT817Radio):
RadioSettingValueInteger(0, 100, _settings.nb_level))
basic.append(rs)
st = RadioSettingValueString(0, 4,
- ''.join([self._CALLSIGN_CHARSET[x]
- for x in
- self._memobj.op_filter1_name]))
+ safe_charset_string(
+ self._memobj.op_filter1_name,
+ self._CALLSIGN_CHARSET)
+ )
st.set_charset(self._CALLSIGN_CHARSET)
rs = RadioSetting("op_filter1_name", "Optional filter1 name", st)
extended.append(rs)
st = RadioSettingValueString(0, 4,
- ''.join([self._CALLSIGN_CHARSET[x]
- for x in
- self._memobj.op_filter2_name]))
+ safe_charset_string(
+ self._memobj.op_filter2_name,
+ self._CALLSIGN_CHARSET)
+ )
st.set_charset(self._CALLSIGN_CHARSET)
rs = RadioSetting("op_filter2_name", "Optional filter2 name", st)
extended.append(rs)
diff --git a/chirp/drivers/icomciv.py b/chirp/drivers/icomciv.py
index dd32ae7..89100d1 100644
--- a/chirp/drivers/icomciv.py
+++ b/chirp/drivers/icomciv.py
@@ -30,8 +30,8 @@ u8 unknown4;
bbcd rtone[2];
u8 unknown5;
bbcd ctone[2];
-u8 unknown6[2];
-bbcd dtcs;
+u8 dtcs_polarity;
+bbcd dtcs[2];
u8 unknown[17];
char name[9];
"""
@@ -50,8 +50,8 @@ u8 unknown4;
bbcd rtone[2];
u8 unknown5;
bbcd ctone[2];
-u8 unknown6[2];
-bbcd dtcs;
+u8 dtcs_polarity;
+bbcd dtcs[2];
u8 unknown[11];
char name[9];
"""
@@ -265,9 +265,18 @@ class IcomCIVRadio(icf.IcomLiveRadio):
if self._rf.valid_tmodes:
mem.tmode = self._rf.valid_tmodes[memobj.tmode]
+ if self._rf.has_dtcs_polarity:
+ if memobj.dtcs_polarity == 0x11:
+ mem.dtcs_polarity = "RR"
+ elif memobj.dtcs_polarity == 0x10:
+ mem.dtcs_polarity = "RN"
+ elif memobj.dtcs_polarity == 0x01:
+ mem.dtcs_polarity = "NR"
+ else:
+ mem.dtcs_polarity = "NN"
+
if self._rf.has_dtcs:
- # FIXME
- mem.dtcs = bitwise.bcd_to_int([memobj.dtcs])
+ mem.dtcs = bitwise.bcd_to_int(memobj.dtcs)
if "Tone" in self._rf.valid_tmodes:
mem.rtone = int(memobj.rtone) / 10.0
@@ -308,6 +317,19 @@ class IcomCIVRadio(icf.IcomLiveRadio):
memobj.ctone = int(mem.ctone * 10)
memobj.rtone = int(mem.rtone * 10)
+ if self._rf.has_dtcs_polarity:
+ if mem.dtcs_polarity == "RR":
+ memobj.dtcs_polarity = 0x11
+ elif mem.dtcs_polarity == "RN":
+ memobj.dtcs_polarity = 0x10
+ elif mem.dtcs_polarity == "NR":
+ memobj.dtcs_polarity = 0x01
+ else:
+ memobj.dtcs_polarity = 0x00
+
+ if self._rf.has_dtcs:
+ bitwise.int_to_bcd(memobj.dtcs, mem.dtcs)
+
LOG.debug(repr(memobj))
self._send_frame(f)
@@ -354,7 +376,7 @@ class Icom7000Radio(IcomCIVRadio):
self._rf.has_offset = False
self._rf.has_name = True
self._rf.has_tuning_step = False
- self._rf.valid_modes = ["LSB", "USB", "AM", "CW", "RTTY", "FM"]
+ 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_bands = [(30000, 199999999), (400000000, 470000000)]
diff --git a/chirp/drivers/th9800.py b/chirp/drivers/th9800.py
index b3ac955..545c3f4 100644
--- a/chirp/drivers/th9800.py
+++ b/chirp/drivers/th9800.py
@@ -44,8 +44,8 @@ struct mem {
scramb:1,
compand:1,
emphasis:1
- unknown1a:1,
- unknown1b:2;
+ unknown1a:2,
+ sqlmode:1; // carrier, tone
u8 rptmod:2, // off, -, +
reverse:1,
talkaround:1,
@@ -352,6 +352,10 @@ class TYTTH9800Base(chirp_common.Radio):
_mem.tx_freq = mem.freq / 10
_mem.tmode = TMODES.index(mem.tmode)
+ if mem.tmode == "TSQL" or mem.tmode == "DTCS":
+ _mem.sqlmode = 1
+ else:
+ _mem.sqlmode = 0
_mem.ctcss = mem.rtone * 10
_mem.dtcs = mem.dtcs
_mem.dtcs_pol = DTCS_POLARITY.index(mem.dtcs_polarity)
diff --git a/chirp/util.py b/chirp/util.py
index 1fc5529..064b70b 100644
--- a/chirp/util.py
+++ b/chirp/util.py
@@ -94,3 +94,16 @@ def get_dict_rev(thedict, value):
for k, v in thedict.items():
_dict[v] = k
return _dict[value]
+
+
+def safe_charset_string(indexes, charset, safechar=" "):
+ """Return a string from an array of charset indexes,
+ replaces out of charset values with safechar"""
+ assert safechar in charset
+ _string = ""
+ for i in indexes:
+ try:
+ _string += charset[i]
+ except IndexError:
+ _string += safechar
+ return _string
diff --git a/locale/uk_UA/LC_MESSAGES/CHIRP.mo b/locale/uk_UA/LC_MESSAGES/CHIRP.mo
new file mode 100644
index 0000000..b388648
Binary files /dev/null and b/locale/uk_UA/LC_MESSAGES/CHIRP.mo differ
--
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