Tuesday 7 July 2020

Talking CAT to my FDM-DUO

I am tinkering with a VERY simple CAT controller for my FDM-DUO. Sending CAT signals to switch Transmit & Receive, sideband selection and for frequency tuning. Of course it may grow into something much more complicated...

CAT commands are sent as ASCII text to the "CAT" USB connection on the FDM-DUO. All commands are terminated with a ";". An Arduino UNO is used, connected via an FTDI serial <-> USB converter.



The CAT commands I need are:

"FA00007100000;" // tune to 7.1MHz 11 characters, "0" padded and frequency in Hz
"TXn;" // transmit where n = 0 is MIC input and n = 1 is USB audio input
"RX;" // receive
"MD1;" and "MD2;" for sideband selection

FREQUENCY
The programming challenge is to store the frequency as a "long" and convert it to ASCII, and pad the string with the right number of '0's before sending it out to the FDM-DUO over a USB link at the default baud rate of 38400.

This is the routine for sending a CAT frequency "FA" command ("cat" is the name of the SoftwareSerial port):

void sendFA(long n) {
  int i;

  String out = String(n, DEC);

  cat.print("FA"); // freq CAT command
  for (i = 0; i < (11 - out.length()); i++) { // add padding
    cat.print("0");
  }
  cat.print(out);
  cat.print(";"); // terminator
}
long 'n' is the required frequency in Hz, which is first converted, as a decimal, to a String "out". Then the command "FA" is printed to the Software Serial Port named "cat" connected to the FDM-DUO. It is prepended with the right number of "0"s to make it up to 11 characters total which are printed followed by the frequency in Hz. Lastly the terminator ";" is sent.

TX/RX
Another simple function prints the CAT strings "TX1;" and "RX;" for transmit (from the USB audio input (change to "TX0;" for MIC input) and for receive:
void sendTRX(bool t) {
  if (t == LOW) cat.print("TX1"); // LOW transmit,  0 = MIC, 1 = USB audio
  else cat.print("RX");
  cat.print(";"); // terminator
}
USB/LSB
This is similar and quite simple (only LSB, USB and CW are implemented)
void sendMODE(int m) {
   switch(m) {
    case 1: cat.print("MD1"); // LSB
    break;
    case 2: cat.print("MD2");
    break;
    case 3: cat.print("MD3");
    break;
   }
  cat.print(";");
}
TESTING
Next step is to wire in a switch for TX/RX and a rotary encoder for frequency tuning, with the option to change the frequency step. Here we go...

Arduino UNO wired up
The UNO has only one +5V line so digital outputs 
(set to HIGH or LOW)
are used to connect VCC & GND to the Switch, Encoder and FDTI

The frequency that can be tuned is currently limited in the code to 7.0 to 7.2MHz, it can be tuned in 10kHz, 1kHz or 100Hz steps. LSB or USB is changed by a long press on the encoder button whereas a short press changes the frequency step.

This is the output on a terminal program on my MacBook:


Bit small, sorry
The output is on the screen is

MD1; // sideband switch by long press
MD2;
FA0000710000; // 7.1MHz tune and +100, +200 Hz
TX1; // transmit using USB audio input
RX; // receive

USB PROBLEMS
USB has beaten me. USB is a serial bus structured as a Master and Slaves. And when I tried to connect my Arduino FTDI USB module to the FDM_DUO USB B CAT it did not work. I connected the FTDI to my MacBook and all was well, as you can see above. I also connected my MacBook to the FDM-DUO CAT USB, and all worked well. So what is going on?

Simple, the FTDI and FDM-DUO are Slaves and my MacBook is a Master.

The Arduino uses an FTDI interface, which acts as a Slave, and the FDM-DUO uses an FD232RL chip, the same as the Arduino interface, so it is also a Slave. Two slaves. So they do not talk to each other. What I need is an interface on the Arduino which acts as a "Host" or Master. And this is a rats nest with lots of products on the Web costing from £5 to £45. Most without any Manuals. And there are libraries too, with difficult to understand functions... it's a mess.

SOLUTION?
 A lot of interest has been generated on the ELAD Group.io forum about USB & CAT. It seems that what is needed is a dedicated USB HOST module, like this one, from Hobbytronics. I have ordered one to try.



The fog is clearing now about USB HOST & SLAVE. To summarise, you need a HOST, normally with a USB A socket, to connect to a SLAVE, normally a USB B socket - like a printer connection. And you need the host to support the Serial FTDI Protocol (there are others for keyboards, mouse, etc). What a struggle it has been just to get that clear.

And now here is my system


At the top you just see the TX/RX toggle switch, under this is the tuning/step encoder , also used for USB/LSB selection. At the bottom is the display of RX/TX, USB/LSB. Frequency and step


Here's a couple of shots of the FDM-DUO screen in TX & RX, and USB & LSB modes.



Obviously it is fairly simple to write other functions to read more inputs and send the ASCII codes to the FDM-DUO.

INPUT/OUTPUT
There are two physical ways to converse with the FDM-DUO CAT. Either the USB B connection or a EXTIO 9 pin connector. This connector has a couple of TX/RX serial data pins. But only the data-in pin can control CAT. If sent a request to send a reply (like "FA;" to get the VFO A frequency), then no data is returned on the 9 pin connector out pin. So the 9 pin can only be one way, into the DUO.  The USB B port on the other hand can be asked to also send out data, for example sending "FA;" will generate an output of "FA00007100000;" or VFO A tuned to 7.1MHz.

The first thing to do is to have a couple of functions to read the data from the DUO. Only two of my three planned functionalities can be read - for some reason the DUO is not able to output it's T/R state! Unless I am missing something...

So for reading the mode (USB, LSB, CW etc) I have this function, read from pos)ition in text string (normally character 2)

text character    0 1 2 3
content           M D 1 ;

read from character position '2', up to finding the terminator ';' Result '1'

int readMODE(int pos) {
  char in[20];
  char out[20];
  int c;

  cat.print("MD;"); // send request for mode
  getCAT(in); // get in response
  c = 0;
  while (in[c] != ';') {
    out[c] = in[c + pos];
    c++;
  }
  out[c] = '\0';
  return atoi(out);
}

Here the issue is that the DUO response to a request for mode information is are ASCII text, and the numerical data must be extracted. All CAT commends start with two letters, followed by 1 to 11 numbers. So "MD;" is sent, to which the DUO responds "MD1,2,3,4,5 or 7 for the modes LSB, USB, CW, FM. AM and CWR. I strip out the two first letters and then convert the remaining number to an integer.

And for the frequency the function is

text character    0 1 2 3 4 5 6 7 8 9 0 1
content           F A 0 0 0 0 7 1 0 0 0 0

read from character position '2', up to finding the terminator ';' Result '1'

long readFA(int pos) {
  char in[20];
  char out[20];
  int c;

  cat.print("FA;"); // send request for FA
  getCAT(in); // get in response
  c = 0;
  while (in[c] != ';') { // skip pos char
    out[c] = in[c + pos];
    c++;
  }
  out[c] = '\0';
  return atol(out);
}

The function getCAT(in) reads a line of text from the DUO.

These functions work vert well and now they must be combined with thesend funciton above to have both the Arduino and the DUO locally to control the parameters, and for either to report the status on the Arduino OLED display.


1 comment:

willie said...

very good! i wanted something similar, so i used a raspberry pi w/LCD touchscreen and the flrig client (which fills the 320x240)... i much prefer the OLED and manual controls though... 72,bill kg4zqz