Skip to content

Latest commit

 

History

17 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

advmesh

A lightweight mesh networking utility for Raspberry Pi. Provides text and voice communication between ARM64 devices over UDP or LoRa radio, using Codec2 for low-bitrate speech encoding and direct Linux kernel ioctls for PCM audio (no ALSA userspace library).

Prerequisites

  • Windows with Visual Studio (C++ Linux Development workload)
  • WSL2 (Ubuntu) with the ARM64 cross-compiler and autotools:
    sudo apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu cmake make autoconf automake libtool
  • Raspberry Pi targets running Linux (ARM64)

Getting Started

Clone the repository and pull submodules:

git clone <repo-url>
cd advmesh
git submodule update --init --recursive

Building Dependencies

All third-party libraries live as git submodules under extern/ and are cross-compiled for ARM64 via WSL2. A single script handles everything:

.\build_deps.ps1                  # Build all dependencies
.\build_deps.ps1 -Name codec2     # Build a specific dependency
.\build_deps.ps1 -Clean           # Clean rebuild all

This configures, builds, and installs each dependency to extern/<name>/install_arm64/, which the Visual Studio project references for headers and libraries.

To add a new dependency:

  1. git submodule add <url> extern/<name>
  2. Optionally add CMake overrides to $DependencyOptions in build_deps.ps1
  3. Add the dependency's install paths to advmesh.vcxproj

Building the Project

Open advmesh.slnx in Visual Studio and build using one of the four configurations:

Configuration Toolchain Use Case
Debug | ARM64 WSL2 cross-compile (aarch64-linux-gnu-g++) Development from Windows
Release | ARM64 WSL2 cross-compile (aarch64-linux-gnu-g++) Optimized build from Windows
Pi Debug | ARM64 Native on-device Building directly on the Pi
Pi Release | ARM64 Native on-device Optimized build on the Pi

Output binary: bin/ARM64/<Configuration>/advmesh.out

Note: For Pi Debug/Pi Release configs (built on-device), install dependencies natively: sudo apt install libcodec2-dev

Deploying

Deploy the compiled binary to one or more Raspberry Pi targets:

.\deploy.ps1                                    # Deploy local Debug to both Pis
.\deploy.ps1 -Rebuild                           # Rebuild then deploy
.\deploy.ps1 -Flavor release -Rebuild           # Rebuild Release then deploy
.\deploy.ps1 -Targets advmesh1                  # Deploy to a specific Pi
.\deploy.ps1 -Source remote -Flavor release      # Deploy Pi Release build

Usage

./advmesh.out <remote_ip> [remote_port] [local_port]
./advmesh.out --lora [options]

UDP Mode

Example — two Pis talking to each other on port 9000:

# On Pi 1 (10.0.0.232)
./advmesh.out 10.0.0.108 9000 9000

# On Pi 2 (10.0.0.108)
./advmesh.out 10.0.0.232 9000 9000

LoRa Mode

Uses the Waveshare SX1262 LoRa HAT connected via UART and GPIO.

# Default settings (915.125 MHz, 2.4kbps air rate, 22dBm TX power)
./advmesh.out --lora

# Custom channel and UART device
./advmesh.out --lora --uart /dev/serial0 --channel 72

# Custom GPIO pins (non-standard HAT wiring)
./advmesh.out --lora --m0-pin 5 --m1-pin 6 --aux-pin 13

LoRa Options

Flag Default Description
--uart <device> /dev/ttyAMA0 UART device path
--baud <rate> 115200 UART baud rate
--channel <0-83> 65 LoRa channel (freq = 850.125 + ch MHz)
--power <0-3> 0 TX power: 0=22dBm, 1=17dBm, 2=13dBm, 3=10dBm
--air-rate <0-7> 3 Air data rate (3 = 4.8 kbps)
--sub-packet <0-3> 2 Sub-packet size: 0=240B, 1=128B, 2=64B, 3=32B
--address <0-65535> 0 Module address (0 = broadcast)
--net-id <0-255> 0 Network ID
--gpio-chip <dev> /dev/gpiochip0 GPIO character device
--m0-pin <pin> 22 M0 GPIO pin number
--m1-pin <pin> 27 M1 GPIO pin number
--aux-pin <pin> 17 AUX GPIO pin number

