New Model #11671
closedBaofeng W31D
100%
Description
I picked up a pair of these Baofeng W31D radios, have tried to connect with the "Next" version of Chirp, I tried the W31E and the BF888, but they fail to connect.
I believe they are similar to the W31E, but Digital instead.
Here is a link to the FCC page for them: https://fcc.report/FCC-ID/2AJGM-W31D
I have attached an image from the sellers page.
I have also requested the correct CPS software from the seller as nothing seems to work with them, please let me know if there is anything else I need to provide.
Files
Updated by Marcos Del Sol about 1 month ago
- File w31d_read.txt w31d_read.txt added
I got my hands on two W31D and have been decompiling the manufacturer's messy Electron app (version v1.4.4 to be specific). I'm documenting it here in case me or someone else more familiar with CHIRP can implement them.
When reading the memory, first it sends a fixed "0270724f4752414d" (b'\x02prOGRAM'). The radio will reply with four bytes which represent the region (first byte), model (second byte), major software version in BCD (third byte) and minor software version in BCD (fourth byte).
The region indicates the built-in voices for the channel indication voices, and are as follows:
- 00: English + Chinese
- 01: Chinese + Russian
- 02: Russian + English
- 03: Arabic + English
- 04: Arabic + Chinese
- 05: Arabic + Russian
- 06: Chinese + Portuguese
- 07: English + Portuguese
- 08: Chinese + Spanish
- 09: English + Spanish
- 0A: Chinese + German
- 0B: English + German
- 0C: Chinese + French
- 0D: English + French
The application has seemingly support for five different programming protocols (called A through E), which are seemingly pretty similar between them. The full list of models and protocol versions are:
The registry of radios and protocols list:
- 00: Baofeng V1D, protocol A
- 01: 888SD, protocol A
- 02: 1901D, protocol C
- 03: 889D, protocol B
- 04: W31D(GMRS), protocol D (that "GMRS" bit is actually in their code)
- 05: T20, protocol D
- 06: V4D, protocol B
- 07: 1904D, protocol A
- 08: 1909D, protocol B
- 09: UV8D, protocol E
- 0A: V12D, protocol A
Then it sends a follow-up message that depends on the protocol:
- A, B or D: 0280824F4752414D
- C: 0220224F4752414D
- E: 02A0A24F4752414D The radio will reply with a 06 byte (ACK?)
Then the PC sends some hardcoded values and checks them against other hardcoded values:
- Sends 02, expects 5033313037f70000
- Sends 06, expects 06
- Sends 52013008, expects 57013008ffffffffffffffff
- Sends 06, expects 06
Now it begins the actual read loop. It reads them in chunks of eight bytes, like so:
- Sends 52 ("R" in ASCII for read?) + two bytes representing the address in big endian + 08 (length?)
- Receives 08 (length? not checked) + two bytes representing the address in little endian (also not checked) + 52 ("R", not checked) + 8 bytes of data
- For all but protocol E, sends 06, expects 06
- For protocol E no idea yet what it's doing Note the addresses are not read linearly - it seems it jumps forward multiple times, and depending on the address it pushes data to one array or the other.
Finally, it issues one final 45 command which is probably to exit programming mode. It does not expect any reply.
Attached is the entire read process for my walkie.
Updated by Marcos Del Sol about 1 month ago
I am currently implementing the driver for the Baofeng W31D on https://github.com/kk7ds/chirp/pull/1207, and I think I found a discrepancy between the documentation and the "test_dtcs" in test_brute_force.py.
Namely, the documentation currently says that:
A Memory.tmode of "DTCS" means that the radio will transmit a DCS code, according to either the Memory.dtcs or Memory.rx_dtcs value. In this mode, the receiver uses DTCS squelch with the same value of the transmitter. If the radio's feature set includes "has_rx_dtcs" then the value used in this case is Memory.rx_dtcs. Otherwise, use Memory.dtcs.
However, the test always writes to m.dtcs
, ignoring has_rx_dtcs
:
def test_dtcs(self):
m = self.get_mem()
m.tmode = "DTCS"
for code in self.rf.valid_dtcs_codes:
m.dtcs = code
self.set_and_compare(m)
Which one is the correct behaviour? Where should I read the DTCS code if has_rx_dtcs
is true? m.dtcs
as the tests suggests, or m.rx_dtcs
as the documentation states?
Updated by Dan Smith about 1 month ago
DTCS
mode means the same code for TX and RX, as stored in Memory.dtcs
. If tmode=Cross and the receive tone mode is DTCS (i.e. ->DTCS
) then rx_dtcs
holds that code and dtcs
holds the transmit code (if used). The complexity comes from the fact that CHIRP was designed for amateur radios that almost universally only support the same tx/rx code and thus we started supporting radios that don't have that behavior, we had to bolt on a solution.
Updated by Marcos Del Sol about 1 month ago
Should the documentation be updated then to reflect in DTCS mode we should use .dtcs
field? Because I'm not the first one to find that clash between docs and implementation: https://github.com/kk7ds/chirp/blob/605037deb68994bbb3114c2a35db7a7a7e4755a6/chirp/drivers/anytone778uv.py#L884-L888
Updated by Dan Smith about 1 month ago
Yeah, probably, I'll work on that later. I don't doubt we've got other drivers that haven't done this perfectly, especially early ones like the one you referenced.
Updated by Dan Smith about 1 month ago
- Related to New Model #11742: Add support for Baofeng BF-T20D added
Updated by Marcos Del Sol 27 days ago
- Status changed from Feedback to Closed
Applied in changeset github|43449629fb3c2ae0b71e8b7cb7d49e8e97a00c64.