[chirp_devel] Fwd: [PATCH 4 of 4] [RT76] Retevis RT76
Jim Unroe
Sat Apr 3 18:05:11 PDT 2021
Note: image files were attached to their respective patches.
Jim KC9HI
---------- Forwarded message ---------
From: Jim Unroe <kc9hi at comcast.net>
Date: Sat, Apr 3, 2021 at 8:59 PM
Subject: [PATCH 4 of 4] [RT76] Retevis RT76
To: <Rock.Unroe at gmail.com>
# HG changeset patch
# User Jim Unroe <rock.unroe at gmail.com>
# Date 1617488266 14400
# Sat Apr 03 18:17:46 2021 -0400
# Node ID 35ce102f7e2d432b0ba6a30b580904ad816c846e
# Parent c11f6ae9ccfd9b306db3b5f1e7fe166364a822b0
[RT76] Retevis RT76
This patch adds support for the Retevis RT76.
Related to #8959
diff -r c11f6ae9ccfd -r 35ce102f7e2d chirp/drivers/retevis_rt21.py
--- a/chirp/drivers/retevis_rt21.py Sat Apr 03 18:13:37 2021 -0400
+++ b/chirp/drivers/retevis_rt21.py Sat Apr 03 18:17:46 2021 -0400
@@ -197,6 +197,48 @@
} settings3;
"""
+MEM_FORMAT_RT76 = """
+#seekto 0x0000;
+struct {
+ lbcd rxfreq[4]; // RX Frequency 0-3
+ lbcd txfreq[4]; // TX Frequency 4-7
+ ul16 rx_tone; // PL/DPL Decode 8-9
+ ul16 tx_tone; // PL/DPL Encode A-B
+ u8 compander:1, // Compander C
+ unknown1:1, //
+ highpower:1, // Power Level
+ wide:1, // Bandwidth
+ unknown2:4; //
+ u8 reserved[3]; // Reserved D-F
+} memory[30];
+
+#seekto 0x002D;
+struct {
+ u8 unknown_1:1, // 002D
+ chnumberd:1, // Channel Number Disable
+ gain:1, // MIC Gain ---
+ savem:1, // Battery Save Mode ---
+ save:1, // Battery Save ---
+ beep:1, // Beep ---
+ voice:2; // Voice Prompts ---
+ u8 squelch; // Squelch 002E ---
+ u8 tot; // Time-out Timer 002F ---
+ u8 channel_4[13]; // 0030-003C
+ u8 unused:7, // 003D
+ vox:1; // Vox ---
+ u8 voxl; // Vox Level 003E ---
+ u8 voxd; // Vox Delay 003F ---
+ u8 channel_5[13]; // 0040-004C
+ u8 unknown_4; // 004D
+ u8 unknown_5[2]; // 004E-004F
+ u8 channel_6[13]; // 0050-005C
+ u8 chnumber; // Channel Number 005D ---
+ u8 unknown_7[2]; // 005E-005F
+ u8 channel_7[13]; // 0060-006C
+ u8 warn; // 006D ---
+} settings;
+"""
+
CMD_ACK = "\x06"
ALARM_LIST = ["Local Alarm", "Remote Alarm"]
@@ -211,6 +253,7 @@
TOTALERT_LIST = ["Off"] + ["%s seconds" % x for x in range(1, 11)]
VOICE_LIST = ["Off", "Chinese", "English"]
VOICE_LIST2 = ["Off", "English"]
+VOICE_LIST3 = VOICE_LIST2 + ["Chinese"]
VOX_LIST = ["OFF"] + ["%s" % x for x in range(1, 17)]
VOXD_LIST = ["0.5", "1.0", "1.5", "2.0", "2.5", "3.0"]
VOXL_LIST = ["OFF"] + ["%s" % x for x in range(1, 9)]
@@ -232,6 +275,7 @@
"totalert": TOTALERT_LIST,
"voice": VOICE_LIST,
"voice": VOICE_LIST2,
+ "voice": VOICE_LIST3,
"vox": VOX_LIST,
"voxd": VOXD_LIST,
"voxl": VOXL_LIST,
@@ -253,7 +297,7 @@
exito = False
for i in range(0, 5):
serial.write(radio._magic)
- if radio.MODEL == "RB26":
+ if radio.MODEL == "RB26" or radio.MODEL == "RT76":
serial.read(1)
ack = serial.read(1)
@@ -387,7 +431,7 @@
status.cur = addr + radio.BLOCK_SIZE
radio.status_fn(status)
- if radio.MODEL == "RB26":
+ if radio.MODEL == "RB26" or radio.MODEL == "RT76":
block = _rb26_read_block(radio, addr, radio.BLOCK_SIZE)
else:
block = _read_block(radio, addr, radio.BLOCK_SIZE)
@@ -633,7 +677,7 @@
LOG.debug("Initializing empty memory")
if self.MODEL == "RB17A":
_mem.set_raw("\x00" * 13 + "\x04\xFF\xFF")
- if self.MODEL == "RB26":
+ if self.MODEL == "RB26" or self.MODEL == "RT76":
_mem.set_raw("\x00" * 13 + _rsvd)
else:
_mem.set_raw("\x00" * 13 + "\x30\x8F\xF8")
@@ -651,8 +695,9 @@
mem.power = self.POWER_LEVELS[_mem.highpower]
- mem.skip = "" if (_skp & bitpos) else "S"
- LOG.debug("mem.skip %s" % mem.skip)
+ if self.MODEL != "RT76":
+ mem.skip = "" if (_skp & bitpos) else "S"
+ LOG.debug("mem.skip %s" % mem.skip)
mem.extra = RadioSettingGroup("Extra", "extra")
@@ -671,10 +716,11 @@
rset = RadioSetting("cdcss", "Cdcss Mode", rs)
mem.extra.append(rset)
- if self.MODEL == "RB26":
- rs = RadioSettingValueBoolean(_mem.bcl)
- rset = RadioSetting("bcl", "Busy Channel Lockout", rs)
- mem.extra.append(rset)
+ if self.MODEL == "RB26" or self.MODEL == "RT76":
+ if self.MODEL == "RB26":
+ rs = RadioSettingValueBoolean(_mem.bcl)
+ rset = RadioSetting("bcl", "Busy Channel Lockout", rs)
+ mem.extra.append(rset)
rs = RadioSettingValueBoolean(_mem.compander)
rset = RadioSetting("compander", "Compander", rs)
@@ -749,7 +795,7 @@
if mem.empty:
if self.MODEL == "RB17A":
_mem.set_raw("\xFF" * 12 + "\x00\x00\xFF\xFF")
- elif self.MODEL == "RB26":
+ elif self.MODEL == "RB26" or self.MODEL == "RT76":
_mem.set_raw("\xFF" * 13 + _rsvd)
else:
_mem.set_raw("\xFF" * (_mem.size() / 8))
@@ -773,7 +819,7 @@
if self.MODEL == "RB17A":
_mem.set_raw("\x00" * 13 + "\x00\xFF\xFF")
- elif self.MODEL == "RB26":
+ elif self.MODEL == "RB26" or self.MODEL == "RT76":
_mem.set_raw("\x00" * 13 + _rsvd)
else:
_mem.set_raw("\x00" * 13 + "\x30\x8F\xF8")
@@ -798,11 +844,12 @@
_mem.highpower = mem.power == self.POWER_LEVELS[1]
- if mem.skip != "S":
- _skp |= bitpos
- else:
- _skp &= ~bitpos
- LOG.debug("_skp %s" % _skp)
+ if self.MODEL != "RT76":
+ if mem.skip != "S":
+ _skp |= bitpos
+ else:
+ _skp &= ~bitpos
+ LOG.debug("_skp %s" % _skp)
for setting in mem.extra:
if setting.get_name() == "scramble_type":
@@ -894,9 +941,10 @@
rset.set_apply_callback(apply_topkey_listvalue, _keys.topkey)
basic.append(rset)
- if self.MODEL == "RB26":
- _settings2 = self._memobj.settings2
- _settings3 = self._memobj.settings3
+ if self.MODEL == "RB26" or self.MODEL == "RT76":
+ if self.MODEL == "RB26":
+ _settings2 = self._memobj.settings2
+ _settings3 = self._memobj.settings3
rs = RadioSettingValueInteger(0, 9, _settings.squelch)
rset = RadioSetting("squelch", "Squelch Level", rs)
@@ -907,14 +955,21 @@
rset = RadioSetting("tot", "Time-out timer", rs)
basic.append(rset)
- rs = RadioSettingValueList(VOICE_LIST2,
- VOICE_LIST2[_settings.voice])
- rset = RadioSetting("voice", "Voice Annumciation", rs)
- basic.append(rset)
+ if self.MODEL == "RT76":
+ rs = RadioSettingValueList(VOICE_LIST3,
+ VOICE_LIST3[_settings.voice])
+ rset = RadioSetting("voice", "Voice Annumciation", rs)
+ basic.append(rset)
- rs = RadioSettingValueBoolean(not _settings.chnumberd)
- rset = RadioSetting("chnumberd", "Channel Number Enable", rs)
- basic.append(rset)
+ if self.MODEL == "RB26":
+ rs = RadioSettingValueList(VOICE_LIST2,
+ VOICE_LIST2[_settings.voice])
+ rset = RadioSetting("voice", "Voice Annumciation", rs)
+ basic.append(rset)
+
+ rs = RadioSettingValueBoolean(not _settings.chnumberd)
+ rset = RadioSetting("chnumberd", "Channel Number Enable", rs)
+ basic.append(rset)
rs = RadioSettingValueBoolean(_settings.save)
rset = RadioSetting("save", "Battery Save", rs)
@@ -924,9 +979,10 @@
rset = RadioSetting("beep", "Beep", rs)
basic.append(rset)
- rs = RadioSettingValueBoolean(not _settings.tail)
- rset = RadioSetting("tail", "QT/DQT Tail", rs)
- basic.append(rset)
+ if self.MODEL == "RB26":
+ rs = RadioSettingValueBoolean(not _settings.tail)
+ rset = RadioSetting("tail", "QT/DQT Tail", rs)
+ basic.append(rset)
rs = RadioSettingValueList(SAVE_LIST, SAVE_LIST[_settings.savem])
rset = RadioSetting("savem", "Battery Save Mode", rs)
@@ -940,29 +996,53 @@
rset = RadioSetting("warn", "Warn Mode", rs)
basic.append(rset)
- rs = RadioSettingValueBoolean(_settings3.vox)
- rset = RadioSetting("settings3.vox", "Vox Function", rs)
- basic.append(rset)
+ if self.MODEL == "RB26":
+ rs = RadioSettingValueBoolean(_settings3.vox)
+ rset = RadioSetting("settings3.vox", "Vox Function", rs)
+ basic.append(rset)
+
+ rs = RadioSettingValueList(VOXL_LIST,
+ VOXL_LIST[_settings3.voxl])
+ rset = RadioSetting("settings3.voxl", "Vox Level", rs)
+ basic.append(rset)
- rs = RadioSettingValueList(VOXL_LIST, VOXL_LIST[_settings3.voxl])
- rset = RadioSetting("settings3.voxl", "Vox Level", rs)
- basic.append(rset)
+ rs = RadioSettingValueList(VOXD_LIST,
+ VOXD_LIST[_settings3.voxd])
+ rset = RadioSetting("settings3.voxd", "Vox Delay", rs)
+ basic.append(rset)
- rs = RadioSettingValueList(VOXD_LIST, VOXD_LIST[_settings3.voxd])
- rset = RadioSetting("settings3.voxd", "Vox Delay", rs)
- basic.append(rset)
+ rs = RadioSettingValueList(PFKEY_LIST,
+ PFKEY_LIST[_settings.pf1])
+ rset = RadioSetting("pf1", "PF1 Key Set", rs)
+ basic.append(rset)
- rs = RadioSettingValueList(PFKEY_LIST, PFKEY_LIST[_settings.pf1])
- rset = RadioSetting("pf1", "PF1 Key Set", rs)
- basic.append(rset)
+ rs = RadioSettingValueList(PFKEY_LIST,
+ PFKEY_LIST[_settings.pf2])
+ rset = RadioSetting("pf2", "PF2 Key Set", rs)
+ basic.append(rset)
+
+ rs = RadioSettingValueInteger(1, 30, _settings2.chnumber + 1)
+ rset = RadioSetting("settings2.chnumber", "Channel Number", rs)
+ basic.append(rset)
+
+ if self.MODEL == "RT76":
+ rs = RadioSettingValueBoolean(_settings.vox)
+ rset = RadioSetting("vox", "Vox Function", rs)
+ basic.append(rset)
- rs = RadioSettingValueList(PFKEY_LIST, PFKEY_LIST[_settings.pf2])
- rset = RadioSetting("pf2", "PF2 Key Set", rs)
- basic.append(rset)
+ rs = RadioSettingValueList(VOXL_LIST,
+ VOXL_LIST[_settings.voxl])
+ rset = RadioSetting("voxl", "Vox Level", rs)
+ basic.append(rset)
- rs = RadioSettingValueInteger(1, 30, _settings2.chnumber + 1)
- rset = RadioSetting("settings2.chnumber", "Channel Number", rs)
- basic.append(rset)
+ rs = RadioSettingValueList(VOXD_LIST,
+ VOXD_LIST[_settings.voxd])
+ rset = RadioSetting("voxd", "Vox Delay", rs)
+ basic.append(rset)
+
+ rs = RadioSettingValueInteger(1, 30, _settings.chnumber + 1)
+ rset = RadioSetting("chnumber", "Channel Number", rs)
+ basic.append(rset)
return top
@@ -1059,6 +1139,34 @@
def process_mmap(self):
self._memobj = bitwise.parse(MEM_FORMAT_RB26, self._mmap)
+
+ at directory.register
+class RT76Radio(RT21Radio):
+ """RETEVIS RT76"""
+ VENDOR = "Retevis"
+ MODEL = "RT76"
+ BAUD_RATE = 9600
+ BLOCK_SIZE = 0x20
+ BLOCK_SIZE_UP = 0x10
+
+ POWER_LEVELS = [chirp_common.PowerLevel("Low", watts=0.50),
+ chirp_common.PowerLevel("High", watts=5.00)]
+
+ _magic = "PHOGR\x14\xD4"
+ _fingerprint = "P32073" + "\x02\xFF"
+ _upper = 30
+ _skipflags = False
+ _reserved = True
+ _gmrs = True
+
+ _ranges = [
+ (0x0000, 0x01E0),
+ ]
+ _memsize = 0x01E0
+
+ def process_mmap(self):
+ self._memobj = bitwise.parse(MEM_FORMAT_RT76, self._mmap)
+
@classmethod
def match_model(cls, filedata, filename):
if cls.MODEL == "RT21":
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Retevis_RT76.img
Type: application/octet-stream
Size: 645 bytes
Desc: not available
Url : http://intrepid.danplanet.com/pipermail/chirp_devel/attachments/20210403/7959ff03/attachment-0001.img
More information about the chirp_devel
mailing list