Wiring (Waveshare SX1262 LoRa HAT)

The HAT plugs directly onto the Raspberry Pi 40-pin header. Key connections:

HAT Pin Pi GPIO Function
M0 GPIO 22 Mode control bit 0
M1 GPIO 27 Mode control bit 1
AUX GPIO 17 Module busy/ready indicator
TXD GPIO 14 (UART TX) Serial data to module
RXD GPIO 15 (UART RX) Serial data from module
VCC 3.3V / 5V Power supply
GND GND Ground

Note: On Raspberry Pi, disable the serial console and enable the UART interface:

sudo raspi-config  # Interface Options → Serial Port → No console, Yes UART

Type messages and press Enter to send. Type /quit to exit.

Voice Mode

Switch between text and voice modes at runtime:

Command Action
/voice Enter voice mode — captures audio from microphone, encodes with Codec2, and transmits over UDP. Incoming voice is played through the speaker. Full-duplex.
/transmit Enter transmit mode — captures audio, encodes with Codec2, batches frames, and streams over radio. Half-duplex push-to-talk.
/receive Enter receive mode — listens for incoming voice stream, decodes, and plays through speaker. Half-duplex.
/stop Exit any voice/transmit/receive mode, return to text.
/text Same as /stop — return to text mode.
/quit Exit the application.

/voice uses Codec2 at 3200 bps (full-duplex, best for UDP). /transmit and /receive auto-select codec mode based on radio type:

Radio Codec Mode Batch Latency
UDP 3200 bps 1 frame (20ms) ~20ms
LoRa 700C bps 8 frames (320ms) ~320ms

LoRa Voice Streaming

For voice over LoRa, use /transmit on one Pi and /receive on the other:

# Pi 1 (transmitter)
./advmesh.out --lora --baud 115200 --sub-packet 2
# Type: /transmit

# Pi 2 (receiver)
./advmesh.out --lora --baud 115200 --sub-packet 2
# Type: /receive

The stream protocol uses three packet types:

  1. StreamInit — announces codec mode, batch size, sample rate
  2. StreamData — 3-byte header (type + sequence number) + batched Codec2 frames
  3. StreamEnd — signals transmission complete

Sequence number gaps are detected on the receiver and filled with silence (no retransmission). Recommended LoRa settings for voice:

Setting Value Flag
UART baud 115200 --baud 115200
Sub-packet 64 bytes --sub-packet 2
Air rate 2.4 kbps (default) --air-rate 2
TX power 22 dBm (default) --power 0

Duty cycle: ISM 915 MHz bands have regulatory duty cycle limits. Use short push-to-talk bursts rather than continuous streaming.

Project Structure

advmesh/
├── main.cpp              # Application entry point (radio init, thread wiring)
├── cli.h/.cpp            # CLI argument parsing (ParseArgs, PrintUsage)
├── app.h/.cpp            # Application controller (mode management, packet routing, threads)
├── radio.h               # IRadio abstract interface
├── udp_radio.h/.cpp      # UdpRadio implementation (UDP sockets)
├── lora_radio.h/.cpp     # LoRaRadio implementation (SX1262 LoRa HAT via UART/GPIO)
├── audio.h               # IAudio abstract interface
├── pcm_audio.h/.cpp      # PcmAudio implementation (direct kernel PCM ioctls)
├── pcm_types.h           # Linux kernel ALSA UAPI type definitions (private to PcmAudio)
├── codec.h               # ICodec abstract interface
├── codec2_codec.h/.cpp   # Codec2Codec implementation (codec2 wrapper)
├── voice_stream.h        # Umbrella include for voice streaming TX/RX
├── voice_stream_tx.h/.cpp # VoiceStreamTx (batched voice capture and transmit)
├── voice_stream_rx.h/.cpp # VoiceStreamRx (batched voice receive and playback)
├── packet.h              # Packet framing (text, voice, stream protocol)
├── latency_stats.h       # Lock-free latency tracker
├── types.h               # Portable type aliases (u8, u16, i16, etc.)
├── build_deps.ps1        # Cross-compile all dependencies for ARM64
├── deploy.ps1            # Deploy binary to Raspberry Pi targets
├── test_lora.py          # On-device LoRa HAT diagnostic script
├── advmesh.slnx          # Visual Studio solution
├── advmesh.vcxproj       # Visual Studio project
└── extern/
    └── codec2/           # codec2 git submodule (low-bitrate speech codec)

