GPIO Band Decoding for the Pi

I made a fork and have now have working band decoder operating on the Raspberry Pi. I have a relay HAT module that changes on band change.

PTT relay logic is also in place though not complete yet. I have to figure out how to figure out the current band inside my function or from extChangedRsPref where I am calling my function from, or some better suggested place.

In the Rig files for the 9700 and 905 so far, I added new GPIO category pin config items for 6 BAND and 6 PTT pins, each with an inversion flag. I added Band and PTT IO output pattern associated with each band extending the current band config item list.

There is a #define GPIO in my gpio.h for now intended to disable GIO stuff for non-Pi platforms, not tested yet.

My fork is at:
https://gitlab.com/K7MDL/wfview

Mike K7MDL

Ooh this is neat.

So let me understand correctly the application.

As the user changes bands, wfview notices (either because it triggered the change or it pulled the radio and found out or via CI-V transceive information). And when it notices it flops a different band relay over?

Presumably this is to cause an amplifier to change bands? Similar to the band voltage but in relays?

What is your application?

—E
de W6EL

Correct. I hooked into setFrequency() so it gets triggered for both UI and radio band changes cleanly. It easily gives me current band and the band and PTT patterns I added to each band in the rig file.

For PTT I still have to finish a working hook. Uses same basic logic and rig fle entries.

You can have any pattern you like to operate one or more IO pins per band. I started with 6 bands for the VHF bands of the 9700 and 905, but is easily extended to more bands and works for any band, microwave or HF.

For the Band IO, you can do thigs like select antennas, operate amplifier remote enable or power inputs. My big VHF amps have a remote AC power control input.

For PTT, same thing as BAND io, only difference is the output pins are activated only during TX.

All IO pins have an inversion flag. The relays I have are active low, other are active high. I have a low cost PCB from one of my USB band decoder projects that is a buffered 1-of-8 for band and for PTT, 12 or 24V.

For the 905 I use the relay outputs to drive a SP6T coax switch to select one of the 3 905 RF outputs to the common 600-6000Mhz dish feed on my tripod or on my rotating mast.

Building it into wfView is cleaner than using a separate serial port connected app and deal with serial connection recovery.

M5Stack and likely others have a 4-relay i2c module with programmable LEDs. Might try that later.

This was a bit of an adventure as I have never done work in or on a true OO app before. Modula 2 30 years ago, otherwise all assembly, C and Pascal and more recently Python. Spent hours trying to get rigCaps rig file properties working inside my gpio class :-).

I have several other band decoders in Python and C on my GitHub site. This borrows from those.

  • Mike
1 Like

One of the most useful features of band decoder IO is PTT breakout, very much needed for the modern small radios like the 9700, 705, 905 that only have a single PTT output and of course some have single RF.

A major usage of the IO based decoding is easy transverter selection. Buffered IO or relays or opto. I have been looking at the wfView code for some time scheming a way to cut in transverter support.

My Teensy and ESP32 controllers do that today, saving the state of a native band before switching to a virtual band with custom offsets for transverters. I save and restore the transverters bands so they are ready to go with the last used VFO, mode, filter, preamp, atten, and such, custom for each band. One major feature left incomplete on these is to swap out the frequency fields in the rig control messages.

wfView acts as a comm bridge already and I think is perfectly positioned to do transverter work and present a transverter frequency to apps like loggers and WSJT-X.

This is all very interesting.

We have been considering something similar with the Pi as well. In our case it is a server sd card image with wfserver, specifically designed for radios that lack a built-in server and might also lack control over things like PTT (icom added a PTT command only around the time the IC-7200 came out). And it would handle the PTT with a relay. The Pi also makes interfacing to the CI-V bus simple. And of course you can add in things like rotor control and antenna switches. Possibly hacked into the wfview remote protocol(s).

Anyway, a lot to think about. The 905 is a good example for your relay project with all the (vastly) different bands it supports.

Thank you for contributing the code and ideas. We will take a look.

—E
de W6EL

I just got PTT working, will be checked in soon.

I split the IO output function call into 2 parts. One to set the current band and the GPIO modules remembers that. The other passes PTT state and sets the 12 Band and PTT lines in bulk. I hooked into wfmain.cpp receivePTTstatus(). I am sure you would have something more elegant.

The ability to set the band separate of the current band is useful for crossband split, particularly the IC-9700 where you may not want to switch relay between the Main and Sub bands, or you might. I make it a config choice,

The Pi IO requires unique IO pins (12 in this case) or setting the values will fail and cause bad things.

I noted the 905 rig file has the 13cm band start 2400Mhz leaving out 2300-2310 and 2390-2400 segments. I just changed my rig file to start at 2300 instead of 2400. 2450 is the high side, at least for Region 2 here. I normally use 2304Mhz for SSB terrestrial.

I like the idea of a headless server running under systemd with live status output to a log file. In my use scenario, at least at this early stage, I am leveraging wfView as a communication interface hub/protocol converter. The prospect of trying to add the LAN interface to the radio into my ESP32/Teensy decoder seems rather tough, there is no OS - the way I like it usually.

In my other decoder I have a config choice for polled or wired PTT. While LAN is decent speed, there is still lag and I prefer wired for the fasted PTT switchover speed.

In my “big” decoder/uW-wattmeter//big_pcb project on Teensy, I also built a Teensy rotator controller. Both use my own simple ASCII message set talking to an optional Python desktop app. Useful as it provides a Config UIO for complex band decoder rules and ship up the final parameters into EEPROM. Using an established rotor protocol has advantages but did not solve my decoder/wattmeter needs.

