Build a Cheap SvxLink Analog Hotspot with Raspberry Pi, CM108 and Quansheng/Baofeng Radio

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.

Silviu Stroe
I'm Silviu and I run Brainic, a mobile-focused software agency. I'm also a member of Nokia and Yahoo wall of fame. My interests are in low-code/no-code development and bleeding-edge technologies.

Leave a Reply

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