Home | Ruby | Programming Icom Radios |     Share This Page
Programming Icom Radios
All content Copyright © 2010, P. LutusMessage Page

Version 1.5, 12/15/2010

Introduction |  Preliminaries |  Setup |  Operation |  Troubleshooting
Technical |  Version History |  GPL |  Listing

(double-click any word to see its definition)

NOTE: This program has been superseded by IcomProgrammer II, a much better program with more features.

 

Introduction

I've been a radio amateur for about 50 years (currently KE7ZZ). I haven't been active that entire time, but I've always had a few interesting radios around, home-built in the early days, and increasingly exotic as I matured.

I recently decided there's no point in having any radios apart from Icoms. This may sound rather narrow-minded, but during my solo around-the-world sail, I watched every single piece of electronics give up the ghost at least once, and I began to rank radios by how long they lasted after a gallon of cold salt water was splashed on them. In this informal ranking, the Icom score remained relatively high, hence my current prejudice (and that's what it is — a prejudice, the choice of a lazy mind).

A digression: don't misunderstand — I didn't deliberately splash salt water on my radios, but there's no need to arrange such a stress test while sailing on the open ocean. Given enough time, nature will take care of that for you. And there is no safe location for a radio — at some point in a long ocean voyage, salt water will get everywhere.

And not just salt water. One night as I lay asleep, sailing along in the tropics under autopilot control, a flying fish flew across the top of my boat's cabin. But this unlucky fish hit an open port cover and was deflected down into the cabin, into my sleeping bag, where I lay asleep in a more or less unclothed condition. You cannot imagine the shock of being awakened from a blissful sleep by the feeling of a greasy, cold, wet flying fish against your bare skin, struggling to get away from you by thrashing even further down into your sleeping bag.

End of digression. Having only one brand of radio greatly simplifies any software projects one might consider. I recently decided to create a way to program all my radios with suitable frequency lists, in a fast, efficient way. In an earlier project called EasyTuner I used a spreadsheet to contain the lists and to program the radios. Later on I created a graphic radio controller for the Icom PCR1000, unfortunately, this radio has a lot of traits not common to other Icom radios, so the code isn't very portable.

Then I wrote a more general controller program called RadioComm, which created a sort of virtual control panel for a number of different Icom radios. But RadioComm is more of a user interface than a radio programmer, and worse, it only runs on Windows, something I've more recently come to regard as inexcusable.

So I have been working on a better, more universal radio programmer, one that would work with most Icom radios, one that would program specific radios with particular sets of frequencies and modes, and that would run on both Windows and Linux. This is the result — IcomProgrammer.

IcomProgrammer is more oriented toward database management than user interface, in fact, it runs on the command line. You tell IcomProgrammer which radio you want to program, and it fetches the required data tables and programs the selected radio, as fast as possible. You can create any number of frequency tables, and you decide which tables are applied to which radio.

The Details

I've recently become a Ruby enthusiast, primarily because Ruby development is so fast, and because Ruby programs remain understandable after months or years of neglect, if one chooses reasonable names for things in the first place. IcomProgrammer is a Ruby script that can program nearly any Icom radio with one or more user-defined frequency tables, including such esoterica as repeater tones and split-frequency modes.

Preliminaries

To use this program, the reader needs to have at least one Icom radio and an Icom RS-232 converter box (CI-V). Actually, now there are better choices than Icom's RS-232 converter box. I just bought one of the new USB CI-V units (from Black Cat Systems), and it is in every way better than Icom's own unit — cheaper, smaller, easier to use, and powered by the USB port it is connected to.

The reader also needs to acquire a copy of Ruby (download here). Ruby versions are available for both Windows and Linux, and my program will run on either platform. IcomProgrammer was originally written and tested on Linux, but because there are so many Windows machines out there, I decided to make it cross-platform compatible, even though I personally think everyone should drop Windows and install Linux.

Setup

Terminology

field
An item of information like a frequency, part of a record.
record
A collection of fields meant to be used together. In this case, a record consists of fields separated by commas.
table
A collection of records. In this case, individual records are on separate lines of a table.

Example

Mode , RxFreq , TxFreq
lsb , 3.9 ,  
usb , 14.2 ,  
fm , 147.2 , 147.8

IcomProgrammer figures out what to do based on internal and external sources of information. Let's start with the external data.

IcomProgrammer reads tables of frequency and mode data from some plain-text data files that have fields separated by commas. This is a transparent, easily understood database form that one can create in an ordinary editor.

The default directory structure for IcomProgrammer looks like this:

ProgDir (the program directory, can have any name)
 icom_programmer.rb (the program, click to view)
frequency_data (the data directory)
 ham_hf.csv (data tables, click to view examples)
 marine_hf.csv
 vhf_repeaters_short.csv

This simple layout assures that IcomProgrammer can find its data tables. Again, the data directory can contain any number of tables for different purposes, and you can apply any combination of tables to a particular radio.

