Project

General

Profile

DevelopersAdd a Radio » History » Version 14

Dan Smith, 07/29/2023 08:09 AM

1 9 Dan Smith
# How to add a new radio driver
2 1 Tom Hayward
3
You've got a radio that's not in Chirp, a little bit of software development experience, and you want to add that radio to Chirp. Here's what you'll need:
4
5 9 Dan Smith
* a subscription to the [chirp_devel mailing list](http://intrepid.danplanet.com/mailman/listinfo/chirp_devel)
6
* a Python development environment
7 1 Tom Hayward
* radio
8
* programming cable
9
10 9 Dan Smith
## Setting up the development environment
11 1 Tom Hayward
12
If you want to develop in another operating system, you're on your own. This guide isn't going to cover it. Here's a guide for Windows: [[DevelopersWin32Environment]].
13
14 9 Dan Smith
## Look over some existing code
15 1 Tom Hayward
16
Read source:chirp/drivers/template.py. The whole thing.
17
18
This serves as a starting point for understanding the structure of a driver for a radio that operates in "clone mode", which is by far the most common type of radio and CHIRP driver. If your radio will operate in "live mode", and especially if your radio uses the CAT protocol, you should probably start by reading source:chirp/drivers/kenwood_live.py.
19
20 9 Dan Smith
## Write the download/upload routines
21 1 Tom Hayward
22 9 Dan Smith
### Sniffing the protocol used by existing software
23 1 Tom Hayward
24 9 Dan Smith
If you have other programming software for your radio, such as the software from the manufacturer, you can sniff the serial programming protocol with [Portmon](http://technet.microsoft.com/en-us/sysinternals/bb896644.aspx). Typically, radio programming software is written for Windows, and Portmon is a Windows utility.
25 1 Tom Hayward
26 9 Dan Smith
For recent versions of Windows, you might try sniffing USB with [USBPcap](http://desowin.org/usbpcap/). The captured data is analysed with any recent version of [Wireshark](http://www.wireshark.org).
27 1 Tom Hayward
28
Start with a read.
29 4 Aaron P
30 9 Dan Smith
1. Click Read in the official software
31
1. Watch the output of Portmon after you click Read
32
1. Look for a line that sets the BAUD RATE. Sometimes there are a few of them.
33
1. Look for a WRITE line with a few data bytes. This is probably the command to tell the radio to start sending data.
34
1. Look for READ lines with lots of data bytes after them. This is probably the memory contents of the radio being downloaded
35
1. You're a smart developer. You should be able to figure out the protocol from here!
36 1 Tom Hayward
37
You can also sniff a many Windows programs by running them in the Wine environment under Linux. Manufacturers' radio programming software is likely to run in this environment. See [[DevelopersUSB Sniffing in Linux]].
38
39
h3. Using existing Chirp code
40
41
If the radio you're developing for doesn't have existing programming software, you won't be able to use the above reverse engineering technique. Most radio manufacturers use a common protocol across most of their radios. Because Chirp supports so many manufacturers, there's a chance an existing radio driver has a download routine that will work with your new radio. This is especially true with Yaesu radios (other than the FT-4/FT-65 family), which don't really even have a protocol. They just dump their memory. All you need to figure out is the baud rate and the memory size (and baud rate is usually 9600).
42
43 5 Daniel Clemmensen
Choose a radio driver that you think might be similar. If you were going to add the VX9, you might start with the VX8 driver:
44 1 Tom Hayward
45 9 Dan Smith
```
46
$ cd chirp/chirp
47
$ sed s/VX8/VX9/g vx8.py > vx9.py
48
```
49 1 Tom Hayward
50 9 Dan Smith
Increase the `_memsize` variable significantly. The goal is to read more data than the radio sends.
51 1 Tom Hayward
52
Launch Chirp and start a download with your new radio driver. Did it work, sort of? Save the .img.
53
54 9 Dan Smith
Now we're going to determine the `_memsize`. Open the .img in a hex editor:
55 1 Tom Hayward
56 9 Dan Smith
```
57
$ hexdump -C VX9_oversize.img | less
58
```
59 1 Tom Hayward
60 9 Dan Smith
Look towards the end of the file for the offset where the data becomes all zeros. This is your `_memsize`. The radio has stopped sending data, but Chirp was still "reading". Change `_memsize` in your driver so that Chirp reads the same number of bytes the radio is sending.
61 1 Tom Hayward
62
h2. Map the memory blob
63
64
To map the memory layout, you're going to make a small change on the radio, do a download, then look for differences. Do this over and over until you have the whole memory layout mapped.
65
66
Here's a little helper script I use for the comparisons:
67
68 9 Dan Smith
`hexdiff.sh:`
69
70
```
71 1 Tom Hayward
#!/bin/sh
72
73
A=`mktemp`
74
B=`mktemp`
75
76
hexdump -C $1 > $A
77
hexdump -C $2 > $B
78
diff $A $B | less
79
rm $A $B
80 9 Dan Smith
```
81 1 Tom Hayward
82 9 Dan Smith
1. Find the first channel
83
1. Find the second channel
84
1. The offset between the two is your memory channel struct size
85
1. Find the last channel. Hopefully its offset is struct size * advertised number of channels away from the first channel!
86 1 Tom Hayward
87
You'll probably start off with something like this:
88 9 Dan Smith
```
89 1 Tom Hayward
MEM_FORMAT = """
90
#seekto 0xb00;
91
struct {
92
  u32 freq;
93
  u8 unknown1;
94
  u8 unknown2;
95
  u8 unknown3;
96
  char name[8];
97
} memory[200];
98
"""
99 9 Dan Smith
```
100 1 Tom Hayward
101 9 Dan Smith
`0xb00` is the location of the first memory channel.
102
`200` is the number of channels the radio supports.
103
`unknown1`, `unknown2`, and `unknown3` are for memory-specific settings (e.g., tone) that you haven't sussed out yet.
104 1 Tom Hayward
105 10 Dan Smith
## Write `get_memory()`
106 1 Tom Hayward
107 11 Dan Smith
This is called to get your driver to populate the CHIRP memory model with the data for one radio memory. On startup, it’s called once for each memory register you’ve delimited for your radio and once for each special memory. Later it will be called as needed.
108
109
* `get_memory()` returns a populated CHIRP memory object that the driver creates as a new instance of the chirp_common.Memory structure. You’ll want to become familiar with the fields in the Memory structure (presently specified in the source tree in the source file `chirp/chirp_common.py`).
110
  
111
* The number of memories is specified in `chirp_common.RadioFeatures.memory_bounds`, which is a pair of numbers (first memory number, last memory number.) `get_memory()` will be called with an integer parameter for regular memories with a value up to the last memory number.
112
113
* Special memories are radio-specific channels that can hold special meaning in the radio (such as scan limits, home/call channel, skip channels, etc.) They are specified in your driver as members of the list that you set at `chirp_common.RadioFeatures.valid_special_chans`. `get_memory()` will be called with a string containing the name of the special channel, and you must set the `Memory.number` field of the resulting memory object to an index that is greater than the last memory register number and different than other special memories without holes in the sequence. Subsequent calls to `get_memory()` may receive either the index or the name.
114
115
Do read the example driver at `chirp/chirp/drivers/template.py`. There is a commented stub version of this routine in `chirp/chirp.common.py`. Your driver is expected to override it.
116
117 9 Dan Smith
## Write `set_memory()`
118 1 Tom Hayward
119 12 Dan Smith
This is called whenever CHIRP wants your driver to set a memory channel according to the fields described in the specific `chirp_common.Memory` parameter. The driver will presumably need to determine the specific place in the radio's memory based upon the value of `memory.number` (e.g. integer less than or greater than last memory number.) The driver should not change the memory structure.
120
121
There is no return value from `set_memory()`.
122
123
Do read the example driver at `chirp/chirp/drivers/template.py`. There is a commented stub version of this routine in `chirp/chirp.common.py`. Your driver is expected to overload it.
124
125 13 Dan Smith
## Per-memory extra settings
126 12 Dan Smith
127 13 Dan Smith
CHIRP can (optionally) manage and display other settings for each memory. These are stored in `chirp_common.Memory.extra`, and are handled by your driver during the `get_memory()` and `set_memory()` by setting or honoring the `extra` field, which should be a `settings.RadioSettingGroup` object.
128 12 Dan Smith
129 9 Dan Smith
## Add an image of your radio to the tree
130 1 Tom Hayward
131 9 Dan Smith
Save it to `tests/images/Vendor_Model.img`
132 1 Tom Hayward
133 9 Dan Smith
## Run tests
134 1 Tom Hayward
135 9 Dan Smith
Make sure all the tests pass before you submit:
136
137
```shell
138
$ tox
139
```
140
141 14 Dan Smith
See [[DevelopersPython3Environment]] for more examples of running tests.
142
143 9 Dan Smith
## Submit code to github