[chirp_devel] Fwd: [PATCH] [BF-T8] add support for the Baofeng BF-T8
Jim Unroe
Wed May 19 18:07:32 PDT 2021
Image attached for testing: Baofeng_BF-T8.img
---------- Forwarded message ---------
From: Jim Unroe <kc9hi at comcast.net>
Date: Wed, May 19, 2021 at 9:00 PM
Subject: [PATCH] [BF-T8] add support for the Baofeng BF-T8
To: <Rock.Unroe at gmail.com>
# HG changeset patch
# User Jim Unroe <rock.unroe at gmail.com>
# Date 1621472333 14400
# Wed May 19 20:58:53 2021 -0400
# Node ID ccf8f96034cd9dbb6f3462bcf10d68526c3e0572
# Parent b04ba05b7b646e144af4f074663941ca122dc4ed
[BF-T8] add support for the Baofeng BF-T8
This patch adds support for the Baofeng BF-T8 (and it variants)
related to #8263
diff -r b04ba05b7b64 -r ccf8f96034cd chirp/drivers/bf-t8.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chirp/drivers/bf-t8.py Wed May 19 20:58:53 2021 -0400
@@ -0,0 +1,702 @@
+# Copyright 2021 Jim Unroe <rock.unroe at gmail.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/>.
+
+import time
+import os
+import struct
+import logging
+
+from chirp import (
+ bitwise,
+ chirp_common,
+ directory,
+ errors,
+ memmap,
+ util,
+)
+from chirp.settings import (
+ RadioSetting,
+ RadioSettingGroup,
+ RadioSettings,
+ RadioSettingValueBoolean,
+ RadioSettingValueFloat,
+ RadioSettingValueInteger,
+ RadioSettingValueList,
+ RadioSettingValueString,
+)
+
+LOG = logging.getLogger(__name__)
+
+MEM_FORMAT = """
+#seekto 0x0000;
+struct {
+ lbcd rxfreq[4]; // RX Frequency
+ lbcd txfreq[4]; // TX Frequency
+ u8 rx_tmode; // RX Tone Mode
+ u8 rx_tone; // PL/DPL Decode
+ u8 tx_tmode; // TX Tone Mode
+ u8 tx_tone; // PL/DPL Encode
+ u8 unknown1:3, //
+ skip:1, // Scan Add: 1 = Skip, 0 = Scan
+ unknown2:2,
+ isnarrow:1, // W/N: 1 = Narrow, 0 = Wide
+ lowpower:1; // TX Power: 1 = Low, 0 = High
+ u8 unknown3[3]; //
+} memory[99];
+
+#seekto 0x0630;
+struct {
+ u8 squelch; // SQL
+ u8 vox; // Vox Lv
+ u8 tot; // TOT
+ u8 unk1:3, //
+ ste:1, // Tail Clear
+ bcl:1, // BCL
+ save:1, // Save
+ tdr:1, // TDR
+ beep:1; // Beep
+ u8 voice; // Voice
+ u8 abr; // Back Light
+ u8 ring; // Ring
+ u8 unknown; //
+ u8 mra; // MR Channel A
+ u8 mrb; // MR Channel B
+ u8 disp_ab; // Display A/B Selected
+ ul16 fmcur; // Broadcast FM station
+ u8 workmode; // Work Mode
+ u8 wx; // NOAA WX ch#
+ u8 area; // Area Selected
+} settings;
+"""
+
+CMD_ACK = "\x06"
+
+TONES = chirp_common.TONES
+TMODES = ["", "Tone", "DTCS", "DTCS"]
+
+AB_LIST = ["A", "B"]
+ABR_LIST = ["OFF", "ON", "Key"]
+AREA_LIST = ["China", "Japan", "Korea", "Malaysia", "American",
+ "Australia", "Iran", "Taiwan", "Europe", "Russia"]
+MDF_LIST = ["Frequency", "Channel #", "Name"]
+RING_LIST = ["OFF"] + ["%s" % x for x in range(1, 11)]
+TOT_LIST = ["OFF"] + ["%s seconds" % x for x in range(30, 210, 30)]
+VOICE_LIST = ["Off", "Chinese", "English"]
+VOX_LIST = ["OFF"] + ["%s" % x for x in range(1, 6)]
+WORKMODE_LIST = ["General", "PMR"]
+WX_LIST = ["CH01 - 162.550",
+ "CH02 - 162.400",
+ "CH03 - 162.475",
+ "CH04 - 162.425",
+ "CH05 - 162.450",
+ "CH06 - 162.500",
+ "CH07 - 162.525"
+ ]
+
+SETTING_LISTS = {
+ "ab": AB_LIST,
+ "abr": ABR_LIST,
+ "area": AREA_LIST,
+ "mdf": MDF_LIST,
+ "ring": RING_LIST,
+ "tot": TOT_LIST,
+ "voice": VOICE_LIST,
+ "vox": VOX_LIST,
+ "workmode": WORKMODE_LIST,
+ "wx": WX_LIST,
+ }
+
+FRS_FREQS1 = [462.5625, 462.5875, 462.6125, 462.6375, 462.6625,
+ 462.6875, 462.7125]
+FRS_FREQS2 = [467.5625, 467.5875, 467.6125, 467.6375, 467.6625,
+ 467.6875, 467.7125]
+FRS_FREQS3 = [462.5500, 462.5750, 462.6000, 462.6250, 462.6500,
+ 462.6750, 462.7000, 462.7250]
+FRS_FREQS = FRS_FREQS1 + FRS_FREQS2 + FRS_FREQS3
+
+
+def _enter_programming_mode(radio):
+ serial = radio.pipe
+
+ exito = False
+ for i in range(0, 5):
+ serial.write(radio._magic)
+ ack = serial.read(1)
+
+ try:
+ if ack == CMD_ACK:
+ exito = True
+ break
+ except:
+ LOG.debug("Attempt #%s, failed, trying again" % i)
+ pass
+
+ # check if we had EXITO
+ if exito is False:
+ _exit_programming_mode(radio)
+ msg = "The radio did not accept program mode after five tries.\n"
+ msg += "Check you interface cable and power cycle your radio."
+ raise errors.RadioError(msg)
+
+ try:
+ serial.write("\x02")
+ ident = serial.read(len(radio._fingerprint))
+ except:
+ _exit_programming_mode(radio)
+ raise errors.RadioError("Error communicating with radio")
+
+ if not ident == radio._fingerprint:
+ _exit_programming_mode(radio)
+ LOG.debug(util.hexprint(ident))
+ raise errors.RadioError("Radio returned unknown identification string")
+
+ try:
+ serial.write(CMD_ACK)
+ ack = serial.read(1)
+ except:
+ _exit_programming_mode(radio)
+ raise errors.RadioError("Error communicating with radio")
+
+ if ack != CMD_ACK:
+ _exit_programming_mode(radio)
+ raise errors.RadioError("Radio refused to enter programming mode")
+
+
+def _exit_programming_mode(radio):
+ serial = radio.pipe
+ try:
+ serial.write("E")
+ except:
+ raise errors.RadioError("Radio refused to exit programming mode")
+
+
+def _read_block(radio, block_addr, block_size):
+ serial = radio.pipe
+
+ cmd = struct.pack(">cHb", 'R', block_addr, block_size)
+ expectedresponse = "W" + cmd[1:]
+ LOG.debug("Reading block %04x..." % (block_addr))
+
+ try:
+ serial.write(cmd)
+ response = serial.read(4 + block_size)
+ if response[:4] != expectedresponse:
+ raise Exception("Error reading block %04x." % (block_addr))
+
+ block_data = response[4:]
+
+ serial.write(CMD_ACK)
+ ack = serial.read(1)
+ except:
+ _exit_programming_mode(radio)
+ raise errors.RadioError("Failed to read block at %04x" % block_addr)
+
+ if ack != CMD_ACK:
+ _exit_programming_mode(radio)
+ raise Exception("No ACK reading block %04x." % (block_addr))
+
+ return block_data
+
+
+def _write_block(radio, block_addr, block_size):
+ serial = radio.pipe
+
+ cmd = struct.pack(">cHb", 'W', block_addr, block_size)
+ data = radio.get_mmap()[block_addr:block_addr + block_size]
+
+ LOG.debug("Writing Data:")
+ LOG.debug(util.hexprint(cmd + data))
+
+ try:
+ serial.write(cmd + data)
+ if serial.read(1) != CMD_ACK:
+ raise Exception("No ACK")
+ except:
+ _exit_programming_mode(radio)
+ raise errors.RadioError("Failed to send block "
+ "to radio at %04x" % block_addr)
+
+
+def do_download(radio):
+ LOG.debug("download")
+ _enter_programming_mode(radio)
+
+ data = ""
+
+ status = chirp_common.Status()
+ status.msg = "Cloning from radio"
+
+ status.cur = 0
+ status.max = radio._memsize
+
+ for addr in range(0, radio._memsize, radio.BLOCK_SIZE):
+ status.cur = addr + radio.BLOCK_SIZE
+ radio.status_fn(status)
+
+ block = _read_block(radio, addr, radio.BLOCK_SIZE)
+ data += block
+
+ LOG.debug("Address: %04x" % addr)
+ LOG.debug(util.hexprint(block))
+
+ _exit_programming_mode(radio)
+
+ return memmap.MemoryMap(data)
+
+
+def do_upload(radio):
+ status = chirp_common.Status()
+ status.msg = "Uploading to radio"
+
+ _enter_programming_mode(radio)
+
+ status.cur = 0
+ status.max = radio._memsize
+
+ for start_addr, end_addr in radio._ranges:
+ for addr in range(start_addr, end_addr, radio.BLOCK_SIZE_UP):
+ status.cur = addr + radio.BLOCK_SIZE_UP
+ radio.status_fn(status)
+ _write_block(radio, addr, radio.BLOCK_SIZE_UP)
+
+ _exit_programming_mode(radio)
+
+
+class BFT8Radio(chirp_common.CloneModeRadio):
+ """Baofeng BF-T8"""
+ VENDOR = "Baofeng"
+ MODEL = "BF-T8"
+ BAUD_RATE = 9600
+ BLOCK_SIZE = BLOCK_SIZE_UP = 0x10
+ ODD_SPLIT = True
+ HAS_NAMES = False
+ SKIP_VALUES = []
+ DTCS_CODES = sorted(chirp_common.DTCS_CODES)
+
+ POWER_LEVELS = [chirp_common.PowerLevel("High", watts=2.00),
+ chirp_common.PowerLevel("Low", watts=0.50)]
+
+ _magic = "\x02" + "PROGRAM"
+ _fingerprint = "\x2E" + "BF-T6" + "\x2E"
+ _upper = 99
+ _frs = _upper == 22
+
+ _ranges = [
+ (0x0000, 0x0B60),
+ ]
+ _memsize = 0x0B60
+
+ def get_features(self):
+ rf = chirp_common.RadioFeatures()
+ rf.has_settings = True
+ rf.has_bank = False
+ rf.has_ctone = True
+ rf.has_cross = True
+ rf.has_rx_dtcs = True
+ rf.has_tuning_step = False
+ rf.can_odd_split = self.ODD_SPLIT
+ rf.has_name = self.HAS_NAMES
+ rf.valid_skips = self.SKIP_VALUES
+ rf.valid_tmodes = ["", "Tone", "TSQL", "DTCS", "Cross"]
+ rf.valid_cross_modes = ["Tone->Tone", "Tone->DTCS", "DTCS->Tone",
+ "->Tone", "->DTCS", "DTCS->", "DTCS->DTCS"]
+ rf.valid_dtcs_codes = self.DTCS_CODES
+ rf.valid_power_levels = self.POWER_LEVELS
+ rf.valid_duplexes = ["", "-", "+", "split", "off"]
+ rf.valid_modes = ["FM", "NFM"] # 25 kHz, 12.5 KHz.
+ rf.memory_bounds = (1, self._upper)
+ rf.valid_tuning_steps = [2.5, 5., 6.25, 10., 12.5, 25.]
+ rf.valid_bands = [(400000000, 470000000)]
+
+ return rf
+
+ def process_mmap(self):
+ self._memobj = bitwise.parse(MEM_FORMAT, self._mmap)
+
+ def validate_memory(self, mem):
+ msgs = ""
+ msgs = chirp_common.CloneModeRadio.validate_memory(self, mem)
+
+ _msg_freq = 'Memory location cannot change frequency'
+ _msg_simplex = 'Memory location only supports Duplex:(None)'
+ _msg_nfm = 'Memory location only supports Mode: NFM'
+ _msg_txp = 'Memory location only supports Power: Low'
+
+ # FRS only models
+ if self._frs:
+ # range of memories with values set by FCC rules
+ if mem.freq != int(FRS_FREQS[mem.number - 1] * 1000000):
+ # warn user can't change frequency
+ msgs.append(chirp_common.ValidationError(_msg_freq))
+
+ # channels 1 - 22 are simplex only
+ if str(mem.duplex) != "":
+ # warn user can't change duplex
+ msgs.append(chirp_common.ValidationError(_msg_simplex))
+
+ # channels 1 - 22 are NFM only
+ if str(mem.mode) != "NFM":
+ # warn user can't change mode
+ msgs.append(chirp_common.ValidationError(_msg_nfm))
+
+ # channels 8 - 14 are low power NFM only
+ if mem.number >= 8 and mem.number <= 14:
+ if str(mem.power) != "Low":
+ # warn user can't change power
+ msgs.append(chirp_common.ValidationError(_msg_txp))
+
+ return msgs
+
+ def sync_in(self):
+ """Download from radio"""
+ try:
+ data = do_download(self)
+ except errors.RadioError:
+ # Pass through any real errors we raise
+ raise
+ except:
+ # If anything unexpected happens, make sure we raise
+ # a RadioError and log the problem
+ LOG.exception('Unexpected error during download')
+ raise errors.RadioError('Unexpected error communicating '
+ 'with the radio')
+ self._mmap = data
+ self.process_mmap()
+
+ def sync_out(self):
+ """Upload to radio"""
+ try:
+ do_upload(self)
+ except:
+ # If anything unexpected happens, make sure we raise
+ # a RadioError and log the problem
+ LOG.exception('Unexpected error during upload')
+ raise errors.RadioError('Unexpected error communicating '
+ 'with the radio')
+
+ def get_raw_memory(self, number):
+ return repr(self._memobj.memory[number - 1])
+
+ def _get_tone(self, mem, _mem):
+ rx_tone = tx_tone = None
+
+ tx_tmode = TMODES[_mem.tx_tmode]
+ rx_tmode = TMODES[_mem.rx_tmode]
+
+ if tx_tmode == "Tone":
+ tx_tone = TONES[_mem.tx_tone]
+ elif tx_tmode == "DTCS":
+ tx_tone = self.DTCS_CODES[_mem.tx_tone]
+
+ if rx_tmode == "Tone":
+ rx_tone = TONES[_mem.rx_tone]
+ elif rx_tmode == "DTCS":
+ rx_tone = self.DTCS_CODES[_mem.rx_tone]
+
+ tx_pol = _mem.tx_tmode == 0x03 and "R" or "N"
+ rx_pol = _mem.rx_tmode == 0x03 and "R" or "N"
+
+ chirp_common.split_tone_decode(mem, (tx_tmode, tx_tone, tx_pol),
+ (rx_tmode, rx_tone, rx_pol))
+
+ def _get_mem(self, number):
+ return self._memobj.memory[number]
+
+ def get_memory(self, number):
+ _mem = self._get_mem(number - 1)
+
+ mem = chirp_common.Memory()
+
+ mem.number = number
+ mem.freq = int(_mem.rxfreq) * 10
+
+ # We'll consider any blank (i.e. 0MHz frequency) to be empty
+ if mem.freq == 0:
+ mem.empty = True
+ return mem
+
+ if _mem.rxfreq.get_raw() == "\xFF\xFF\xFF\xFF":
+ mem.freq = 0
+ mem.empty = True
+ mem.mode = "NFM"
+ if mem.number <= 22 and not self._frs:
+ LOG.debug("Initializing empty memory")
+ _mem.set_raw("\x00" * 13 + "\xFF" * 3)
+ FRS_FREQ = FRS_FREQS[mem.number - 1] * 1000000
+ mem.freq = FRS_FREQ
+ if mem.number >= 8 and mem.number <= 14:
+ mem.power = "Low"
+ else:
+ mem.power = "High"
+
+ return mem
+
+ if _mem.get_raw() == ("\xFF" * 16):
+ LOG.debug("Initializing empty memory")
+ _mem.set_raw("\x00" * 13 + "\xFF" * 3)
+
+ if int(_mem.rxfreq) == int(_mem.txfreq):
+ mem.duplex = ""
+ mem.offset = 0
+ else:
+ mem.duplex = int(_mem.rxfreq) > int(_mem.txfreq) and "-" or "+"
+ mem.offset = abs(int(_mem.rxfreq) - int(_mem.txfreq)) * 10
+
+ # wide/narrow
+ mem.mode = _mem.isnarrow and "NFM" or "FM"
+
+ # tone data
+ self._get_tone(mem, _mem)
+
+ # tx power
+ levels = self.POWER_LEVELS
+ try:
+ mem.power = levels[_mem.lowpower]
+ except IndexError:
+ LOG.error("Radio reported invalid power level %s (in %s)" %
+ (_mem.power, levels))
+ mem.power = levels[0]
+
+ if mem.number <= 22 and self._frs:
+ FRS_IMMUTABLE = ["freq", "duplex", "offset", "mode"]
+ if mem.number >= 8 and mem.number <= 14:
+ mem.immutable = FRS_IMMUTABLE + ["power"]
+ else:
+ mem.immutable = FRS_IMMUTABLE
+
+ return mem
+
+ def _set_tone(self, mem, _mem):
+ ((txmode, txtone, txpol),
+ (rxmode, rxtone, rxpol)) = chirp_common.split_tone_encode(mem)
+
+ _mem.tx_tmode = TMODES.index(txmode)
+ _mem.rx_tmode = TMODES.index(rxmode)
+ if txmode == "Tone":
+ _mem.tx_tone = TONES.index(txtone)
+ elif txmode == "DTCS":
+ _mem.tx_tmode = txpol == "R" and 0x03 or 0x02
+ _mem.tx_tone = self.DTCS_CODES.index(txtone)
+ if rxmode == "Tone":
+ _mem.rx_tone = TONES.index(rxtone)
+ elif rxmode == "DTCS":
+ _mem.rx_tmode = rxpol == "R" and 0x03 or 0x02
+ _mem.rx_tone = self.DTCS_CODES.index(rxtone)
+
+ def set_memory(self, mem):
+ _mem = self._get_mem(mem.number - 1)
+
+ # if empty memmory
+ if mem.empty:
+ if mem.number <= 22 and self._frs:
+ _mem.set_raw("\xFF" * 8 + "\x00" * 5 + "\xFF" * 3)
+ FRS_FREQ = int(FRS_FREQS[mem.number - 1] * 100000)
+ _mem.rxfreq = _mem.txfreq = FRS_FREQ
+ _mem.isnarrow = True
+ if mem.number >= 8 and mem.number <= 14:
+ _mem.lowpower = True
+ else:
+ _mem.lowpower = False
+ else:
+ _mem.set_raw("\xFF" * 8 + "\x00" * 4 + "\x03" + "\xFF" * 3)
+
+ return mem
+
+ _mem.set_raw("\x00" * 13 + "\xFF" * 3)
+
+ # frequency
+ _mem.rxfreq = mem.freq / 10
+
+ if mem.duplex == "off":
+ for i in range(0, 4):
+ _mem.txfreq[i].set_raw("\xFF")
+ elif mem.duplex == "split":
+ _mem.txfreq = mem.offset / 10
+ elif 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
+
+ # wide/narrow
+ _mem.isnarrow = mem.mode == "NFM"
+
+ # tone data
+ self._set_tone(mem, _mem)
+
+ # tx power
+ if mem.power:
+ _mem.lowpower = self.POWER_LEVELS.index(mem.power)
+ else:
+ _mem.lowpower = 0
+
+ return mem
+
+ def get_settings(self):
+ _settings = self._memobj.settings
+ basic = RadioSettingGroup("basic", "Basic Settings")
+ top = RadioSettings(basic)
+
+ # Menu 03
+ rs = RadioSettingValueInteger(0, 9, _settings.squelch)
+ rset = RadioSetting("squelch", "Squelch Level", rs)
+ basic.append(rset)
+
+ # Menu 11
+ rs = RadioSettingValueList(TOT_LIST, TOT_LIST[_settings.tot])
+ rset = RadioSetting("tot", "Time-out timer", rs)
+ basic.append(rset)
+
+ # Menu 06
+ rs = RadioSettingValueList(VOX_LIST, VOX_LIST[_settings.vox])
+ rset = RadioSetting("vox", "VOX Level", rs)
+ basic.append(rset)
+
+ # Menu 15 (BF-T8)
+ rs = RadioSettingValueList(VOICE_LIST, VOICE_LIST[_settings.voice])
+ rset = RadioSetting("voice", "Voice", rs)
+ basic.append(rset)
+
+ # Menu 12
+ rs = RadioSettingValueBoolean(_settings.bcl)
+ rset = RadioSetting("bcl", "Busy Channel Lockout", rs)
+ basic.append(rset)
+
+ # Menu 10
+ rs = RadioSettingValueBoolean(_settings.save)
+ rset = RadioSetting("save", "Battery Saver", rs)
+ basic.append(rset)
+
+ # Menu 08
+ rs = RadioSettingValueBoolean(_settings.tdr)
+ rset = RadioSetting("tdr", "Dual Watch", rs)
+ basic.append(rset)
+
+ # Menu 05
+ rs = RadioSettingValueBoolean(_settings.beep)
+ rset = RadioSetting("beep", "Beep", rs)
+ basic.append(rset)
+
+ # Menu 04
+ rs = RadioSettingValueList(ABR_LIST, ABR_LIST[_settings.abr])
+ rset = RadioSetting("abr", "Back Light", rs)
+ basic.append(rset)
+
+ # Menu 13
+ rs = RadioSettingValueList(RING_LIST, RING_LIST[_settings.ring])
+ rset = RadioSetting("ring", "Ring", rs)
+ basic.append(rset)
+
+ rs = RadioSettingValueBoolean(not _settings.ste)
+ rset = RadioSetting("ste", "Squelch Tail Eliminate", rs)
+ basic.append(rset)
+
+ #
+
+ rs = RadioSettingValueInteger(1, self._upper, _settings.mra)
+ rset = RadioSetting("mra", "MR A Channel #", rs)
+ basic.append(rset)
+
+ rs = RadioSettingValueInteger(1, self._upper, _settings.mrb)
+ rset = RadioSetting("mrb", "MR B Channel #", rs)
+ basic.append(rset)
+
+ rs = RadioSettingValueList(AB_LIST, AB_LIST[_settings.disp_ab])
+ rset = RadioSetting("disp_ab", "Selected Display Line", rs)
+ basic.append(rset)
+
+ rs = RadioSettingValueList(WX_LIST, WX_LIST[_settings.wx])
+ rset = RadioSetting("wx", "NOAA WX Radio", rs)
+ basic.append(rset)
+
+ def myset_freq(setting, obj, atrb, mult):
+ """ Callback to set frequency by applying multiplier"""
+ value = int(float(str(setting.value)) * mult)
+ setattr(obj, atrb, value)
+ return
+
+ # FM Broadcast Settings
+ val = _settings.fmcur
+ val = val / 10.0
+ val_low = 76.0
+ if val < val_low or val > 108.0:
+ val = 90.4
+ rx = RadioSettingValueFloat(val_low, 108.0, val, 0.1, 1)
+ rset = RadioSetting("settings.fmcur", "Broadcast FM Radio (MHz)", rx)
+ rset.set_apply_callback(myset_freq, _settings, "fmcur", 10)
+ basic.append(rset)
+
+ rs = RadioSettingValueList(WORKMODE_LIST,
+ WORKMODE_LIST[_settings.workmode])
+ rset = RadioSetting("workmode", "Work Mode", rs)
+ basic.append(rset)
+
+ rs = RadioSettingValueList(AREA_LIST, AREA_LIST[_settings.area])
+ rs.set_mutable(False)
+ rset = RadioSetting("area", "Area", rs)
+ basic.append(rset)
+
+ return top
+
+ def set_settings(self, settings):
+ for element in settings:
+ if not isinstance(element, RadioSetting):
+ self.set_settings(element)
+ continue
+ else:
+ try:
+ if "." in element.get_name():
+ bits = element.get_name().split(".")
+ obj = self._memobj
+ for bit in bits[:-1]:
+ obj = getattr(obj, bit)
+ setting = bits[-1]
+ else:
+ obj = self._memobj.settings
+ setting = element.get_name()
+
+ if element.has_apply_callback():
+ LOG.debug("Using apply callback")
+ element.run_apply_callback()
+ elif setting == "ste":
+ setattr(obj, setting, not int(element.value))
+ elif element.value.get_mutable():
+ LOG.debug("Setting %s = %s" % (setting, element.value))
+ setattr(obj, setting, element.value)
+ except Exception, e:
+ LOG.debug(element.get_name())
+ raise
+
+ @classmethod
+ def match_model(cls, filedata, filename):
+ # This radio has always been post-metadata, so never do
+ # old-school detection
+ return False
+
+
+class BFU9Alias(chirp_common.Alias):
+ VENDOR = "Baofeng"
+ MODEL = "BF-U9"
+
+
+class AR8Alias(chirp_common.Alias):
+ VENDOR = "Arcshell"
+ MODEL = "AR-8"
+
+
+ at directory.register
+class BaofengBFT8Generic(BFT8Radio):
+ ALIASES = [BFU9Alias, AR8Alias, ]
diff -r b04ba05b7b64 -r ccf8f96034cd tools/cpep8.manifest
--- a/tools/cpep8.manifest Wed Apr 28 07:50:34 2021 -0700
+++ b/tools/cpep8.manifest Wed May 19 20:58:53 2021 -0400
@@ -19,6 +19,7 @@
./chirp/drivers/baofeng_common.py
./chirp/drivers/baofeng_uv3r.py
./chirp/drivers/baofeng_wp970i.py
+./chirp/drivers/bf-t8.py
./chirp/drivers/bjuv55.py
./chirp/drivers/btech.py
./chirp/drivers/ft1500m.py
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Baofeng_BF-T8.img
Type: application/octet-stream
Size: 3081 bytes
Desc: not available
Url : http://intrepid.danplanet.com/pipermail/chirp_devel/attachments/20210519/a3564068/attachment-0001.img
More information about the chirp_devel
mailing list