LoRa port for TARPN node
KV4P has been experimenting with adding LoRa ports to his TARPN node. LoRa is very desirable for TARPN because LoRa transceivers are very inexpensive yet have good range, are very small and low-power, and reduce the overall setup cost of a new link.
Materials:
- Raspberry Pi Zero 2 W (~$15 when in stock), WITH gpio header. You can use any Rapsberry Pi model for this, but this is what I used.
- Adafruit LoRa Radio Bonnet with OLED - RFM95W @ 915MHz - RadioFruit ($32.50)
- 78mm of 16AWG magnet wire (33cm band 1/4 wave antenna), soldered to the radio bonnet antenna center conductor via (right next to the connector we won't use) (~$12 for a spool)
This assumes you already have a TARPN node. With this experimental guide, you'll be building a LoRa radio that shows up on your network as a TCP-based KISS TNC, which we'll wrap in a virtual serial port so TARPN ports 11 or 12 can be configured to access it like a normal TNC.
I'm going to assume you already have the Raspberry Pi configured with Raspberry Pi OS, and connected to your local network (the same network as your TARPN node). You'll want to assign a static IP to it (rather than DHCP), so you can ensure your TARPN node will be able to find it on the network after restarts.
A few notes:
- This has only been tested with the "Lite" Raspberry Pi OS image, not either of the "with desktop" images. They might work, but have not been tested.
- This definitely does not work on a Pi that has TARPN installed. Something in the TARPN setup script is incompatible with the LoRa bonnet. We may be able to fix this in the future, but it would require significant debugging to figure out what TARPN setup step breaks the LoRa bonnet functionality.
Get LoRa bonnet working
You can read more about these steps on this Adafruit page.
- sudo apt install python3-pip
- sudo pip3 install --upgrade setuptools
- sudo pip3 install --upgrade adafruit-python-shell
- wget https://github.com/adafruit/Adafruit_CircuitPython_framebuf/raw/main/examples/font5x8.bin
- wget https://raw.githubusercontent.com/adafruit/Raspberry-Pi-Installer-Scripts/master/raspi-blinka.py
- sudo python3 raspi-blinka.py (this will require reboot at the end)
- sudo pip3 install adafruit-circuitpython-ssd1306
- sudo pip3 install adafruit-circuitpython-framebuf
- sudo pip3 install adafruit-circuitpython-rfm9x
- create this test script rfm9x_check.py, which you should run ("python3 rfm9x_check.py") to prove your bonnet is properly connected and working:
# SPDX-FileCopyrightText: 2018 Brent Rubell for Adafruit Industries # # SPDX-License-Identifier: MIT """ Wiring Check, Pi Radio w/RFM9x Learn Guide: https://learn.adafruit.com/lora-and-lorawan-for-raspberry-pi Author: Brent Rubell for Adafruit Industries """ import time import busio from digitalio import DigitalInOut, Direction, Pull import board # Import the SSD1306 module. import adafruit_ssd1306 # Import the RFM9x radio module. import adafruit_rfm9x # Button A btnA = DigitalInOut(board.D5) btnA.direction = Direction.INPUT btnA.pull = Pull.UP # Button B btnB = DigitalInOut(board.D6) btnB.direction = Direction.INPUT btnB.pull = Pull.UP # Button C btnC = DigitalInOut(board.D12) btnC.direction = Direction.INPUT btnC.pull = Pull.UP # Create the I2C interface. i2c = busio.I2C(board.SCL, board.SDA) # 128x32 OLED Display reset_pin = DigitalInOut(board.D4) display = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c, reset=reset_pin) # Clear the display. display.fill(0) display.show() width = display.width height = display.height # Configure RFM9x LoRa Radio CS = DigitalInOut(board.CE1) RESET = DigitalInOut(board.D25) spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO) while True: # Clear the image display.fill(0) # Attempt to set up the RFM9x Module try: rfm9x = adafruit_rfm9x.RFM9x(spi, CS, RESET, 915.0) display.text('RFM9x: Detected', 0, 0, 1) except RuntimeError as error: # Thrown on version mismatch display.text('RFM9x: ERROR', 0, 0, 1) print('RFM9x Error: ', error) # Check buttons if not btnA.value: # Button A Pressed display.text('Ada', width-85, height-7, 1) display.show() time.sleep(0.1) if not btnB.value: # Button B Pressed display.text('Fruit', width-75, height-7, 1) display.show() time.sleep(0.1) if not btnC.value: # Button C Pressed display.text('Radio', width-65, height-7, 1) display.show() time.sleep(0.1) display.show() time.sleep(0.1)
Turn it into a TCP KISS TNC
See the original github project this is forked from for more info.
- sudo apt install git aprx python3-rpi.gpio python3-spidev python3-pil python3-smbus
- git clone https://github.com/VanceVagell/RPi-LoRa-KISS-TNC-2ndgen.git
- Edit config.py and update the frequency (search for "frequency"). You can/should customize the frequency to anything in the 33cm band (but at least 500kHz from the band edge).
- Optional: The default config.py settings are for balanced speed and range. If your connection is strong, you can increase bandwidth up to 500000 (500kHz) which will significantly improve speed. 500kHz is roughly equivalent to 9600 baud, and 62500 is roughly equivalent to 1200 baud. If you need even more distance, you can also increase spreadingFactor above 7 (to say 8 or 9), which will make it transmit more slowly but be received much better. There are other settings in config.py that can affect range and speed as well, but this is a good starting point.
Note that if you're using a ham band other than 33cm you may need to use lower bandwidth settings to adhere to FCC requirements for spread spectrum transmissions (<100kHz bandwidth below 33cm). You can use the full 500kHz 33cm and above.
Create log placeholders that the library expects to exist:
- sudo mkdir /var/log/lora
- sudo touch /var/log/lora/lora.log
Start/test your TCP-based KISS TNC with this command (you should see it print out the config values and say it's listening for connections, with no errors listed):
- sudo python3 Start_lora-tnc.py
This is what you should see:
######################## #LORA KISS TNC STARTING# ######################## #Lora parameters: frequency= 910300000 preamble= 32 spreadingFactor= 7 bandwidth= 500000 codingrate= 5 APPEND_SIGNAL_REPORT= False outputPower= 17 TX_OE_Style= False sync_word= 0x12 crc= True ######################## 2023/08/15 00:27:18 - KISS-Server: Started. Listening on IP 0.0.0.0 Port: 10001 2023/08/15 00:27:18 - LoRa radio initialized. Waiting for LoRa Spots...
You'll want this to start every time the LoRa pi reboots, so follow these steps (TODO replace this crontab approach with systemd):
- sudo crontab -e (If you've never used crontab it will ask you to select you preferred text editor, I use nano)
- Paste this line at the end of the crontab file, and save:
@reboot /usr/bin/python3 /home/pi/RPi-LoRa-KISS-TNC-2ndgen/Start_lora-tnc.py &
TARPN configuration
TARPN only supports serial TNCs, so first we need to "fake" a serial TNC that actually connects to our TCP-bsaed LoRa KISS TNC using the "socat" command.
- sudo apt install socat
- sudo nano lora-port-up.sh
- Use these contents but replace the IP address to your LoRa KISS TNC's address:
#!/bin/bash printf "Bringing up LoRa port as /dev/ttyS0\n" while true do sudo socat pty,link=/dev/ttyS0,b115200,raw,nonblock,echo=0,mode=777 tcp:192.168.1.90:10001,forever,interval=10 printf "LoRa port /dev/ttyS0 disconnected, waiting 1 second and bringing it up again.\n" sleep 1 done
- chmod +x lora-port-up.sh
You'll want this LoRa virtual device to appear on device reboot, you can do this with crontab (TODO replace this crontab approach with systemd):
- sudo crontab -e (If you've never used crontab it will ask you to select you preferred text editor, I use nano)
- Paste this line at the end of the crontab file, and save:
@reboot nohup /home/pi/lora-port-up.sh &
- Start the fake serial device with "./lora-port-up.sh &" and it will show up as /dev/ttyS0 like a serial TNC would be. (You might want to do this in crontab or something, so it always runs on node restart.)
Then you can edit your TARPN node.ini to configure port 11 as follows:
usb-port11:ENABLE portdev11:/dev/ttyS0 speed11:115200 txdelay11:1 frack11:2000 kissoptions11:disable neighbor11:KV4P-3
Of course, assign "neighbor11" to the callsign/ssid of the node you plan to connect to via LoRa on your new port 11.
Performance
With the above config.py settings, a throughput test on my own TARPN node with a "bench setup" (2 LoRa transceivers right next to each other), I achieved 135bytes/sec. That's about as good as a very solid 9600 baud link with a NinoTNC and high quality mobile radios.
It can probably be made to go much faster with additional optimization. It's unclear if the KISS service running in Python represents a cap on the throughput, or if it's just the settings.
Although the distance of this link hasn't been tested yet, the LoRa module claims to work between 4km and 40km (from city to perfectly flat ideal conditions). 33cm has the nice property of easily going through windows and walls, so it should be especially good for suburban links, or between nodes with a fairly clear shot.