LA1K / LA100K / LA1UKA

Controlling a SteppIR SDA 100 controller from Python

Some time back, we acquired a BigIR antenna. This antenna can automatically tune itself to some optimal length according to the desired frequency. For extra convenience, the controller of the antenna can be made to track the current frequency of the transceiver. Our current transceiver setup makes this a bit of an hassle, however, since we want all our transceivers to have the possibility to transmit on all antennas, and this would require a rather weird CAT (computer assisted transceiver) network.

We therefore wanted to develop a software-based system more suited for our needs. Before we could do that, we needed to be able to arbitrarily control the SDA 100 controller from a computer.

Late Saturday afternoon struggles

We first thought we would have to emulate a radio and implement full CAT control for this fake radio system that then could communicate with SDA100 through SDA100’s transceiver interface. We got as far as creating the directory fake_transceiver and open ic9100.c in the Hamlib source code in order to figure out how CAT is implemented on the other end, until LA3WUA Øyvind luckily found out from the specifications that a far simpler communication protocol is available.

Connecting a standard crossed serial cable from a computer to the “Data OUT” port makes a serial interface available. Here, we’d just have to send ?A\r in order to obtain the current frequency, and @A\r followed by a hexadecimal representation of the frequency in order to set the current frequency. Perfect! A simple interface for simple people like us. We found some closed-source GUI software programs like PstRotatorAz that had this implemented, but did not really fit our purposes. We therefore borrowed a serial cable and serial-to-USB-converter from our local information technology committee, and set up a serial interface in order to hack together something ourselves.

Despite some failure, we finally managed to send ?A\r to the controller and get @A\x00\x15\x7f\xe8\x00\x179c\r back. Out of desperation, we also found that sending the exact same string back would set 1409000 as the frequency if the controller was at another frequency, which meant we’d only have to figure out what to replace and not have to decipher the entire documentation. After a wild ride, we were able to figure out that 1409000 could reproduce \x00\x15\x7f\xe8 by struct.pack('>i', 1409000), and we were able to successfully both set and get frequencies to and from the controller.

Since we had such difficulty finding working examples except for closed source binary applications from Windows (which were, however, helpful in verifying that remote control of SDA100 worked fine), we are making our code available on GitHub for others to find when they start having the same desires and/or frustrations as us.

Software implementation

The Python module we’ve developed can be found here: https://github.com/bjorgan/steppir. We plan to use this for a system where we’ll sniff the current desired frequency from N1MM or similar and push it to SDA100 when desired.

We create a serial interface by

import serial
ser = serial.Serial("/dev/ttyUSB0", 9600)

and ask for the current frequency by

ser.write(b'?A\r')

This produces 11 bytes which can be read by

message = ser.read(11)

The actual frequency is located at zero-indexed positions 2-5, while the other bytes are related to motor status and versioning. Converting the frequency bytes to an understandable number can be done by

import struct
frequency = struct.unpack('>i', message[2:6])[0]

which would be in deca-Hertz. This is converted to Hertz by multiplying by 10.

Setting a new frequency is simply done by converting a given frequency to a hexadecimal byte array by

hex_freq = struct.pack('>i', int(frequency))

and then constructing a set command by

cmd = b'@A' + hex_freq + b'\x00\x179c\r'

We obtained the last part (\x00\x179c) from messages we got back from the controller. We didn’t bother figuring out how to construct valid bytes here since the documentation was confusing and that set of bytes apparently worked fine. B)

Finally, we’ve encapsuled the above code in a Python module, so that you’d just have to clone the GitHub repository, install the module according to the README and then set and get frequencies by its more high-level interface. Happy length adjustment!

4 Comments

  1. Curt Mills

    Has any additional work been done on this code by the original authors?

    I’ve worked on it for the last few days and have fully-decoded the returned data except for the busy-motors byte: That’s confusing in the documentation and I don’t need to make use of it anyway. I’ve also added code to control every function that the controller allows and it all works.

    However, I’ve seen serial commands hang occasionally, and seen button-change commands sometimes fail to take effect. I’ll be adding serial timeouts as well as command retries, checking status after each command to verify that the commands stick. I’d also like create an upper-level script with a UDP server, plus a separate GUI that can control it which simulates the front panel. I also need a link-up between my SDR software and this Python combo so the antenna tracks the current frequency. My end goal is to relocate the SteppIR controller to the base of the tower and control it remotely over ethernet from the shack.

    • LA9SSA

      Nice! 🙂 We didn’t do much more with the code, but great to hear that you found use for our initial prototype and have taken it much further.

  2. Hong Park

    EX:
    Check current frequency 3F 41 0D
    Set frequency to 18.150mhz 40 41 00 1B B1 D8 00 05 30 00 0D
    Home the elements 40 41 00 1B B1 D8 00 05 53 00 0D

    I wonder
    HI want to know about AUTOTRACK ON/OFF ?
    Is there a command for POWER ON/OFF ?

    • HamChuck

      I’m also trying to find the command to turn AutoTrack on/off. Have you found anything?

Leave a Reply to Curt Mills Cancel reply

Your email address will not be published. Required fields are marked *