[chirp_devel] New TH-UV8000 Driver

Dan Smith
Wed Jul 3 07:22:30 PDT 2019


(Jim, question for you below)

> diff -r 3f9d47c26743 -r 251bf9ab9b14 chirp/drivers/th_uv8000.py
> --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> +++ b/chirp/drivers/th_uv8000.py	Sun Jun 30 05:35:16 2019 -0700
> @@ -0,0 +1,1568 @@
> +# Copyright 2019: Rick DeWitt (RJD), <aa0rd at yahoo.com>
> +# Version 1.0 for TYT-UV8000D/

Remove trailing slash here?

> +# Thanks to Damon Schaefer (K9CQB)and the Loudoun County, VA ARES

Needs a space after the close paren and "and".

> +def _clean_buffer(radio):
> +    radio.pipe.timeout = 0.005
> +    junk = radio.pipe.read(256)
> +    radio.pipe.timeout = STIMEOUT
> +    if junk:
> +        Log.debug("Got %i bytes of junk before starting" % len(junk))

"Log" is undefined and you will crash with NameError here.

> +def _download(radio):
> +    """Get the memory map"""
> +
> +    # Put radio in program mode and identify it
> +    _do_ident(radio)
> +
> +    # UI progress
> +    status = chirp_common.Status()
> +    status.cur = 0
> +    status.max = MEM_SIZE / BLOCK_SIZE
> +    status.msg = "Cloning from radio..."
> +    radio.status_fn(status)
> +
> +    data = ""
> +    for addr in range(0, MEM_SIZE, BLOCK_SIZE):
> +        frame = _make_frame("R", addr, BLOCK_SIZE)
> +        # DEBUG
> +        LOG.info("Request sent:")
> +        LOG.debug("Frame=" + util.hexprint(frame))
> +
> +        # Sending the read request
> +        _rawsend(radio, frame)
> +        dx = _rawrecv(radio, 4)
> +
> +        # Now we read data
> +        d = _recv(radio, addr, BLOCK_SIZE)
> +        # LOG.warning("Data= " + util.hexprint(d))
> +
> +        # Aggregate the data
> +        data += d
> +
> +        # UI Update
> +        status.cur = addr / BLOCK_SIZE
> +        status.msg = "Cloning from radio..."
> +        radio.status_fn(status)
> +
> +    _exit_program_mode(radio)
> +    # Append the model number to the downloaded memory
> +    data += radio.MODEL.ljust(9)

Why are you doing this? Modern chirp will keep track of which model an image was created from, making it unnecessary to do this sort of thing for file identification...

> +def force_odd(fmfrq):
> +    """Force FM Broadcast Frequency to have odd KHz """
> +    oddfrq = int(fmfrq / 100000)    # remove 10Khz and lower
> +    if (oddfrq % 2) == 0:    # increment to odd
> +        oddfrq += 1
> +    return (oddfrq * 100000)

Can you explain this a little more? This doesn't seem to make sense to me and more comments about *why* you're doing it would be good.

> +def model_match(cls, data):
> +    """Match the opened/downloaded image to the correct version"""
> +    val = MEM_SIZE + len(cls.MODEL)
> +    if len(data) == val:
> +        rid = data[MEM_SIZE:val]
> +        return rid.startswith(cls.MODEL)

As above, I think this is probably unnecessary now.

> + at directory.register
> +class tyt_uv8000d(chirp_common.CloneModeRadio):

This is not a conventional Python class name. Please capitalize it and make it consistent with the rest of the code.

> +        rp.info = \
> +            ('Click on the "Special Channels" tab of the layout '
> +             'screen to see/set the upper and lower frequency-mode values, '
> +             'as well as the 25 FM broadcast radio station channels.\n\n')

If you're going to do this, please at least make it correct. It's not a "tab" it's a button (actually a toggle-button which shows a little differently), but it's very distinct from the tabs on the top and left. Also, nothing else in chirp mentions the "layout screen" and if you said this to me with no context, I wouldn't know what you meant. I would suggest "memory editor" or "memories" to be consistent with the left-side tab under which the button actually exists.

