[chirp_devel] [patch] initial support for AnyTone 778uv
Hello,
As a bit of lockdown fun I've written a driver for the AnyTone 778UV, see issue #4901. It only supports memories (no settings) and can control frequency, offset, duplex, power level, and CTCSS tones.
Testing so far has been pretty limited, it passes the chirp test suite, and I can round-trip settings from chirp to the radio to the AnyTone software and back without corruption.
Patch and factory image attached. It's my first chirp driver, so I'm sure there will be things to change. Suggestions welcome.
Cheers Joe
Hi Joe,
Patch and factory image attached. It's my first chirp driver, so I'm sure there will be things to change. Suggestions welcome.
Sorry for the delay. Lockdown hasn't been less busy for me, unfortunately so I have been woefully behind on processing this and Rick's updated patch. Thanks for working on this, and your patience. I haven't made it through this all the way, but will give you some early feedback on what I've seen so far.
+struct {
- bbcd freq[4];
- bbcd offset[4];
- u8 unknown1;
- bit flags1[8];
Wow, I totally forgot about this bit type. I should be using this more. However, I think you don't actually want to use this. This is for arrays of homogenous flag bits, where we're mapping memory number into a bitfield of presence bits or something. Since this appears to be an array of heterogenous flags, I think you'd be better doing something like this:
u8 talkaround:1, scramble:1, unknown:2, txpower:2, negsplit:1, possplit:1;
and then you can refer to them by bit:
if _mem.talkaround: ...
which removes the need to do all your bit-shifting math.
+def reprdata(bindata):
- hexwidth = 60
- sepwidth = 4
- line = ''
- sepctr = 0
- for b in bytes(bindata):
line += '%02x' % ord(b)
sepctr += 1
if sepctr == sepwidth:
line += ' '
sepctr = 0
- line += ' ' * (hexwidth - len(line))
- for b in bindata:
if 0x21 <= ord(b) <= 0x7E:
line += b
else:
line += '.'
- return line
I think utils.hexprint() is what you want. It'll print hex/ascii which I hope would be enough.
+# Download data from the radio and populate the memory map +def do_download(radio):
- '''Download memories from the radio'''
- # Get the serial port connection
- serial = radio.pipe
- try:
enter_program_mode(radio)
# now read the contents of all 200 memories
# TODO there's a load of other stuff we could read here
memory_data = ''
# read the occupied memories
# TODO use this to guide read memories
for addr in ADDR_OCCUPIED_MEMORIES + ADDR_SCAN_MEMORIES:
read_command = struct.pack('>BHB', 0x52, addr, MEMORY_RW_BLOCK_SIZE)
read_response = send_serial_command(serial, read_command,
MEMORY_RW_BLOCK_CMD_SIZE)
LOG.debug('read response: %s' % reprdata(read_response))
# TODO: check checksums
address, data, valid = parse_read_response(read_response)
memory_data += data
# status info for the UI
status = chirp_common.Status()
status.cur = 0
status.max = (MEMORY_ADDRESS_RANGE[1] -
MEMORY_ADDRESS_RANGE[0])/MEMORY_RW_BLOCK_SIZE
status.msg = 'Cloning from radio...'
radio.status_fn(status)
# TODO the vendor s/w does some magic here and only reads the occupied
# memories
for read_address in range(MEMORY_ADDRESS_RANGE[0],
MEMORY_ADDRESS_RANGE[1] +
MEMORY_RW_BLOCK_SIZE, MEMORY_RW_BLOCK_SIZE):
read_command = struct.pack('>BHB', 0x52, read_address,
MEMORY_RW_BLOCK_SIZE)
read_response = send_serial_command(serial, read_command,
MEMORY_RW_BLOCK_CMD_SIZE)
LOG.debug('read response: %s' % reprdata(read_response))
# TODO: check checksums
address, data, valid = parse_read_response(read_response)
memory_data += data
# update UI
status.cur = (read_address -
MEMORY_ADDRESS_RANGE[0])/MEMORY_RW_BLOCK_SIZE
radio.status_fn(status)
exit_program_mode(radio)
Hmm, it looks to me like you're reading the memory out of order, which is fine, but also constructing the image out of order as well. It's cool to try to optimize the read, which looks like future work, but we need to construct a whole and faithful image. That means the image should mirror what is in the radio. You can read the mapping first, but you should construct data to fill the image for the sections you don't read (according to what it looks like in the radio) and make sure to stash the mapping information you read early into the memory map in the right location based on where it is in the radio. Also, make sure you're reading everything else if there is a gap between the end of the memory and those flags. The OEM software has the advantage of knowing what the memory layout of the radio should look like, but since we don't, we should try to capture as much of it faithfully as we can.
- except errors.RadioError, e:
raise e
Please use python3-compatible syntax in new code (should be "except exception as e".
- except Exception, e:
raise errors.RadioError('Failed to download from radio: %s' % e)
- return memmap.MemoryMap(memory_data)
Since this is a new driver, please use the newer format so that this has a hope of being python3 compatible. That means using MemoryMapBytes() here and setting NEEDS_COMPAT_SERIAL=False on your radio class. See the tk8180 driver for one example. (There's not really much way you could have known this, without following the archives here, sorry but thanks).
rp.experimental = \
('This kinda works for me, see if it works for you'
'and let me know: joe@milbourn.org.uk '
'If you break it, you broke it, and you get '
'to keep the all the bits.')
In the final version we commit, I'd like this just to mirror what some of the other drivers mention. Things you haven't tested, concerns you have, or just a statement that it's experimental. People can file a bug report for issues, which we can assign to you. I'd like to not have direct emails in these just because it reduces visibility for everyone else that there may be a problem.
# TODO radio does support dtcs, but I've not looked into that yet
# so it's disabled here.
rf.has_dtcs = False
This really needs to be implemented in the final version. DTCS is too core and common to not include it.
This is as far as I've gotten thus far, but overall it looks like a really solid first draft, so thanks and kudos!
--Dan
Hi Dan,
Thanks for looking through the patch, and thanks for chirp. New patch and image attached, which I think covers all your points. I've run the test suite with tox, and get a clean sweep with no errors.
A few specific comments in-line below.
On 15 May 20, Dan Smith via chirp_devel said:
Wow, I totally forgot about this bit type. I should be using this more. However, I think you don't actually want to use this. This is for arrays of homogenous flag bits, where we're mapping memory number into a bitfield of presence bits or something. Since this appears to be an array of heterogenous flags, I think you'd be better doing something like this:
Excellent - I hadn't twigged you could that, much easier to read. Done.
I think utils.hexprint() is what you want. It'll print hex/ascii which I hope would be enough.
hexprint() will do nicely, I stole reprdata from my hacky development scripts. Done.
Hmm, it looks to me like you're reading the memory out of order, which is fine, but also constructing the image out of order as well. It's cool to try to optimize the read, which looks like future work, but we need to construct a whole and faithful image. That means the image should mirror what is in the radio. You can read the mapping first, but you should construct data to fill the image for the sections you don't read (according to what it looks like in the radio) and make sure to stash the mapping information you read early into the memory map in the right location based on where it is in the radio. Also, make sure you're reading everything else if there is a gap between the end of the memory and those flags. The OEM software has the advantage of knowing what the memory layout of the radio should look like, but since we don't, we should try to capture as much of it faithfully as we can.
Done, I think, just let me check what I should be doing. Previously I was reading in only the bits of memory I knew what to do with, and storing them out of order. Understand why that's not desirable, so now I'm reading the whole memory, settings and everything, and only modifying things I understand.
Is that what you intended?
Please use python3-compatible syntax in new code (should be "except exception as e".
Done.
Since this is a new driver, please use the newer format so that this has a hope of being python3 compatible. That means using MemoryMapBytes() here and setting NEEDS_COMPAT_SERIAL=False on your radio class. See the tk8180 driver for one example. (There's not really much way you could have known this, without following the archives here, sorry but thanks).
Done.
In the final version we commit, I'd like this just to mirror what some of the other drivers mention. Things you haven't tested, concerns you have, or just a statement that it's experimental. People can file a bug report for issues, which we can assign to you. I'd like to not have direct emails in these just because it reduces visibility for everyone else that there may be a problem.
Done, now says: "This is experimental support for the AnyTone 778UV. Please send in bug and enhancement requests!"
This really needs to be implemented in the final version. DTCS is too core and common to not include it.
Done.
Cheers, Joe
Thanks for looking through the patch, and thanks for chirp. New patch and image attached, which I think covers all your points. I've run the test suite with tox, and get a clean sweep with no errors.
Indeed, thanks a lot for making those changes. It's easy to eye-verify the communication routines now (trusting you on the end address of course).
hexprint() will do nicely, I stole reprdata from my hacky development scripts. Done.
Looks like you converted to using it, but didn't remove the definition of the helper. With your permission I'll remove that as it doesn't seem like you depend on it anymore.
Done, I think, just let me check what I should be doing. Previously I was reading in only the bits of memory I knew what to do with, and storing them out of order. Understand why that's not desirable, so now I'm reading the whole memory, settings and everything, and only modifying things I understand.
Is that what you intended?
Yes, with one annotation. If you can avoid reading some of the memory because you know it's empty, but still construct a whole image, it's fine to skip the actual reading to save time. The important part is the consistent image format. What you have now is simple, straightforward, and faithful. If you think it's important to iterate to the performance-optimized version that avoids those reads (as I'm sure the OEM software does) then that's fine, as long as you keep the image in order and whole. In my experience, for small-memory radios it's not that important to avoid three extra seconds downloading, so it's not worth the code complexity, but I'll defer to you as the one with the tactile experience with that specific radio :)
I've applied this version and the image, thanks very much!
--Dan
participants (2)
-
Dan Smith
-
Joe Milbourn