Myon's Ham Radio BlogChristoph Berg's Bloghttps://www.df7cb.de/blog/tag/afu.htmlChristoph Berg's Blogikiwiki2023-08-26T21:29:23ZGetting I/Q SDR data from Icom IC-7610's USB 3 port using libftd3xxhttps://www.df7cb.de/blog/2023/ic7610ftdi.html2023-08-26T21:29:23Z2023-08-26T21:29:23Z
<p>I had been looking around for some time if someone had already managed to get
I/Q data from Icom's IC-7610 HF transceiver without going through the
binary-only hdsdr driver provided by Icom, but couldn't find anything.</p>
<p>First attempts at doing that on Debian Linux using libftdi1 didn't work, so I
resorted to using the (again binary-only) libftd3xx driver from FT, and
succeeded after some tinkering around.</p>
<p>The program writes raw I/Q data to a file in int16-int16 format.</p>
<ul>
<li>ic7610ftdi: https://github.com/df7cb/ic7610ftdi</li>
<li>Get libftd3xx from https://ftdichip.com/drivers/d3xx-drivers/</li>
<li>IC-7610 I/Q port reference: https://www.icomjapan.com/support/manual/1792/</li>
<li>The IC-7610 needs to be connected using a decent USB 3 cable, preferably without any hub in-between</li>
<li>If the SuperSpeed-FIFO Bridge disappears after some time, re-plug the cable or power-cycle the transceiver</li>
</ul>
<pre><code>$ lsusb | grep IC
Bus 002 Device 024: ID 0c26:0029 Prolific Technology Inc. IC-7610 SuperSpeed-FIFO Bridge
$ make
cc -Wall -g -c -o ic7610ftdi.o ic7610ftdi.c
cc ic7610ftdi.o -lftd3xx -o ic7610ftdi
$ ./ic7610ftdi iq.cs16
Device[0]
Flags: 0x4 [USB 3] | Type: 600 | ID: 0x0C260029
SerialNumber=23001123
Description=IC-7610 SuperSpeed-FIFO Bridge
fe fe 98 e0 1a 0b fd ff
fe fe e0 98 1a 0b 00 fd IQ data output: 0
fe fe 98 e0 1a 0b 01 fd
fe fe e0 98 fb fd ff ff OK
RX 42 MiB ^C
fe fe 98 e0 1a 0b 00 fd
fe fe e0 98 fb fd ff ff OK
$ ls -l iq.cs16
-rw-rw-r-- 1 myon myon 44040192 26. Aug 22:37 iq.cs16
$ inspectrum -r 1920000 iq.cs16 &
</code></pre>
UDP port forwarding with iptables and fermhttps://www.df7cb.de/blog/2022/udp-portforwarding.html2022-08-07T21:27:52Z2022-08-07T21:27:52Z
<p>To talk to my IC-7610 via wireguard, I set up UDP port forwarding for ports 50001 50002 50003 on a raspi:</p>
<pre><code>domain (ip) {
table filter {
chain FORWARD {
policy ACCEPT;
}
}
table nat {
chain PREROUTING {
interface (wg0) {
proto udp dport 50001 DNAT to 192.168.0.6;
proto udp dport 50002 DNAT to 192.168.0.6;
proto udp dport 50003 DNAT to 192.168.0.6;
}
}
chain POSTROUTING {
outerface (eth0) {
proto udp dport 50001 SNAT to-source 192.168.0.3;
proto udp dport 50002 SNAT to-source 192.168.0.3;
proto udp dport 50003 SNAT to-source 192.168.0.3;
}
}
}
}
</code></pre>
LoRa APRS iGate on TTGO LoRa32https://www.df7cb.de/blog/2022/lora-aprs-igate.html2022-04-23T10:37:29Z2022-04-01T08:49:04Z
<h1>LoRa APRS iGate</h1>
<p>The official documentation of
<a href="https://github.com/lora-aprs/LoRa_APRS_iGate">https://github.com/lora-aprs/LoRa_APRS_iGate</a>
uses the PlatformIO plugin of MS Visual Studio Code. Here are the commands to
get it running without the GUI:</p>
<pre><code>git clone https://github.com/lora-aprs/LoRa_APRS_iGate.git
cd LoRa_APRS_iGate
</code></pre>
<ul>
<li>Edit data/is-cfg.json with your station info</li>
<li>Edit platformio.ini: <code>board = ttgo-lora32-v21</code></li>
</ul>
<pre><code>pip3 install platformio
pio run
...
Building .pio/build/lora_board/firmware.bin
...
pio run --target upload
...
Uploading .pio/build/lora_board/firmware.bin
...
pio run --target uploadfs
...
Building SPIFFS image from 'data' directory to .pio/build/lora_board/spiffs.bin
/is-cfg.json
...
Uploading .pio/build/lora_board/spiffs.bin
...
</code></pre>
<h1>LoRa APRS Tracker</h1>
<p>The procedure for the tracker is the same, but the GPS module might need a
reset first:</p>
<pre><code>git clone https://github.com/lora-aprs/TTGO-T-Beam_GPS-reset.git
cd TTGO-T-Beam_GPS-reset
pio run -e ttgo-t-beam-v1
pio run --target upload -e ttgo-t-beam-v1
# screen /dev/ttyACM0 115200
</code></pre>
<p>... and then upload https://github.com/lora-aprs/LoRa_APRS_Tracker.git</p>
Iambic CW keyer based on DigiSpark, MIDI, and PulseAudio on Linuxhttps://www.df7cb.de/blog/2022/midicwkeyer.html2022-03-23T17:55:11Z2022-03-23T17:53:16Z
<p>Classic ham radio transceivers have physical connectors for morse keys and
microphones. When the transceiver is a software defined radio (SDR) device,
voice operation is easy by attaching a headset, but solutions to connect a
morse key, be it a straight key or paddles, to a modern PC are rare. In the old
times, machines had serial ports with RTS/DTR lines, but these do not exist
anymore, so a new interface is needed.</p>
<p>I am using a LimeSDR as ground station for the QO-100 satellite, and naturally
also wanted to do CW operation there. I started with SDRangel which has a
built-in morse generator, but naturally wanted to connect a CW key. At first
sight, all the bits are there, there's a tune button that could be used as a
straight key, as well as keyboard bindings for dots and dashes. But the delay
key->local audio is almost a full second, so that's a no-go. I then went to
hack my K3NG keyer to output ^ (high) _ (low) signals on the USB interface, and
have a smallish Python program read that and send SDRangel REST API requests.
Works, but that solution always felt "too big" to me, plus the sidetone from
the buzzer inside the Arduino case could be heard in the whole house. And the
total TX-RX delay was well over a second.</p>
<p>Next I tried building some GNU Radio flowcharts to solve the same problem but
which all had the same trouble that the buffers grew way too big to allow the
sidetone to be used for keying. At the same time, I switched the transceiver
from SDRangel to another GR flowchart which reduced the overall TX-RX delay to
something much shorter, but the local audio delay was still too slow for CW.</p>
<p>So after some back and forth, I came up with this solution: the external
interface from the CW paddles to the PC is a small DigiSpark board programmed
to output MIDI signals, and on the (Linux) PC side, there is a Python program
listening for MIDI and acting as a iambic CW keyer. The morse dots and dashes
are uploaded as "samples" to PulseAudio, where they are played both on the
local sidetone channel (usually headphones) and on the audio channel driving
the SDR transceiver. There is no delay. :)</p>
<h2>DigiSpark hardware</h2>
<p>The DigiSpark is a very small embedded computer that can be programmed using
the Arduino toolchain.</p>
<p>Of the 6 IO pins, two are used for the USB bus, two connect the dit and dah
lines of the CW paddle, one connects to a potentiometer for adjusting the
keying speed, and the last one is unconnected in this design, but could be used
for keying a physical transceiver. (The onboard LED uses the this pin.)</p>
<pre><code> +---------------+
| P5 o -- 10k potentiometer middle pin
===== Attiny85 P4 o -- USB (internal)
USB ----- P3 o -- USB (internal)
----- P2 o -- dah paddle
===== 78M05 P1 o -- (LED/TRX)
| P0 o -- dit paddle
+---o-o-o-------+
</code></pre>
<p>There is an extra 27 kΩ resistor in the ground connection of the potentiometer
to keep the P5 voltage > 2.5 V, or else the DigiSpark resets. (This could be
changed by blowing some fuses, but is not necessary.)</p>
<p><img src="https://www.df7cb.de/blog/2022/digisparkkeyer.jpg" alt="DigiSpark keyer" /></p>
<p>The <a href="https://www.df7cb.de/blog/tag/midicwkeyer.ino">Arduino sketch</a> for the keyer uses the
<a href="https://github.com/heartscrytech/DigisparkMIDI">DigisparkMIDI library</a>.
The code is quite simple: if the paddles are pressed, send a MIDI note_on event
(dit = note 1, dah = note 2), when released, send note_off. When the
potentiometer is changed, send a control_change event (control 3), the value
read is conveniently scaled to wpm speed values between 8 and 40.</p>
<pre><code> if (dit)
midi.sendNoteOn(NOTE_DIT, 1);
else
midi.sendNoteOff(NOTE_DIT, 0);
if (dah)
midi.sendNoteOn(NOTE_DAH, 1);
else
midi.sendNoteOff(NOTE_DAH, 0);
if (new_speed != old_speed)
midi.sendControlChange(CHANNEL_SPEED, new_speed);
</code></pre>
<p>The device uses a generic USB id that is recognized by Linux as a MIDI device:</p>
<pre><code>$ lsusb
Bus 001 Device 008: ID 16c0:05e4 Van Ooijen Technische Informatica Free shared USB VID/PID pair for MIDI devices
$ amidi -l
Dir Device Name
IO hw:2,0,0 MidiStomp MIDI 1
$ aseqdump -l
Port Client name Port name
24:0 MidiStomp MidiStomp MIDI 1
$ aseqdump --port MidiStomp
Source Event Ch Data
24:0 Control change 0, controller 3, value 24
24:0 Note on 0, note 1, velocity 1
24:0 Note on 0, note 2, velocity 1
24:0 Note off 0, note 1, velocity 0
24:0 Note off 0, note 2, velocity 0
24:0 Control change 0, controller 3, value 25
24:0 Control change 0, controller 3, value 26
</code></pre>
<h2>Python and PulseAudio software</h2>
<p>On the Linux host side, a <a href="https://www.df7cb.de/blog/tag/midicwkeyer.py">Python program</a> is listening for
MIDI events and acts as a iambic CW keyer that converts the stream of note
on/off into CW signals.</p>
<p>Instead of providing a full audio stream, dit and dah "samples" are uploaded to
PulseAudio, and triggered via the
<a href="https://github.com/mk-fg/python-pulse-control">pulsectl library</a>.
On speed changes, new samples are uploaded.
The samples are played on two channels, one for the sidetone on the operator
headphones, and one on the audio input device for the SDR transmitter.</p>
<p><img src="https://www.df7cb.de/blog/2022/cw050.png" alt="24 wpm dit (50 ms)" /></p>
<p>The virtual "tx0" audio device can be created on boot using this systemd config
snippet:</p>
<pre><code># $HOME/.config/systemd/user/pulseaudio.service.d/override.conf
[Service]
ExecStartPost=/usr/bin/pacmd load-module module-null-sink sink_name=tx0 sink_properties=device.description=tx0
</code></pre>
<p>The CW text sent is printed on stdout:</p>
<pre><code>$ ./midicwkeyer.py
TX port is tx0 (3)
Sidetone port is Plantronics Blackwire 3225 Series Analog Stereo (7)
CQ CQ DF7CB
</code></pre>
<h2>Download</h2>
<p>Needless to say, this is open source:
<a href="https://github.com/df7cb/df7cb-shack/tree/master/midicwkeyer">https://github.com/df7cb/df7cb-shack/tree/master/midicwkeyer</a></p>
DARC Xmas Contest 2006https://www.df7cb.de/blog/2007/DARC-Xmas.html2011-02-17T12:21:52Z2007-01-10T11:35:54Z
<p>For years, the Xmas contest has virtually been my only ham radio activity. This
year, after I had to take down the antenna in my parents' yard, I put up the
40m part of a 80/40m dipole in the attic of my flat in Saarbrücken. The first
tests were satisfying so I drove back to Saarbrücken for December 26th.</p>
<p><p>
The contest started nice with a S9+50 signal from DR5S - of course DOK Q10
meant it was just very close. Unfortunately, things turned out much worse. The
antenna wasn't as matched as I had hoped and I had to put my small MFJ tuner
in. But, whatever I would tune to, the 1:1 would only withstand some second of
transmission and I had to retune. The 1:1 there would pop back up, and I had to
retune back to the original settings. GOTO 10.</p>
<p><p>
After a bit more than one hour I gave up. The final log is here:</p>
<p><p>
<table>
<tr><td>8.33</td><td>3.543</td><td>DR5S</td><td>599 Q02</td><td>599 Q10</td></tr>
<tr><td>8.42</td><td>7.016</td><td>DL0CS</td><td>599 Q02</td><td>599 M15</td></tr>
<tr><td>8.43</td><td>7.016</td><td>G4OGD</td><td>599 Q02</td><td>599 004</td></tr>
<tr><td>8.50</td><td>7.013</td><td>OK5MM</td><td>599 Q02</td><td>599 019</td></tr>
<tr><td>9.38</td><td>3.545</td><td>DK9IP</td><td>599 Q02</td><td>599 A24</td></tr>
</table></p>
<p><p>
I don't know where the fault was, in the TRX, the tuner, or the antenna. I hope
it is not the TRX.</p>