diff --git a/chirp/drivers/baofeng_common.py b/chirp/drivers/baofeng_common.py index d990c4757..445364c10 100644 --- a/chirp/drivers/baofeng_common.py +++ b/chirp/drivers/baofeng_common.py @@ -51,6 +51,8 @@ def _rawrecv(radio, amount): raise errors.RadioError(msg) if len(data) != amount: + LOG.debug('Wanted %i, got %i: %s', + amount, len(data), util.hexprint(data)) msg = "Error reading data from radio: not the amount of data we want." raise errors.RadioError(msg) diff --git a/chirp/drivers/baofeng_uv17.py b/chirp/drivers/baofeng_uv17.py index 150afbcc3..09b7da0ec 100644 --- a/chirp/drivers/baofeng_uv17.py +++ b/chirp/drivers/baofeng_uv17.py @@ -44,7 +44,10 @@ def _get_memory_size(radio): def _get_memory_map(radio): # Get memory map memory_map = [] - mem_size = _get_memory_size(radio) + if radio._magic_memsize: + mem_size = _get_memory_size(radio) + else: + mem_size = radio._radio_memsize if mem_size != radio._radio_memsize: raise errors.RadioError("Incorrect radio model or model not supported " "(memory size doesn't match)") @@ -60,7 +63,9 @@ def _get_memory_map(radio): def _download(radio): """Get the memory map""" - baofeng_uv17Pro._do_ident(radio) + if not radio._DETECTED_BY: + # The GA510v2 (at least) is detected, and thus has already done ident + baofeng_uv17Pro._do_ident(radio) data = b"" memory_map = _get_memory_map(radio) @@ -73,6 +78,8 @@ def _download(radio): for block_number in radio.BLOCK_ORDER: if block_number not in memory_map: # Memory block not found. + LOG.error('Block %i (0x%x) not in memory map: %s', + block_number, block_number, memory_map) raise errors.RadioError('Radio memory is corrupted. ' + 'Fix this by uploading a backup image ' + 'to the radio.') @@ -189,8 +196,7 @@ class UV17(baofeng_uv17Pro.UV17Pro): LIST_MODE = ["Name", "Frequency"] CHANNELS = 999 - MEM_FORMAT = """ - #seekto 0x0030; + MEM_DEFS = """ struct channel { lbcd rxfreq[4]; lbcd txfreq[4]; @@ -209,28 +215,10 @@ class UV17(baofeng_uv17Pro.UV17Pro): scan:1; u8 unknown4; }; - - struct { - struct channel mem[252]; - } mem1; - - #seek 0x10; - struct { - struct channel mem[255]; - } mem2; - - #seek 0x10; - struct { - struct channel mem[255]; - } mem3; - - #seek 0x10; - struct { - struct channel mem[237]; - } mem4; - - #seekto 0x7000; - struct { + struct channelname { + char name[11]; + }; + struct settings { u8 powerondistype; u8 unknown0[15]; char boottext1[10]; @@ -261,7 +249,39 @@ class UV17(baofeng_uv17Pro.UV17Pro): u8 unknown9:6, chbdistype:1, chadistype:1; - } settings; + }; + struct ani { + u8 unknown[5]; + u8 code[5]; + }; + struct pttid { + u8 code[5]; + }; + """ + + MEM_LAYOUT = """ + #seekto 0x0030; + struct { + struct channel mem[252]; + } mem1; + + #seek 0x10; + struct { + struct channel mem[255]; + } mem2; + + #seek 0x10; + struct { + struct channel mem[255]; + } mem3; + + #seek 0x10; + struct { + struct channel mem[237]; + } mem4; + + #seekto 0x7000; + struct settings settings; struct vfo { lbcd rxfreq[4]; @@ -289,10 +309,6 @@ class UV17(baofeng_uv17Pro.UV17Pro): } vfo; #seekto 0x4000; - struct channelname { - char name[11]; - }; - struct channelname names1[372]; #seek 0x4; struct channelname names2[372]; @@ -300,16 +316,11 @@ class UV17(baofeng_uv17Pro.UV17Pro): struct channelname names3[255]; #seekto 0x8000; - struct { - u8 code[5]; - } pttid[15]; - - struct { - u8 unknown[5]; - u8 code[5]; - } ani; + struct pttid pttid[15]; + struct ani ani; """ + MEM_FORMAT = MEM_DEFS + MEM_LAYOUT def _make_frame(self, cmd, addr, length, data=""): """Pack the info in the header format""" @@ -395,7 +406,7 @@ def decode_tone(self, val): return mode, xval, pol - def get_raw_memory(self, number): + def _get_raw_memory(self, number): # The flash memory contains page_numbers # This is probably to do wear leveling on the memory # These numbers are needed, but make the channel memory @@ -413,6 +424,9 @@ def get_raw_memory(self, number): _mem = self._memobj.mem1.mem[number] return _mem + def get_raw_memory(self, number): + return repr(self._get_raw_memory(number)) + def get_channel_name(self, number): number = number - 1 if number >= 744: @@ -425,7 +439,7 @@ def get_channel_name(self, number): return _name def get_memory(self, number): - _mem = self.get_raw_memory(number) + _mem = self._get_raw_memory(number) _nam = self.get_channel_name(number) mem = chirp_common.Memory() @@ -456,7 +470,7 @@ def encode_tone(self, memtone, mode, tone, pol): memtone.set_value(memtone + 0x4000) def set_memory(self, mem): - _mem = self.get_raw_memory(mem.number) + _mem = self._get_raw_memory(mem.number) _nam = self.get_channel_name(mem.number) if mem.empty: diff --git a/chirp/drivers/baofeng_uv17Pro.py b/chirp/drivers/baofeng_uv17Pro.py index ae2c2ca0b..99e7af1ed 100644 --- a/chirp/drivers/baofeng_uv17Pro.py +++ b/chirp/drivers/baofeng_uv17Pro.py @@ -1191,11 +1191,14 @@ def get_memory_common(self, _mem, name, mem): mem.name = str(name).replace('\xFF', ' ').replace('\x00', ' ').rstrip() - def get_raw_memory(self, number): + def _get_raw_memory(self, number): return self._memobj.memory[number - 1] + def get_raw_memory(self, number): + return repr(self._get_raw_memory(number)) + def get_memory(self, number): - _mem = self.get_raw_memory(number) + _mem = self._get_raw_memory(number) mem = chirp_common.Memory() mem.number = number @@ -1205,7 +1208,7 @@ def get_memory(self, number): return mem def unsplit_txfreq(self, mem): - _mem = self.get_raw_memory(mem.number) + _mem = self._get_raw_memory(mem.number) if mem.duplex == "off": for i in range(0, 4): _mem.txfreq[i].set_raw(b"\xFF") @@ -1251,7 +1254,7 @@ def set_memory_common(self, mem, _mem): _mem.scode = self._scode_offset def set_memory(self, mem): - _mem = self.get_raw_memory(mem.number) + _mem = self._get_raw_memory(mem.number) _mem.set_raw(b"\x00"*16 + b"\xff" * 16) diff --git a/chirp/drivers/ga510.py b/chirp/drivers/ga510.py index dba6609e9..13d426e8f 100644 --- a/chirp/drivers/ga510.py +++ b/chirp/drivers/ga510.py @@ -1,4 +1,4 @@ -# Copyright 2011 Dan Smith +# Copyright 2024 Dan Smith # Portions copyright 2023 Dave Liske # Portions copyright 2020 by Jiauxn Yang # @@ -21,6 +21,8 @@ from chirp import bitwise from chirp import chirp_common from chirp import directory +from chirp.drivers import baofeng_uv17 +from chirp.drivers import baofeng_uv17Pro from chirp import errors from chirp import memmap from chirp.settings import RadioSetting, RadioSettingGroup, RadioSettings @@ -60,7 +62,7 @@ def start_program(radio): def do_download(radio): - ident = start_program(radio) + # No start_program() here because it was done in detect_from_serial() s = chirp_common.Status() s.msg = 'Downloading' @@ -355,6 +357,24 @@ class RadioddityGA510Radio(chirp_common.CloneModeRadio): _gmrs = False + @classmethod + def detect_from_serial(cls, pipe): + for rcls in reversed(cls.detected_models()): + pipe.baudrate = rcls.BAUD_RATE + radio = rcls(pipe) + try: + if isinstance(radio, baofeng_uv17Pro.UV17Pro): + ident = baofeng_uv17Pro._do_ident(radio) + else: + ident = start_program(radio) + except errors.RadioError: + LOG.debug('No response from radio with %s', rcls) + pipe.read(256) + continue + if ident: + return rcls + raise errors.RadioError('No response from radio') + def sync_in(self): try: data = do_download(self) @@ -1074,3 +1094,69 @@ def _set_mem(self, num): def _set_nam(self, number): return self._memobj.names[number - 1] + + +@directory.register +@directory.detected_by(RadioddityGA510Radio) +class RadioddityGA510v2(baofeng_uv17.UV17): + """Baofeng UV-17""" + VENDOR = "Radioddity" + MODEL = "GA-510" + VARIANT = "V2" + + MODES = ["FM", "NFM"] + BLOCK_ORDER = [2, 4, 6, 16, 24] + MEM_TOTAL = 0x6000 + WRITE_MEM_TOTAL = 0x6000 + BLOCK_SIZE = 0x40 + BAUD_RATE = 57600 + + _magic = b"PSEARCH" + _magic_response_length = 8 + _magics = [(b"PASSSTA", 3), (b"SYSINFO", 1), + (b"\x56\x00\x00\x0A\x0D", 13), (b"\x06", 1), + (b"\x56\x00\x10\x0A\x0D", 13), (b"\x06", 1), + (b"\x56\x00\x20\x0A\x0D", 13), (b"\x06", 1), + (b"\x56\x00\x00\x00\x0A", 11), (b"\x06", 1), + (b"\xFF\xFF\xFF\xFF\x0C\x44\x4d\x52\x31\x37\x30\x32", 1), + (b"\02", 8), (b"\x06", 1)] + _magic_memsize = [] + _radio_memsize = 0x10000 + _magics2 = [] + _fingerprint = b"\x06DMR1702" + _scode_offset = 1 + + _tri_band = False + POWER_LEVELS = [chirp_common.PowerLevel("Low", watts=1.00), + chirp_common.PowerLevel("Medium", watts=5.00), + chirp_common.PowerLevel("High", watts=10.00)] + + LENGTH_NAME = 11 + SCODE_LIST = ["%s" % x for x in range(1, 16)] + SQUELCH_LIST = ["Off"] + list("123456789") + LIST_POWERON_DISPLAY_TYPE = ["Full", "Message", "Voltage"] + LIST_TIMEOUT = ["Off"] + ["%s sec" % x for x in range(15, 615, 15)] + LIST_VOICE = ["Chinese", "English"] + LIST_BACKLIGHT_TIMER = ["Always On"] + ["%s sec" % x for x in range(1, 11)] + LIST_MODE = ["Name", "Frequency"] + CHANNELS = 128 + + MEM_LAYOUT = """ + #seekto 0x1000; + struct settings settings; + + #seekto 0x2000; + struct pttid pttid[15]; + struct ani ani; + + #seekto 0x3040; + struct { + struct channel mem[128]; + } mem1; + + #seekto 0x400B; + struct channelname names1[128]; + """ + MEM_FORMAT = baofeng_uv17.UV17.MEM_DEFS + MEM_LAYOUT + + _has_workmode_support = False diff --git a/tests/Python3_Driver_Testing.md b/tests/Python3_Driver_Testing.md index b8d22291f..5a9a1d77b 100644 --- a/tests/Python3_Driver_Testing.md +++ b/tests/Python3_Driver_Testing.md @@ -272,6 +272,7 @@ | Radioddity_DB25-G | [@KC9HI](https://github.com/KC9HI) | 11-Nov-2022 | Yes | 0.17% | | Radioddity_GA-2S | [@KC9HI](https://github.com/KC9HI) | 4-Dec-2022 | Yes | 0.19% | | Radioddity_GA-510 | [@kk7ds](https://github.com/kk7ds) | 21-Oct-2022 | Yes | 0.42% | +| Radioddity_GA-510_V2 | | | Yes | | | Radioddity_GS-5B | [@lunapiercook](https://github.com/lunapiercook) | 5-Mar-2023 | Yes | | | Radioddity_R2 | [@KC9HI](https://github.com/KC9HI) | 17-Dec-2022 | Yes | 0.04% | | Radioddity_UV-5G | [@KC9HI](https://github.com/KC9HI) | 18-Nov-2022 | Yes | 0.47% | @@ -466,11 +467,11 @@ | Zastone_ZT-X6 | [Implied by Retevis_RT22](#user-content-Retevis_RT22) | 9-Dec-2022 | Yes | 0.11% | ## Stats -**Drivers:** 463 +**Drivers:** 464 -**Tested:** 87% (406/57) (93% of usage stats) +**Tested:** 87% (406/58) (93% of usage stats) -**Byte clean:** 91% (424/39) +**Byte clean:** 91% (425/39) ## Meaning of this testing diff --git a/tests/images/Radioddity_GA-510_V2.img b/tests/images/Radioddity_GA-510_V2.img new file mode 100644 index 000000000..7695033d1 Binary files /dev/null and b/tests/images/Radioddity_GA-510_V2.img differ