Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package chirp for openSUSE:Factory checked in at 2026-05-23 23:26:48 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/chirp (Old) and /work/SRC/openSUSE:Factory/.chirp.new.2084 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "chirp" Sat May 23 23:26:48 2026 rev:71 rq:1354869 version:20260522 Changes: -------- --- /work/SRC/openSUSE:Factory/chirp/chirp.changes 2026-05-15 23:58:48.806207257 +0200 +++ /work/SRC/openSUSE:Factory/.chirp.new.2084/chirp.changes 2026-05-23 23:28:39.379844803 +0200 @@ -1,0 +2,9 @@ +Sat May 23 17:13:36 UTC 2026 - Andreas Stieger <[email protected]> + +- Update to version 20260522: + * tdh8: Fix loading out-of-range group code values + * baofeng_uv17Pro: Fix uploading over BLE for supported models + * Add BLE serial detection + * mp31: Add support for Baofeng MP31 + +------------------------------------------------------------------- Old: ---- chirp-20260515.obscpio New: ---- chirp-20260522.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ chirp.spec ++++++ --- /var/tmp/diff_new_pack.6cFdra/_old 2026-05-23 23:28:40.227879423 +0200 +++ /var/tmp/diff_new_pack.6cFdra/_new 2026-05-23 23:28:40.231879586 +0200 @@ -20,7 +20,7 @@ %define pythons python3 Name: chirp -Version: 20260515 +Version: 20260522 Release: 0 Summary: Tool for programming amateur radio sets License: GPL-3.0-only ++++++ _service ++++++ --- /var/tmp/diff_new_pack.6cFdra/_old 2026-05-23 23:28:40.259880729 +0200 +++ /var/tmp/diff_new_pack.6cFdra/_new 2026-05-23 23:28:40.263880892 +0200 @@ -4,8 +4,8 @@ <param name="scm">git</param> <param name="changesgenerate">enable</param> <param name="filename">chirp</param> - <param name="versionformat">20260515</param> - <param name="revision">cb0e19f55fbd17b9485fcb7696fb9cd4863ccf58</param> + <param name="versionformat">20260522</param> + <param name="revision">c04781671024a690082f4a979287f96404ce9ad2</param> </service> <service mode="manual" name="set_version"/> <service name="tar" mode="buildtime"/> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.6cFdra/_old 2026-05-23 23:28:40.283881709 +0200 +++ /var/tmp/diff_new_pack.6cFdra/_new 2026-05-23 23:28:40.287881872 +0200 @@ -1,7 +1,7 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/kk7ds/chirp.git</param> - <param name="changesrevision">cb0e19f55fbd17b9485fcb7696fb9cd4863ccf58</param> + <param name="changesrevision">c04781671024a690082f4a979287f96404ce9ad2</param> </service> </servicedata> (No newline at EOF) ++++++ chirp-20260515.obscpio -> chirp-20260522.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chirp-20260515/.gitignore new/chirp-20260522/.gitignore --- old/chirp-20260515/.gitignore 2026-05-12 02:16:08.000000000 +0200 +++ new/chirp-20260522/.gitignore 2026-05-21 04:59:22.000000000 +0200 @@ -40,3 +40,4 @@ result/ # for nvim editor .nvim.lua +.DS_Store diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chirp-20260515/chirp/drivers/baofeng_uv17Pro.py new/chirp-20260522/chirp/drivers/baofeng_uv17Pro.py --- old/chirp-20260515/chirp/drivers/baofeng_uv17Pro.py 2026-05-12 02:16:08.000000000 +0200 +++ new/chirp-20260522/chirp/drivers/baofeng_uv17Pro.py 2026-05-21 04:59:22.000000000 +0200 @@ -19,6 +19,7 @@ from chirp.drivers import baofeng_common as bfc from chirp import chirp_common, directory, memmap, bandplan_na from chirp import bitwise +from chirp import platform from chirp.settings import RadioSetting, \ RadioSettingValueBoolean, RadioSettingValueList, \ RadioSettingValueString, \ @@ -158,7 +159,7 @@ radio.BLOCK_SIZE): frame = radio._make_read_frame(addr, radio.BLOCK_SIZE) - radio.pipe.log('Sending request for %04x' % addr) + radio.pipe.log('Sending request for 0x%04x' % addr) bfc._rawsend(radio, frame) d = bfc._rawrecv(radio, radio.BLOCK_SIZE + 4) @@ -173,7 +174,6 @@ # UI Update status.cur = len(data) // radio.BLOCK_SIZE - status.msg = "Cloning from radio..." radio.status_fn(status) return data @@ -494,7 +494,7 @@ def _make_frame(self, cmd, addr, length, data=""): """Pack the info in the header format""" - frame = cmd + struct.pack(">i", addr)[2:] + struct.pack("b", length) + frame = cmd + struct.pack(">i", addr)[2:] + struct.pack("B", length) # add the data if set if len(data) != 0: frame += data @@ -2358,7 +2358,10 @@ MEM_TOTAL = 0x8240 + _is_on_ble = False + _has_support_for_banknames = False + _has_bt = True # allow BT setting _idents = [MSTRING_UV17PROGPS] _mem_size = MEM_TOTAL @@ -2385,6 +2388,81 @@ _uhf_rx2_range] MODES = UV17Pro.MODES + ['AM'] + BLE_UP_BLOCK_SIZE = 0x80 # uploading to radio over BLE uses 0x80 blocksize + + def sync_in(self): + self._is_on_ble = platform.get_platform().is_ble_serial(self.pipe) + LOG.debug('Detected BLE: %s' % self._is_on_ble) + return super().sync_in() + + def sync_out(self): + self._is_on_ble = platform.get_platform().is_ble_serial(self.pipe) + LOG.debug('Detected BLE: %s' % self._is_on_ble) + return super().sync_out() + + def _upload(radio): + """Upload to UV5R Mini (over BLE or USB/Serial)""" + # Put radio in program mode and identify it and + # determine if on BLE or USB/Serial connection + _do_ident(radio) + + if radio._is_on_ble: # BLE upload needs a diff blocksize + _blocksize = radio.BLE_UP_BLOCK_SIZE + else: + _blocksize = radio.BLOCK_SIZE + + data = b"" + + # UI progress + status = chirp_common.Status() + status.cur = 0 + status.max = radio.MEM_TOTAL // _blocksize + status.msg = "Cloning to radio on %s/Serial..." % \ + ('BLE' if radio._is_on_ble else 'USB') + radio.status_fn(status) + + data_addr = 0x00 + radio_mem = radio.get_mmap() + radio.pipe.log('Uploading to radio using block size of 0x%04x' + % _blocksize) + for i in range(len(radio.MEM_SIZES)): + MEM_SIZE = radio.MEM_SIZES[i] + MEM_START = radio.MEM_STARTS[i] + for addr in range(MEM_START, MEM_START + MEM_SIZE, + _blocksize): + # calc min byte count to keep from reading too many bytes + byte_count = min(_blocksize, (MEM_START + MEM_SIZE) - addr) + data = radio_mem[data_addr:data_addr + byte_count] + + if byte_count < _blocksize: # does block need padding? + radio.pipe.log('Padding partial block with \xff ' + 'by 0x%02x bytes' % + (_blocksize - len(data))) + # pad partial block with \xff + data += (b'\xff' * (_blocksize - len(data))) + + if radio._uses_encr: + data = _crypt(radio._encrsym, data) + + data_addr += byte_count # advance read pointer + + frame = radio._make_frame(b"W", addr, _blocksize, data) + radio.pipe.log('Sending address %04x' % addr) + bfc._rawsend(radio, frame) + + ack = bfc._rawrecv(radio, 1) + if ack != b"\x06": + msg = "Bad ack writing block %04x" % addr + raise errors.RadioError(msg) + + # UI Update + status.cur = data_addr // _blocksize + radio.status_fn(status) + + return data + + upload_function = _upload + _end_fmt = """ // #seekto 0x8220; struct { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chirp-20260515/chirp/drivers/h777.py new/chirp-20260522/chirp/drivers/h777.py --- old/chirp-20260515/chirp/drivers/h777.py 2026-05-12 02:16:08.000000000 +0200 +++ new/chirp-20260522/chirp/drivers/h777.py 2026-05-21 04:59:22.000000000 +0200 @@ -27,6 +27,22 @@ LOG = logging.getLogger(__name__) +MEM_FORMAT_SETTINGS = """ +#seekto 0x02B0; +struct { + u8 voiceprompt; + u8 voicelanguage; + u8 scan; + u8 vox; + u8 voxlevel; + u8 voxinhibitonrx; + u8 lowvolinhibittx; + u8 highvolinhibittx; + u8 alarm; + u8 fmradio; +} settings; +""" + MEM_FORMAT = """ #seekto 0x0010; struct { @@ -44,20 +60,7 @@ bcl:1; u8 unknown4[3]; } memory[16]; -#seekto 0x02B0; -struct { - u8 voiceprompt; - u8 voicelanguage; - u8 scan; - u8 vox; - u8 voxlevel; - u8 voxinhibitonrx; - u8 lowvolinhibittx; - u8 highvolinhibittx; - u8 alarm; - u8 fmradio; -} settings; -""" +""" + MEM_FORMAT_SETTINGS H777_SETTINGS2 = """ #seekto 0x03C0; @@ -656,6 +659,65 @@ return False +MP31_MEM_FORMAT = """ +#seekto 0x0000; +struct { + lbcd rxfreq[4]; + lbcd txfreq[4]; + lbcd rxtone[2]; + lbcd txtone[2]; + u8 unknown3:1, + unknown2:1, + unknown1:1, + skip:1, + highpower:1, + narrow:1, + beatshift:1, + bcl:1; + u8 unknown4[3]; +} memory[38]; +""" + +MP31_SETTINGS2 = """ +#seekto 0x026B; +struct { + u8 squelchlevel; + u8 batterysaver; + u8 voxdelay; + u8 timeouttimer; + u8 scanmode; + u8 beep; + u8 sidekey; + u8 rxemergency; +} settings2; +""" + + [email protected] +class MP31Radio(H777Radio): + """Baofeng MP31""" + VENDOR = "Baofeng" + MODEL = "MP31" + IDENT = [b"P3107\xf7\x00\x00"] + _ranges = [(0x0000, 0x0400)] + _memsize = 0x0400 + _has_sidekey = False + ALIASES = [] + + def process_mmap(self): + self._memobj = bitwise.parse( + MP31_MEM_FORMAT + MP31_SETTINGS2 + MEM_FORMAT_SETTINGS, self._mmap) + + def get_features(self): + rf = super().get_features() + rf.memory_bounds = (1, 38) + return rf + + @classmethod + def match_model(cls, filedata, filename): + return False + + class H777TestCase(unittest.TestCase): def setUp(self): @@ -703,6 +765,23 @@ self.driver._encode_tone(self.testdata.foo, '', 67.0, 'N') self.assertEqual(16665, int(self.testdata.foo)) + def test_mp31_38_channels(self): + radio = MP31Radio(None) + rf = radio.get_features() + self.assertEqual(rf.memory_bounds, (1, 38)) + + def test_mp31_memsize(self): + radio = MP31Radio(None) + self.assertEqual(radio._memsize, 0x0400) + + def test_mp31_ranges(self): + radio = MP31Radio(None) + self.assertEqual(radio._ranges, [(0x0000, 0x0400)]) + + def test_mp31_ident(self): + radio = MP31Radio(None) + self.assertIn(b"P3107\xf7\x00\x00", radio.IDENT) + @directory.register class ROGA2SRadio(H777Radio): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chirp-20260515/chirp/drivers/tdh8.py new/chirp-20260522/chirp/drivers/tdh8.py --- old/chirp-20260515/chirp/drivers/tdh8.py 2026-05-12 02:16:08.000000000 +0200 +++ new/chirp-20260522/chirp/drivers/tdh8.py 2026-05-21 04:59:22.000000000 +0200 @@ -1965,11 +1965,15 @@ gcode_val = "" else: gcode_val = gcode_val[1] + try: + cur = GROUPCODE.index(gcode_val) + except ValueError: + cur = len(GROUPCODE) rs = RadioSetting( "gcode", "Group Code", RadioSettingValueList( GROUPCODE, - current_index=GROUPCODE.index(gcode_val))) + current_index=cur)) dtmf.append(rs) icode_list = self._memobj.icode.idcode @@ -2156,8 +2160,8 @@ def get_settings(self): try: return self._get_settings() - except Exception: - raise InvalidValueError("Setting Failed!") + except Exception as e: + raise InvalidValueError("Setting Failed!") from e def set_settings(self, settings): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chirp-20260515/chirp/platform.py new/chirp-20260522/chirp/platform.py --- old/chirp-20260515/chirp/platform.py 2026-05-12 02:16:08.000000000 +0200 +++ new/chirp-20260522/chirp/platform.py 2026-05-21 04:59:22.000000000 +0200 @@ -182,6 +182,9 @@ return ver + def is_ble_serial(self, serial): + return serial.port.startswith('/tmp/ttyBLE') + class Win32Platform(Platform): """A platform module suitable for Windows systems""" @@ -230,6 +233,48 @@ return vers.get(pform, "Win32 (Unknown %i.%i:%i)" % (pform, sub, build)) + def is_ble_serial(self, serial): + import winreg + + max_ports = 255 + key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, + r'HARDWARE\DEVICEMAP\SERIALCOMM') + devices = {} + for i in range(max_ports): + try: + # device is something like \Device\com0com24 + # name is something like COM12 + device, name, _ = winreg.EnumValue(key, i) + devices[name] = device + except EnvironmentError: + break + + LOG.debug('All device/name pairs: %s' % devices) + + try: + # ble-serial names its device BLE, so find it + ble_device = devices.get('BLE') + except KeyError: + LOG.debug('No BLE device found') + sys.exit(1) + + # The pair device appears to always be \Device\com0com14 if + # the BLE device is \Device\com0com24 + pair_device = list(ble_device) + # Change 2 to 1 to get the first device of the pair + pair_device[-2] = '1' + pair_device = ''.join(pair_device) + LOG.debug('Found BLE device %s, guessing pair is %s' % ( + device, pair_device)) + try: + pair_name = dict(((v, k) for k, v in devices.items()))[pair_device] + except KeyError: + LOG.debug('Pair device not found!') + else: + LOG.info('BLE pair device is %s' % pair_name) + + return serial.port == pair_name + def _get_platform(basepath): if os.name == "nt": diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chirp-20260515/chirp/share/model_alias_map.yaml new/chirp-20260522/chirp/share/model_alias_map.yaml --- old/chirp-20260515/chirp/share/model_alias_map.yaml 2026-05-12 02:16:08.000000000 +0200 +++ new/chirp-20260522/chirp/share/model_alias_map.yaml 2026-05-21 04:59:22.000000000 +0200 @@ -376,3 +376,6 @@ Powerful: - alt: Quansheng UV-K5 model: UV-S5 +Pxton: +- alt: Baofeng MP31 + model: 999S Binary files old/chirp-20260515/tests/images/Baofeng_MP31.img and new/chirp-20260522/tests/images/Baofeng_MP31.img differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chirp-20260515/tests/test_clone.py new/chirp-20260522/tests/test_clone.py --- old/chirp-20260515/tests/test_clone.py 2026-05-12 02:16:08.000000000 +0200 +++ new/chirp-20260522/tests/test_clone.py 2026-05-21 04:59:22.000000000 +0200 @@ -16,6 +16,10 @@ class SerialNone(serialtrace.SerialTrace): + def __init__(self, *a, **k): + super().__init__(*a, **k) + self.port = '/dev/ttyUSB0' + def flush(self): pass ++++++ chirp.obsinfo ++++++ --- /var/tmp/diff_new_pack.6cFdra/_old 2026-05-23 23:28:41.535932822 +0200 +++ /var/tmp/diff_new_pack.6cFdra/_new 2026-05-23 23:28:41.535932822 +0200 @@ -1,5 +1,5 @@ name: chirp -version: 20260515 -mtime: 1778544968 -commit: cb0e19f55fbd17b9485fcb7696fb9cd4863ccf58 +version: 20260522 +mtime: 1779332362 +commit: c04781671024a690082f4a979287f96404ce9ad2