> +
> +        rp.pre_download = _(dedent("""\
> +            Follow these instructions to download your config:

Please choose something other than "your config" here. Nothing else in chirp calls the contents of a radio's memory its "config".

> +
> +            1 - Turn off your radio
> +            2 - Connect your interface cable
> +            3 - Turn on your radio, volume @ 50%
> +            4 - Radio > Download from radio
> +            """))
> +        rp.pre_upload = _(dedent("""\
> +            Follow this instructions to upload your config:

s/this/these/

> +    def _get_fm_memory(self, mem, _mem):
> +        mem.name = "----"
> +        rx = self._memobj.fm_stations[mem.number + 2].rxfreq
> +        if rx == 0xFFFF:
> +            mem.empty = True
> +            return mem
> +        else:
> +            mem.freq = (float(int(rx)) / 40) * 1000000
> +            mem.empty = False
> +
> +        mem.offset = 0.0
> +        mem.power = 0
> +        mem.duplex = "off"      # inhibits tx
> +        mem.mode = self.MODES[1]
> +        dtcs_pol = ["N", "N"]
> +        mem.ctone = 88.5
> +        mem.rtone = 88.5
> +        mem.tmode = ""
> +        mem.cross_mode = "Tone->Tone"
> +        mem.skip = ""
> +        mem.comment = ""
> +        return mem

I'm not really sure how I feel about this. I think the other radios that support editing the (broadcast) FM presets do so via RadioSetting values instead of calling them channels. Doing this makes editing them a little more like regular channels, but they include a bunch of other gorp (like tones) that will never apply, and they involve the usual band checking for the radio which defeats the ability of the memory editor UI being able to range check things properly.

Jim, any opinions here? For consistency I'd tend to lean towards just putting these into RadioSettings to be consistent with the other radios.

> +    def _set_memory(self, mem, _mem):
> +        """Convert UI column data (mem) into MEM_FORMAT memory (_mem)."""
> +        # At this point mem points to either normal, fm or Freq chans
> +        # These first attributes are common to all types
> +        if mem.empty:
> +            if mem.number > 0:
> +                _mem.rxfreq = 0xffffffff
> +                # Set 'empty' and 'skip' bits
> +                _do_map(mem.number, 1, self._memobj.chnmap.map)
> +                _do_map(mem.number, 1, self._memobj.skpchns.map)
> +            elif mem.number == -2:  # upper VFO Freq
> +                _mem.rxfreq = 14652000   # VHF National Calling freq
> +            elif mem.number == -1:  # lower VFO
> +                _mem.rxfreq = 44600000   # UHF National Calling freq
> +            else:       # FM stations, mem.number -3 to -27
> +                _mem.rxfreq = 0xffff
> +                _do_map(mem.number + 28, 1, self._memobj.fmmap.fmset)
> +            return
> +
> +        _mem.rxfreq = mem.freq / 10
> +
> +        if mem.number < -2:     # FM stations, only rxfreq
> +            _mem.rxfreq = (force_odd(mem.freq) * 40) / 1000000
> +            _do_map(mem.number + 28, 0, self._memobj.fmmap.fmset)
> +            return

It looks like this will let me set something like 146.52 into the FM preset memories, right? What happens if I do? What happens if I try to set 89.1MHz into one of the regular channels?

> +        if False:   # Skip these unknowns
> +            # FM Scan Range lo and Hi ??? MEM
> +            val = 87.5
> +            rx = RadioSettingValueFloat(87.5, 107.9, val, 0.1, 1)
> +            rset = RadioSetting("setstuf.fmsclo",
> +                                "Low FM Scan Bound (MHz)", rx)
> +            rset.set_apply_callback(myset_freq, _sets, "fmsclo", 40)
> +            fmb.append(rset)
> +
> +            val = 107.9     # ??? @@@ where
> +            rx = RadioSettingValueFloat(87.5, 107.9, val, 0.1, 1)
> +            rset = RadioSetting("setstuf.fmschi",
> +                                "High FM Scan Freq (MHz)", rx)
> +            rset.set_apply_callback(myset_freq, _sets, "fmschi", 40)
> +            fmb.append(rset)

I would really prefer that you not add dead code like this. Commented out code is also pretty smelly, so I would rather just mention in a comment that you don't know what "fmsclo" and "fmschi" do and that they're unimplemented or something like that. A person could look at this (especially via grep or in a diff) for a while wondering why this isn't showing up in the UI, before noticing that it's dead.

> diff -r 3f9d47c26743 -r 251bf9ab9b14 tools/cpep8.manifest
> --- a/tools/cpep8.manifest	Wed Jun 26 08:00:02 2019 -0700
> +++ b/tools/cpep8.manifest	Sun Jun 30 05:35:16 2019 -0700
> @@ -74,6 +74,7 @@
>  ./chirp/drivers/th9800.py
>  ./chirp/drivers/th_uv3r.py
>  ./chirp/drivers/th_uv3r25.py
> +./chirp/drivers/th_uv8000.py
> 

Good man :)

--Dan


More information about the chirp_devel mailing list