I am surrounded by transverters. Most are on the K3 as it supports them natively and has BCD band IO. I have been trying to bring the 705 up to equivalent capability, nearly there. All my transverters, amps, and decoders are located 100ft away outside in a cabinet fed by 72VDC and stepped down to 12 and 28V. Everything has to be automated or it won’t work.

  • Mike K7MDL

I have added a PTT Input pin read function (poling style). Configured in the Rig file with pin # and invert option. This version is polling based requiring it be put into a fast loop some place.

The desired IO pin is configured for input and pullup. These IO pins are 3.3V max.

2 questions:

  1. Where is the best place for fast polling hardware like this?
  2. The function returns -1 for error, 0 for PTT OFF, and 1 for PTT ON. This accounts for inversion of configured so that the program always sees 1=ON. 0=OFF.

For testing I call the function from wfmain at the same place/time as I set the outputs today, then put a jumper on the configured pin (18 in my rig file) and note the state change in the log file info message.

A better solution is to set pin monitoring up as an interrupt with a callback function which I can do. The callback can signal a PTT TX/RX event . I do not know how to do that (yet). The Signal/Slot implementation is above my paygrade still.

  • Mike

I’m thinking that putting it in similar to the USB Controllers would make sense but I’ll let @phil confirm.

After some research looking how to do an interrupt callback for GPIO event in Linux on the Pi, it seems that gpiod library event functions are blocking. Not what I am used to in my microcontroller world.

I have a compile time option, #define POLL, to choose a simple pin polling action or create a gpiod lib event on PTT that a thread can wait on io_read_ptt(). I think setting the timeout to -1 makes it wait forever. Upon detection it breaks out of the wait and reads the line event then can activate PTT with that result.

If you have the radio SEND wired to pin 18 (observing 3.3V limit) then all works out because the normal Rx/Tx mechanisms apply.

If you key the Pi only via the PTT input pin (footswitch, sequencer) then you have to tell the app to TX.

For now, I put io_read_ptt() operating in POLL mode into icomCommander receiveCommand() function which polls the PTT line pretty fast (enabled when haveRigCaps). Then I call queue->add(…) to tell the program about it (no 3 minute timer started though, not sure how to reference that) which in turn keys the radio.

The rig file is set for Pin 18 as input. When I short it o GND it operates the PTT relay quickly. Poll mode may be good enough.

it is working pretty slick now. Changes are checked in.

  • Mike

I think I have taken it about as far as I can go and let you guys take a look at it in depth without me changing things.

Eventually will need to work out how it operates on the 9700 when the sub RX is on. On my other decoder I made it a choice between main band only, or do cross-band split in which case you call io_setband() with the desired band foir Tx and for Rx, adding in some relay settling time before PTT applied.

Have fun.

  • Mike

Hi Mike.

Looks good, if possible, could you create a PR on gitliab and we can merge that into a new branch?

73 Phil

I am not much of a GitLab person but I created a Merge Request yesterday, same thing?

Pi GPIO (!30) · Merge requests · Elliott Liggett / wfview · GitLab

Yes sorry, I meant MR (PR is GitHub terminology!)

Hi Mike.

I have merged this into a branch called gpio and fixed various things regarding compiling on ‘non’ RPi hardware. I have also added management of the GPIO pins to the rigcreator screen as I don’t encourage direct editing of .rig files (rigcreator may delete non-standard edits).

Anyway… I thought I would try building on my Pi4, all good although I had to install:

apt install gpiod libgpio-dev

Unfortunately, on connection to my IC-9700, wfview immediately crashes, this is in the log:

2025-04-04 13:59:27.833 INF system: Running configureVFOs()
2025-04-04 13:59:28.293 INF GPIO: PTT input pin = 18 PTT input pin invert = true
2025-04-04 13:59:28.293 INF GPIO: Band pins 26 20 12 11 10 9
2025-04-04 13:59:28.293 INF GPIO: PTT pins 21 4 5 6 7 8
2025-04-04 13:59:28.294 WRN GPIO: gpiod_line_request_bulk failed, likely due to duplicated pin number assignment(s)

Any ideas?

I also noticed that it crashes when no GPIO pins are defined (connecting to IC-7610) so I guess more checking is needed?

I added the gpiod lib into the install script and make file.

gpiod is user level io and does not allow for pin usage conflicts (used by another program or same pin more than once) unlike other kernel level libraries, or directly accessing registers.

I used the bulk method for simplicity, but it is harder to see which pin is in error. You can also use a single line approach. With bulk you have to have a complete list of unique pins that match the number of pins specified. I went with a fixed list of 6 band and 6 PTT lines to draw a line in the sand, but you can change that to be flexible. They cannot be null, all pin #0, or used by another program.

I would look at each pin in the list and see if they are already claimed by something on your Pi board. Perhaps a fan on one of the pins for example.

On the command line you can run various tools to see what state they are in

gpiodetect, gpioinfo, gpioget, gpioset, gpiofind and gpiomon

Also on bookworm you can use pinctrl get to see the state of all pins and manually set them. raspi-gpio on older versions.

I tested on Pi 5, the only difference should be the gpiochip4 for Pi5 vs gpiochip0 for Pi4, tested and used at the start.

I dug out a Pi4 so I can try the wfview/gpio branch on both here today.

Some use the ctxless version commands. piHPSDR is an example. it sets up an event monitor for each line added. Being it is still gpiod, it is also rigorous about using unclaimed and valid lines only. Takes some practice to spot the error message in the logs to see what line was the problem.

Thanks Mike.

I am doing a fair bit of re-writing of the code to improve exception handling, my plan is to remove the fixed limitation for number of pins, which should then work when no pins are defined!

You can run the set of pins though a test before assignment with this function.

gpiod_line_is_free() to verify a line is available before assignment
gpiod_line_is_used() might be a better one.

also this

gpiod_line_is_requested() to see if you have ownership before using it.