A few words about the data tables. IcomProgrammer honors five field names: Mode, RxFreq, TxFreq, RxTone and TxTone. The field names appear in the first line of the table, a line called the "header". This header line is required to be present, but not all the field names need to be included. If you don't have any use for RxTone, TxTone or TxFreq, just leave them out. Also, the field names don't have to be in any particular position, because IcomProgrammer reads the header line and creates a list of field positions for later use while reading the data. Finally, any number of other field names may be present in the table for other purposes, IcomController will not get confused.

The only required fields are Mode and RxFreq. One might use TxFreq to specify a different frequency for transmitting than receiving (split-frequency mode). One uses TxTone to specify a tone frequency that allows repeater access, typically used in VHF repeater work. One uses RxTone to specify a tone squelch frequency, now only sometimes used. Any of these fields may be absent from your tables except Mode and RxFreq, the two required fields. And one may retain a field name and column, but leave the values blank as in the data table example shown on this page, and IcomProgrammer will know what to do.

The sample tables linked above have field data that is delimited by quotes, but the quotes are optional. I posted these quoted example tables because this is how a typical spreadsheet program exports data in the CSV (comma-separated values) format. A spreadsheet is a reasonable way to create and edit frequency tables, after which one needs to export the tables as plain-text CSV data files. By the way, if you encounter strange errors or inconsistencies while using IcomProgrammer, make sure there are no commas within your data fields — this will confuse the relatively simple data scanner used in IcomProgrammer.

Let's turn to some user configuration options within the Ruby script itself. To choose a serial com port other than the default ("COM1" for Windows and "/dev/ttyUSB0" for Linux), edit the variable named "@ser_port". To change the name or location of the data directory, edit the variable named "@data_directory".

But the single most important user customization step is to edit the radio information array named "@radio_info_hash" to suit your needs and preferences. Here is what the array looks like in the listing:

@radio_info_hash = {
   "IC-706-Boat" => [0x4e,["ham_hf","marine_hf","marine_vhf_short","E"]],
   "IC-706-Home" => [0x4e,["ham_hf","marine_hf","vhf_repeaters_short","E"]],
   "IC-746" => [0x56,["ham_hf","marine_hf","marine_vhf_short","vhf_repeaters_short","E"]],
   "IC-756" => [0x5c,["ham_hf","marine_hf","E"]],
   "IC-R8500" => [0x4a,["ham_hf","marine_hf","cb","marine_vhf_long","vhf_repeaters_long","E"]]
}
              

This array consists of lines, one line per radio configuration (notice that one radio has two possible configurations). Each line contains the following information:

   "Radio Name" => [Radio hex ID,["data_table_1","data_table_2"]],
              
Icom Model
Hex ID
Ham Radios
IC-703 0x68
IC-706 0x4e
IC-706MKIIG 0x58
IC-718 0x5e
IC-725 0x28
IC-726 0x30
IC-728 0x38
IC-729 0x3a
IC-735 0x04
IC-736 0x40
IC-746 0x56
IC-746Pro 0x66
IC-751 0x1c
IC-756PRO 0x5c
IC-756PROII 0x64
IC-756PROIII 0x6e
IC-761 0x1e
IC-765 0x2c
IC-775 0x46
IC-781 0x26
IC-970 0x2e
IC-7000 0x70
IC-7200 0x76
IC-7600 0x7a
IC-7700 0x74
IC-7800 0x6a
IC-R71 0x1a
IC-R72 0x32
IC-R75 0x5a
IC-R7000 0x08
IC-R7100 0x34
IC-R8500 0x4a
IC-R9000 0x2a
Marine Radios
M-700Pro 0x02
M-710 0x01
M-710RT 0x03
M-802 0x08
(Any) 0x00

The user may add as many such lines as are required to represent existing radios and data tables. There is nothing magic about the radio names, they are only used by the human. But the hex radio IDs are special — each Icom radio has a unique hex ID that needs to be entered so the instructions for that radio are routed correctly. Use the list on this page to find your radio's hex ID, or find the code on the Web for those radios not included in my list.

The frequency table list can contain any number of entries. Each entry in the list represents a shortened form of the data file names to be located in the frequency data directory. For an entered name of "my_frequencies", IcomProgrammer will look for a file named "frequency_data/my_frequencies.csv".

There is a special, optional pseudo-filename of "E" that can be included in the list, as shown in the example list above. This name tells IcomProgrammer to erase any unused memory locations as the last step in the programming of the radio.

One final note about radios and frequency lists. If you have more than one desired configuration for a particular radio, simply make multiple entries in the configuration array described above and use different names for the radio — "IC-756 At Home" and "IC-756 Field Day", for example, with a different list of frequency tables, but with the same hex ID. The program menu will display all the entries you create, so you can choose a specific configuration for any radio.

Operation

Once you have created and positioned the desired frequency tables and edited the program's radio list and other options, it's time to run IcomProgrammer. First, click here for a plain-text copy of the Ruby script. Download it, rename it "icom_programmer.rb" and position it as shown above — with a subdirectory named "frequency_data" that contains your frequency tables. Under Linux, make the file executable:

$ chmod +x icom_programmer.rb
              

Connect your CI-V converter box to your computer, and connect your radios to the CI-V converter box (one at a time, if necessary). In Windows, assuming you have already installed Ruby (see the "Preliminaries" section above for this), to run IcomProgrammer you should be able to click the program filename in Windows Explorer. Under Linux, if you want to be able to launch IcomProgrammer directly from X Windows, use a shell script like this one:

#!/bin/sh

[ "$TERM" == "dumb" ] && exec xterm $0 "$@"

path=`dirname $0`
[ "$path" == "." ] && path=`pwd`
cd $path

./icom_programmer.rb "$@"

echo -n "Press Enter to close:"
read
              
Click here for a plain-text copy of this Linux script. Name the shell script something like "launch.sh", make it executable ("chmod +x launch.sh"), and place it in the same directory as the Ruby script. When you click the shell script from XWindows, it will relaunch itself in a console window and then launch the Ruby script.

When you run IcomController, you will see a menu of choices, more or less like this:

Choose an action:
   1) Program IC-706-Boat
   2) Program IC-706-Home
   3) Program IC-746
   4) Program IC-756
   5) Program IC-R8500
   6) Generate Memory Lists
   7) Quit
Choose (1 - 7):|
              

Obviously, after you have edited the program file to suit your personal preferences, your menu display will be different. To run IcomProgrammer, choose an option and type in the corresponding number.

The option "Generate Memory Lists" creates a set of memory content lists in CSV format for the radios as they would be programmed by IcomProgrammer, including memory and memory bank numbers if applicable. A separate memory list is generated for each configuration. The lists are placed in a subdirectory named "radio_lists".

Troubleshooting

If anything is wrong with your setup, there won't be a progress display of dots, instead the program will wait forever, silently, for a response from the radio you have chosen, or it will print an error message and exit. Here are some possible problems:

  • You chose the wrong radio from the menu list.
  • The wrong hex ID has been entered into the program configuration.
  • The radio has had its hex ID changed from the default (yes, this is possible on some Icom models).
  • The radio isn't connected to the CI-V or is not turned on.
  • The serial port you have entered into the program listing is not present.
  • You have multiple serial ports and the CI-V converter box isn't connected to the port you think it is.
  • The frequency tables are not located correctly with respect to the program (see the diagram above).

There are other, more exotic, error possibilities, but these are the most likely causes of difficulty.

Some Technical Details

NOTE: In a known limitation and for unknown reasons, this Ruby script won't correctly program repeater access tones into a particular Icom radio (the IC-706 and newer models of this line). I think it may be because this specific ability was left out of this radio's instruction set.

Click here for a Web site that has a great deal of detail about the communications protocol used by Icom radios and the CI-V.

In my earlier Icom programming projects, I quickly discovered that the CI-V doesn't use any kind of handshaking to regulate the transaction speed. So I carefully inserted delays between transmitted commands to prevent dropped bytes. But this approach suffered by assuming the worst-case speed — the slowest radio, executing the slowest command, governed the overall speed of communication for any radio.

In this project, I decided to find out exactly what the Icom radios were replying with, in hope of using the replies as a simple handshake method. I figured out that the radio first echoes the entire command just sent, then after processing the command it sends a formal reply of six bytes to reveal whether any errors occurred. So I am now using the radio's replies to regulate the transaction, which greatly speeds up the rate at which I can program a radio.

There is one drawback to this approach. If there is anything wrong with the setup, if for some reason the radio doesn't respond, the program will hang forever waiting for a reply, and will have to be cancelled by the human operator. Normally the operator will see a row of dots being printed as the transaction progresses, and if this row of dots doesn't get printed, it means the program is in an eternal wait state and will have to be cancelled — by pressing Ctrl+C or by closing the window the program is running in.

To deal with possible error conditions, I recommend that the reader run the program from an opened shell session rather than by clicking on the program filename — this allows some kinds of error messages to be read and acted upon. Also, edit the program and set "DEBUG=true" near the top of the listing — this will print a lot of detailed information about what is taking place.

While the DEBUG flag is set to true, the reader will see a number of error messages that only show that a command sequence required by a particular radio was not recognized by your radio, e.g. a harmless error with no consequences.

Version History

  • 12/15/2010 Version 1.5. Updated the Icom radio / hex code cross-reference list.
  • 12/10/2010 Version 1.4. Changed one line to accommodate an evolutionary change in Ruby.
  • 11/05/2007 Version 1.3. Fixed an inconsistency in the list generator that caused it to fall out of sync with the actual radio index numbers when multiple tables were used. Added a way to skip the menu when list generation is all one wants (a program argument of "-g").
  • 10/28/2007 Version 1.2. Initial Public Release.

GPL Note

IcomProgrammer is Copyright © 2010, P. Lutus, and is released under the GPL. Please post to my Message Page any comments you may have about this program.
 

Home | Ruby | Programming Icom Radios |     Share This Page