This tutorial shows how I built a low-cost analog SvxLink hotspot using a Raspberry Pi 3B+, a CM108 USB sound card, a Quansheng/Baofeng-style handheld radio and a small 2N7000 transistor interface.
The project is inspired by Marcin’s original “SvxPi_Qhs – The cheapest svxlink hotspot” article.
Marcin’s idea was to make the cheapest possible working analog hotspot using a handheld radio. My build follows the same practical spirit, but uses a Raspberry Pi 3B+ and a protected GPIO interface for both PTT and SQL/COS.
What this hotspot does
The node works like this:
local handheld → hotspot radio → Raspberry Pi → SvxReflector
SvxReflector → Raspberry Pi → hotspot radio → local RF
This is a personal simplex hotspot, not a wide-area repeater. The goal is stable local coverage with low power and clean audio.
Parts used
Raspberry Pi 3B+
CM108 USB sound card
Quansheng/Baofeng-style handheld radio
Kenwood 2-pin pigtail cable
Small protoboard
2× 2N7000 TO-92 MOSFET
Resistors: 1k, 4.7k/5.1k, 10k
30 AWG wire-wrap wire
Ferrite clips
Battery eliminator for the radio
The tested pigtail had this wiring:
RED = 3.5 mm ring = MIC+
YELLOW = 2.5 mm tip = SPK+
WHITE = 2.5 mm sleeve = GND / SPK-
BLACK = 3.5 mm sleeve = PTT / MIC-
Always verify your own pigtail with a multimeter before soldering.
Hardware concept
The interface uses two 2N7000 MOSFETs:
2N7000 #1 = PTT control
2N7000 #2 = SQL/COS protection
The Raspberry Pi does not directly short the radio PTT line. GPIO17 drives a 2N7000, and the MOSFET pulls the radio PTT line to ground.
The SQL/COS signal is taken from the radio SPK+ line. Because this can be too high for a Raspberry Pi GPIO, it is also passed through a 2N7000. This makes the GPIO input protected and active-low.
Final logic:
PTT: GPIO17 HIGH → radio transmits
SQL: no signal → GPIO16 HIGH
SQL: signal active → GPIO16 LOW
2N7000 pinout
For a standard 2N7000 TO-92, flat side facing you, legs down:
1 = Source
2 = Gate
3 = Drain
Verify your own components before soldering.
Final wiring
Common ground
All grounds must be common:
WHITE pigtail
Raspberry Pi GND
CM108 GND
2N7000 PTT Source
2N7000 SQL Source
PTT circuit
2N7000 PTT:
Source → GND
Gate → GPIO17 through 4.7k/5.1k
Gate → GND through 10k pull-down
Drain → BLACK pigtail / radio PTT
Raspberry Pi pin:
GPIO17 = physical pin 11
SQL/COS circuit
2N7000 SQL:
Source → GND
Gate → YELLOW / SPK+ through 4.7k/5.1k
Drain → GPIO16
GPIO16 → 10k pull-up to 3.3V
Raspberry Pi pins:
GPIO16 = physical pin 36
3.3V = physical pin 1
GND = physical pin 6
Audio wiring
CM108 SPK OUT → 1k → RED / MIC+
YELLOW / SPK+ → CM108 MIC IN
If RX audio is too loud or distorted, add attenuation:
YELLOW / SPK+ → 10k → CM108 MIC IN
GPIO tests
Before starting SvxLink, test PTT manually.
PTT off:
sudo pinctrl set 17 op dl
pinctrl get 17
PTT on:
sudo pinctrl set 17 op dh
PTT off again:
sudo pinctrl set 17 op dl
Test SQL/COS:
pinctrl get 16
Expected result:
no signal → GPIO16 hi
with signal → GPIO16 lo
ALSA audio device
The CM108 appeared as:
card 1: USB PnP Sound Device, device 0
So SvxLink uses:
AUDIO_DEV=alsa:plughw:1,0
Check with:
aplay -l
arecord -l
Working SvxLink configuration
This is the core working configuration.
[GLOBAL]
LOGICS=SimplexLogic,ReflectorLogic
CFG_DIR=svxlink.d
TIMESTAMP_FORMAT="%c"
CARD_SAMPLE_RATE=48000
LINKS=ReflectorLink
[SimplexLogic]
TYPE=Simplex
RX=Rx1
TX=Tx1
MODULES=
CALLSIGN=YO6SAY-R
EVENT_HANDLER=/usr/share/svxlink/events.tcl
DEFAULT_LANG=en_US
RGR_SOUND_DELAY=0
SHORT_IDENT_INTERVAL=0
LONG_IDENT_INTERVAL=0
MUTE_RX_ON_TX=1
MUTE_TX_ON_RX=1
FX_GAIN_NORMAL=0
FX_GAIN_LOW=-12
MACROS=Macros
QSO_RECORDER=:QsoRecorder
[ReflectorLogic]
TYPE=ReflectorV2
HOSTS=svx.145500.xyz
HOST_PORT=5337
CALLSIGN=YO6SAY-R
AUTH_KEY="p@ssw0rd"
JITTER_BUFFER_DELAY=200
AUDIO_CODEC=OPUS
EVENT_HANDLER=/usr/share/svxlink/events.tcl
DEFAULT_LANG=en_US
DEFAULT_TG=9
MONITOR_TGS=9
TG_SELECT_TIMEOUT=3600
[ReflectorLink]
CONNECT_LOGICS=SimplexLogic:9:TG,ReflectorLogic
DEFAULT_ACTIVE=1
TIMEOUT=0
[Rx1]
TYPE=Local
AUDIO_DEV=alsa:plughw:1,0
AUDIO_CHANNEL=0
AUDIO_DEV_KEEP_OPEN=1
SQL_DET=GPIOD
SQL_GPIOD_CHIP=/dev/gpiochip0
SQL_GPIOD_LINE=!16
SQL_GPIOD_BIAS=PULLUP
SQL_START_DELAY=1000
SQL_DELAY=500
SQL_HANGTIME=100
SQL_TIMEOUT=180
DEEMPHASIS=0
DTMF_DEC_TYPE=INTERNAL
DTMF_MUTING=1
DTMF_HANGTIME=40
[Tx1]
TYPE=Local
AUDIO_DEV=alsa:plughw:1,0
AUDIO_CHANNEL=0
AUDIO_DEV_KEEP_OPEN=1
PTT_TYPE=GPIOD
PTT_GPIOD_CHIP=/dev/gpiochip0
PTT_GPIOD_LINE=17
TX_DELAY=300
TIMEOUT=180
PREEMPHASIS=0
[Macros]
Important notes:
SQL_GPIOD_LINE=!16 because SQL is active-low.
/dev/gpiochip0 worked correctly on this Raspberry Pi 3B+ setup.
Fixing the squelch-tail problem
During testing, the node sometimes produced a short unwanted tail after retransmitting audio from the reflector.
The log pattern looked like this:
Tx1: Turning the transmitter OFF
Rx1: The squelch is OPEN
ReflectorLogic: Talker start on TG #9: YO6SAY-R
This means the local radio/interface briefly detected false RX after TX stopped.
The practical fix was SQL timing:
SQL_START_DELAY=1000
SQL_DELAY=500
SQL_HANGTIME=100
SQL_TIMEOUT=180
What these do:
SQL_START_DELAY=1000 → ignore squelch for 1 second after TX stops
SQL_DELAY=500 → accept SQL only after 0.5 seconds stable
SQL_HANGTIME=100 → keep RX tail short
SQL_TIMEOUT=180 → protect against stuck RX
If tail still happens, increase gradually:
SQL_START_DELAY=1500
Then, only if needed:
SQL_START_DELAY=2000
Do not jump too high if people reply quickly, because fast local replies may be clipped.
Audio level tuning
There are two audio paths.
Local RF to reflector
local radio → hotspot radio → CM108 MIC IN → SvxLink → reflector
Affected by:
Quansheng volume
CM108 Mic/Capture level
AGC setting
possible 10k attenuation on SPK+ → MIC IN
Recommended starting point:
Quansheng volume: 10–25%
CM108 Mic/Capture: 20–30
AGC: OFF
Use:
alsamixer
Then save:
sudo alsactl store
To check input level:
arecord -D plughw:1,0 -f S16_LE -r 48000 -c 1 -vv /dev/null
The meter should move clearly but not stay at maximum.
Reflector to local RF
reflector → SvxLink → CM108 SPK OUT → radio MIC+ → RF
Affected by:
CM108 Speaker level
radio Mic dB setting
TX audio resistor
On IJV firmware, Mic dB +12 dB may be too high. A safer starting point is:
Mic dB +6 dB
Then adjust by listening.
Recommended Quansheng node settings
For the radio used as the node:
Power: LOW or minimum needed
VOX: OFF
Dual Watch: OFF
Scan: OFF
Battery Save: OFF
Roger Beep: OFF
Key Beep: OFF
PTT ID: OFF
DTMF ID: OFF
Compander: OFF
Scrambler: OFF
TOT: ON
Tx STE: ON
Rx STE: around 2×100 ms
Squelch: stable, not too low
CTCSS: recommended if needed
The node radio should be predictable and silent. Disable anything that can generate tones, IDs or automatic beeps.
Ferrites and RF noise
Ferrites helped reduce digital/RF noise.
Best locations:
1. Kenwood pigtail, close to the interface board
2. Raspberry Pi power cable, close to the Pi
3. USB cable to CM108, if used
4. GPIO wire bundle
The most important ferrite is on the pigtail near the interface.
Start SvxLink automatically
Enable the service:
sudo systemctl enable svxlink
sudo systemctl start svxlink
sudo systemctl status svxlink
Force PTT off before SvxLink starts:
sudo systemctl edit svxlink
Add:
[Service]
ExecStartPre=/usr/bin/pinctrl set 17 op dl
Then:
sudo systemctl daemon-reload
sudo systemctl restart svxlink
Optional: QSO recording
Add to [SimplexLogic]:
QSO_RECORDER=:QsoRecorder
Add:
[QsoRecorder]
REC_DIR=/var/spool/svxlink/qso_recorder
MIN_TIME=1000
MAX_TIME=1800
SOFT_TIME=60
DEFAULT_ACTIVE=1
TIMEOUT=0
QSO_TIMEOUT=10
ENCODER_CMD=/usr/bin/opusenc "%f" "%d/%b.opus" 2>/dev/null && rm "%f"
Install OPUS tools:
sudo apt install -y opus-tools
Create the recording directory:
sudo mkdir -p /var/spool/svxlink/qso_recorder
sudo chown -R svxlink:svxlink /var/spool/svxlink/qso_recorder
sudo chmod 775 /var/spool/svxlink/qso_recorder
To delete recordings older than 30 days:
sudo nano /etc/cron.daily/svxlink-qso-cleanup
Add:
#!/bin/sh
find /var/spool/svxlink/qso_recorder -type f -name 'qsorec_*' -mtime +30 -delete
Enable it:
sudo chmod +x /etc/cron.daily/svxlink-qso-cleanup
Final notes
This build worked after solving several real-world problems:
PTT stuck because GPIO17 was left high during testing
SQL/COS needed active-low configuration
GPIOD needed /dev/gpiochip0
SQL bias had to be PULLUP
TG0 timeout needed TG_SELECT_TIMEOUT=3600
Audio needed careful Mic/Speaker tuning
Squelch tail needed SQL timing adjustments
The most important final settings were:
SQL_GPIOD_LINE=!16
SQL_START_DELAY=1000
SQL_DELAY=500
SQL_HANGTIME=100
SQL_TIMEOUT=180
PTT_GPIOD_LINE=17
This is a cheap, practical and working analog SvxLink hotspot inspired by Marcin’s original low-cost concept, but adapted and debugged on a Raspberry Pi 3B+ with a protected 2N7000 GPIO interface.