LoRa Voice Transmission Analysis

A future LoRaRadio class will implement IRadio for packet transmission over LoRa. Below is the feasibility analysis for real-time voice over LoRa using the project's packet format and Codec2 codec.

System Parameters

Parameter Value
Packet header 3 bytes (1B type + 2B payload size)
Sample rate 8000 Hz
Codec2 frame duration 20 ms (160 samples)
LoRa bandwidth 125 kHz
LoRa coding rate 4/5

Codec2 Mode Comparison

Mode Bitrate Bytes/Frame Voice Quality
CODEC2_MODE_3200 3200 bps 8 B Best
CODEC2_MODE_2400 2400 bps 6 B Very Good
CODEC2_MODE_1600 1600 bps 4 B Good
CODEC2_MODE_1300 1300 bps 4 B Moderate
CODEC2_MODE_1200 1200 bps 3 B Moderate
CODEC2_MODE_700C 700 bps 2 B Low (robotic)

LoRa Spreading Factor vs Range

SF Nominal Bitrate Urban Range Rural/LOS Range
SF7 5469 bps ~2 km ~8 km
SF8 3125 bps ~3 km ~10 km
SF9 1758 bps ~4 km ~13 km
SF10 977 bps ~5 km ~16 km
SF11 537 bps ~7 km ~22 km
SF12 293 bps ~10 km ~30 km

Chosen Configuration: CODEC2_MODE_2400

Single codec frames cannot fit within one LoRa transmission — frame batching is required. Multiple 20ms codec frames are packed into a single LoRa packet to amortize preamble and header overhead.

Batch Payload LoRa SF Range Latency Timing Margin
3x 21 B SF7 2–8 km 60 ms 5.7%
5x 33 B SF7 2–8 km 100 ms 28.1%
10x 63 B SF7 2–8 km 200 ms 41.0%
15x 93 B SF8 3–10 km 300 ms 4.3%
20x 123 B SF8 3–10 km 400 ms 7.7%
50x 303 B SF8 3–10 km 1000 ms 17.0%

Recommended: 5-Frame Batch at SF7

  • Codec: CODEC2_MODE_2400 (2400 bps, 6 bytes/frame) — very good voice quality
  • Batch: 5 frames per packet (33 bytes payload)
  • Latency: 100 ms — imperceptible to the listener
  • Range: 2–8 km (urban to rural line-of-sight)
  • Timing margin: 28.1% — comfortable headroom for processing

For additional range at the cost of latency, a 15-frame batch (300ms) reaches SF8 for 3–10 km, which feels like a satellite phone delay.

Latency Guidelines

Latency Perception
< 150 ms Feels real-time
150–300 ms Noticeable but comfortable (phone call with slight delay)
300–500 ms Satellite phone feel — requires turn-taking discipline
500 ms–1 s Walkie-talkie feel, acceptable for push-to-talk

Duty Cycle Considerations

Most LoRa ISM bands (868 MHz EU, 915 MHz US) enforce 1–10% duty cycle limits, making continuous voice streaming infeasible. Options include:

  • Amateur radio bands — no duty cycle limit (license required)
  • 2.4 GHz LoRa — no duty cycle restriction (shorter range)
  • Half-duplex push-to-talk — short transmission bursts within duty cycle

Dependencies

Library Purpose License
codec2 Low-bitrate speech codec (1300 bps default) LGPL 2.1

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages