- The I/O controller (Arduino based)
- The Host controller (X86 processor/windows based)
The Host controller can be realised in numerous ways according to mission requirements. Most likely the station PC or a laptop will be employed but one could equally well use a single board X86 computer built into the same case as the I/O controller et al.
I/O controller (Arduino) architecture
The I/O controller is an Arduino Due or possibly an Arduino Mega, which has the same pin-outs but is a 5V rather than 3.3V processor. Up to two VFO encoders, eight rotary encoders and 32 pushbutton switches can be supported.
The Arduino's function is to provide connectivity to the various physical controls, interpret changes and present the change data to the host processor. This is a relatively simple requirement and the Arduino code is correspondingly straightforward, requiring no complex libraries.
The VFO encoders are high resolution optical rotary encoders, with around 200 to 600 steps per revolution. These provide a quadrature output on two I/O lines that are directly connected to Arduino input pins. Changes on these pins, as a result of turning the VFO encoder create interrupts that are handled by the Arduino. By comparing the relative timing of these interrupts it is possible to determine the direction of rotation.
Rotary encoders are used for controls such as volume, filter width, etc. In fact any control that in a traditional radio would have a control knob. The encoders I use are 24 steps per revolution and that provides adequate resolution at low cost. These encoders are also quadrature output devices and are handled by the Arduino in the same way as VFO inputs.
The pushbutton switches are connected through one or two 1-of-16 multiplexors which considerably reduces the number of I/O pins required (from 32 down to six for a 32 switch configuration). The multiplexer chip is the well known CD74HC4067 but rather than mess with SMDs I decided to use the Sparkfun board, which is inexpensive and does the job perfectly.
Software in the Arduino handles all these inputs and sends a simple message via the USB-derived serial I/O port to the host controller, as shown in the table below.
The Flex API has a typical latency of around 30ms and whilst it is possible to send commands more often there isn't much point. Instead, the I/O controller sends updates every 20ms. So, for example, if VFO A has been turned 20 steps clockwise in the last 20ms then <VA+020; is sent to the host controller. If rotary encoder 3 was turned two steps anticlockwise then <E3-02; is sent. And if Switch 17 is pressed then <S17; is sent.
This simple protocol enables any controller change to be sent quickly and unambiguously to the host controller. Serial I/O is run at 115k baud, so the typical serialisation delay is under 1ms. There are also a small set of commands that the host controller sends to the I/O controller, notably the command to set the LED pushbutton lights used to display VFO status.
Host controller architecture
The host controller is responsible for taking the I/O controller activity and presenting it to the Flex 6000 radio and to the user in the form of an LCD screen. This may not sound like much but it is, in fact, the heavy lifting for the controller project.
The host can be any processor running Windows 7 or above. It takes the simple I/O messages and translates them into commands to the Flex radio. It also takes information from the Flex radio to update the various controls and display information to the user on an 800 x 480 pixel panel that can conveniently displayed on a small 5" LCD screen on the controller physical panel.
To do all this, the host controller has to integrate with the FlexRadio API, which is an Ethernet-based interface. The connection can be wired or Wifi, as required. Between the Flex API and the host controller is another piece of software, the G3WGV API processor. This is a considerable body of code that takes the raw API and turns it into an event-driven interface that the host controller can work with, without needing to know the API architecture in detail. This makes the host controller essentially API agnostic - changes to the API do not affect the host controller software.
Example: tuning the VFO
To illustrate this concept, let us imagine that we are tuning up the band and at this particular instance we have just tuned VFO 0 from 14020.000 to 14020.150kHz. Let us further assume that the VFO step rate is 10Hz per encoder step.
This means that we have turned the VFO knob through 15 steps. The I/O controller handles 15 interrupts on each of the two VFO inputs and by looking at the phase relationship between these interrupts determines that the VFO encoder was turned clockwise.
The I/O controller sends <V0+015; to the host processor.
The host processor knows that, for the current profile,VFO 0 is logical VFO-A and that it was on 14020.000kHz. It calculates that the message from the I/O controller represents 150Hz and that therefore the new frequency will be 14020.150kHz.
The host processor now constructs a message to send to the API processor as follows:
This tells the API processor to set slice 0 to 14020150Hz. Note that the host processor needs to have a way of knowing that VFO A is actually slice 0. We'll come on to that later, for now just assume that it does know.
The API processor now has to construct a message that the radio's API will understand. This is what it will sent to the API:
CDnnnn|slice tune 0 14.020150
C means that this is a command
D, if present, means that we want diagnostic information to be returned
nnnn is a sequential number that is incremented for each command sent to the radio
0 is the slice
14.020150 is the frequency in MHz.
When the radio has processed this command, it will respond with
This response indicates that command number nnnn has been processed OK. There are other possible responses if, for any reason, the command cannot be executed and in that case <diagnostic info> may contain additional information.
The API processor is responsible for managing all the command sequencing and response handling. The host controller has no need to be involved in this low level activity.
Next, the host processor needs to update the user's display to show that the frequency has indeed changed. All this happens in a few milliseconds which is fast enough that the user's impression is of smooth tuning, just the same as a normal VFO.
As you can see, there is quite a lot going on. You can find out more about the API protocol and how the API processor deals with radio events by reading my API Primer.
Mapping controls to Flex functions
One of the fascinating opportunities offered by the controller architecture is the ability to map particular physical controls to a specific control function. So, for example, the left-most encoder on the front panel might be the volume for VFO A. Or it might be something completely different. We can also envisage having several different logical panel layouts for a given physical layout, that can be selected at will. This could even be an operator preference, so, for example, a left-handed operator might chose to swap VFO-A and VFO-B.
As far as the controller software is concerned, there is no relationship between a physical control and a radio control function. Instead, a profile is loaded by the software to create the relationships as required. The controller can have multiple profiles, so you might have a profile for contests and another for DXing, calling into operation the appropriate control functions and mapping them to the physical control of your choice.
The subject of control mapping and profiles is sufficiently complex and fundamental to warrant its own section. For now it is sufficient to know that the concept exists as part of the controller architecture.