Udev Rules in Linux

I became very frustrated with the fact that my USB ports kept changing. I have a TNC2S 1k2 for Aprs and an SCS Tracker for Robust Packet connected to my Pi. The Icom 7300 is controlled via HamLib on another Raspberry Pi. But once it was necessary to reboot the PI running Linbpq , the ttyUSB0 or the ttyUSB1 would keep changing places. Conclusion, I had to adjust the bpq32.cfg again before everything worked the way I wanted.

Now it is quite easy to do something about this. Call me Lazy because it took so long.

Udev rules look like this

SUBSYSTEM=="tty", ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303",
SYMLINK+="ttyTNC2S

Now, of course, we first have to find out what the “idVendor” and “idProduct” is.

With the command….

udevadm info -a -n /dev/ttyUSB0

We get a long list of data from usb to serial port ttyUSB0.

With this information we can create an udev rule.

sudo nano etc/udev/rules.d/99-usb-serial.rules
SUBSYSTEM=="tty", ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303",
SYMLINK+="ttyTNC2S
udevadm control --reload
reboot

This has been done for both sides. Both ttyUSB0 and ttyUSB1. And look there are the ttyTNC2S and ttySCS ports. Now you can restart Linux as often as you want and trust that the same USB port is always assigned to the right box.

Now my port config looks like this in bpq32.cfg.

PORT
 PORTNUM=3
 ID=14.1022 RPR ;(RPR)
 TYPE=EXTERNAL 
 COMPORT=/dev/ttySCS
 SPEED=38400
 DRIVER=SCSTracker
 CONFIG
RIGCONTROL
HAMLIB 44.137.31.76:4532
14.1022,USB,F1,H1
****
WL2KREPORT PUBLIC, api.winlink.org, 80, PI8LAP-10, JO11VN, 00-23, 14102200, ROBUST, 25, 35, 3
WL2KREPORT PUBLIC, api.winlink.org, 80, PI8LAP-10, JO11VN, 00-23, 14102200, PKT300, 25, 35, 3
WL2KREPORT PUBLIC, api.winlink.org, 80, PI8LAP-10, JO11VN, 00-23, 144850000, PKT1200, 10, 20, 5, 0
WL2KREPORT PUBLIC, api.winlink.org, 80, PI8LAP-10, JO11VN, 00-23, 430950000, PKT9600, 10, 20, 5, 0
;#
  M UISC
  O 4                   ; MAXFRAME
  F 190                 ; FRACK
  T 8                   ; TX Delay
  FORCE ROBUST
  USEAPPLCALLS          ; Accept connects to all APPLCALLS
  BEACONAFTERSESSION    ; Beacon after session
  %L 1500               ; Centre Freq for Normal Packet (Default is 1500)
  @I 64                 ; Paclen = 60
  %T 1                  ; TX Autotracking 1 = on
  %N 10
  %B 300
ENDPORT

Great…..

XRpi interfacing with LinFBB

Software is available on this link

Wow, found great software. Yes I know, it has been around for a while. I thought it would be nice to keep me busy on a rainy Saturday. So let’s interface it with LinFBB.

It actually works a bit like BPQ32 and LinFBB with WA8DED emulation. But for XRouter and LinFBB we need a virtual comport. We can make these easily with socat.

sudo apt install socat

Now lets create some comports

# Create pty pair
socat -d -d -ly PTY,link=/home/pi/xrpi/ttyq1 PTY,link=/home/pi/xrpi/ptyq1 &
sleep 2

I have chosen to create this as a normal user and put it in the directory /home/pi/xrpi/. Now as a normal user I can access and use them. I am never much of a fan of doing everything as a Root user.

Now lets configure XRouter.

INTERFACE=5
	TYPE=ASYNC
	COM=/home/pi/xrpi/ttyq1
	PROTOCOL=DEDHOST
	APPLNUM=1
	CHANNELS=4
	SPEED=57600
	FLOW=0
	MTU=256
ENDINTERFACE

APPL=1
	APPLNAME=FBB
	APPLCALL=PI8LAP-1
	APPLALIAS=LAPFBB
	APPLQUAL=254
	APPLFLAGS=4
ENDAPPL

Next is LinFBB… port.sys

# FBB7.0.8-beta8
#
#Ports TNCs
 1     1
#
#Com Interface Adress (Hex)       Baud
1  	 9        /home/pi/xrpi/ptyq1    57600
 
#TNC NbCh Com MultCh Pacln Maxfr NbFwd MxBloc M/P-Fwd Mode  Freq
 0   0    0   0      0     0     0     0      00/01   ----  File-fwd.
1   4    1   1      236   4     1     10     00/15 DUWYL XRpi

Now fist create a start file for XRpi

# First kill running process of socat
sudo kill $(ps aux | grep '[s]ocat' | awk '{print $2}')
# Create pty pair
socat -d -d -ly PTY,link=/home/pi/xrpi/ttyq1 PTY,link=/home/pi/xrpi/ptyq1 &
sleep 2
# Start XRpi(1)
sudo setcap cap_net_raw,cap_net_bind_service=pe xrpi
./xrpi

1. As Normal user, it will need CAP_NET_RAW capability in order to use TCP/IP via the LAN, WiFi or localhost. And it will need CAP_NET_BIND_SERVICE if you wish to open any “service ports” on the linux TCP/IP stack whose numbers are below 1024.

First we have to start XRpi because of course the virtual comports have to be created. After this it is LinFBB’s turn. Now is the time to test.

The link with BPQ32 is also online. Also with virtual comports.

And yes, there is the old trusted LinFBB.

The possibilities are endless with this software. So there goes me free Saturday again.

MHSave and Python

Today I am playing with Python and Matplotlib. In BPQ32 you have the option to save the Most Heard list (MH) when you close BPQ32. This contains a lot of data that you can use. Above I made a plot of the received stations and the number of packets I received at 14.1022Mhz + 1000Hz at 300Baud. Now I am not a world programmer, so this could probably be easier or different. Below the script I have written and used.

#!/usr/bin/python3
import re, csv, zlib
import matplotlib.pyplot as plt
import numpy as np

#First get the data form the right port. 14.1022Mhz 300 Baud HF Packet

port4 = []

with open("MHSave.txt") as f:
        found_port4 = False

        for line in f:
                if line.startswith("Port:4"):

                        found_port4 = True

                if found_port4:
                        if line.startswith("Port:5"):
                                break
                        else:
                                mod_string = line.replace('||', '')
                                mod_strings = re.sub("via.*$", "", mod_string)
                                port4.append(mod_strings.rstrip('\n'))

with open('port4.txt', 'w') as fout:
        fout.writelines("\n".join(port4[1:]))

#print("\n".join(port4))

# Convert it to a csv file
with open('port4.txt', 'r') as in_file:
    lines = in_file.read().splitlines()
    stripped = [line.replace(","," ").split() for line in lines]
    grouped = zip(*[stripped]*1)
    with open('port4.csv', 'w') as out_file:
        writer = csv.writer(out_file)
        writer.writerow(('Epoch', 'Pack-rev', 'Call', 'Month', 'Day', 'Time'))
        for group in grouped:
            writer.writerows(group) 

# Matplotlib create a nice Plot of the received calls

filename = 'port4.csv'
with open(filename) as f:
    reader = csv.reader(f)
    header_row = next(reader)

    #Get Packets and Calls received
    packs, calls = [], []
    for row in reader:
        pack = int(row[1])
        call = str(row[2])
        packs.append(pack)
        calls.append(call)

x = np.arange(len(calls))

fig, ax = plt.subplots()

ax.barh(x, packs, align='center')
ax.set_title("Call and Packets received on PI1LAP")
ax.set_xlabel('Received Packets')
ax.set_ylabel('Station Callsigns')
ax.set_xticks(packs, minor=True)
ax.set_yticks(x)
ax.set_yticklabels(calls)
plt.tight_layout()
plt.show()

Upcoming release of Jnos

Read all about it…….

differences between 2.0m.5Gx and 2.0m.5G - April 17, 2021
 ---------------------------------------------------------

 being released this evening (CDT) ...

 ax25 heard has been 'revamped', new 'heard via digipeater' feature,
 so that you can actually see stations not directly heard, I created
 this due to my crazy obsession with Robust Packet lately and seeing
 all the APRS frames coming in on 30 meters, many via K4KPN-10, nice
 to know who else you can qso with (indirectly), really liking this.

 the save/load functionality improved, you can specify save and load
 file now, and times are FINALLY accurate on load, this took a lot of
 effort, but worth it in the end I think. I have NOT included saving
 of the latest digipeater heard list (yet), that will be next time.

 To be honest ? I hated the introduction of the 'show' subcommand, so
 the original 'ax25 h <iface>' is back and will stay that way ...

 command help dialogue now taken from a NEW usage/ax25/heard.txt file
  (create new /jnos/usage/ax25 directory, copy heard.txt over to it)

 note : I have NOT updated j2addendum.txt (yet)

Kantronics KPC4

Today I have been working on a Kantronics KPC4 which I bought from PD4R. I am very happy that I can add it to the collection.

Kantronics KAM_KPC-1-2-4-2400_Installation Manual
Kantronics KAM_KPC-1-2-4-2400_Operations Manual

Kantronics KPC4 Firmware

The nice thing is that such modems can also be accessed from BPQ32. Here is a small example.

PORT
 ID=Serial TNC KPC4
 COMPORT=/dev/ttyUSB1
 SPEED=9600
 DRIVER=SERIAL
 QUALITY=0
 PORTCALL=PI1LAP
ENDPORT

Bpq32 with QtSoundModem and Hamlib

Yesterday I added 2 HF ports to my Bpq32 Node / BBS. I have chosen to use QtSoundModem and Hamlib. QtSoundModem is a Linux port or Soundmodem from UZ7HO. I use Hamlib/rigctld to take control of the Tranceiver. QtSoundmodem and Hamlib run on a different Raspberry than the BBS and Node.

After some testing I found out that I need Hamlib version 3.3 to control the icom 7300. The versions 4.0 and 4.1 do not work for me. Apparently the icom 7300 is not being initialized. Can’t actually find out why this is. With the command “rigctld -l” you get a list of which tranceivers are supported.

So I need number 373 for the Icom 7300.

/usr/local/bin/rigctld -m 373 -r /dev/ttyUSB0 -s 19200 -T 44.137.31.76 -t 4532 &

In the QtSoundModem.ini I have in the [Init] section.

HamLibHost=44.137.31.76
HamLibPort=4532
PTT=HAMLIB
PTTBAUD=19200
PTTMode=17

Now the bpq32.cfg

PORT
 PORTNUM=4
 ID=14.1022 +1100Hz
 DRIVER=UZ7HO
 CHANNEL=A
 PACLEN=80
 CONFIG
  ADDR 44.137.31.76 8101 ; AGW port of QtSoundModem
  BEACONAFTERSESSION
  MAXSESSIONS=5
ENDPORT

PORT
 PORTNUM=5
 ID=14.1022 +2000Hz
 DRIVER=UZ7HO
 CHANNEL=B
 PACLEN=80
 CONFIG
  ADDR 44.137.31.76 8101 ; AGW port of QtSoundModem
  BEACONAFTERSESSION
  MAXSESSIONS=5
ENDPORT

With Hamlib it is also possible to control the TRX from Bpq32. I immediately added a Robust 300 packet port to Bpq32 with rig control. Here is an example.

PORT
 PORTNUM=3
 ID=Robust 300 ;(RPR Packet)
 TYPE=EXTERNAL 
 COMPORT=/dev/ttyUSB0
 SPEED=38400
 DRIVER=SCSTracker
 INTERLOCK=3
 CONFIG
 RIGCONTROL
HAMLIB 44.137.31.76:4532
15,14.1022,USB,F1,R1,H1
15,7.04510,USB,F1,R1,H1
****
WL2KREPORT PUBLIC, api.winlink.org, 80, PI8LAP-10, JO11VN, 00-23, 14102200, ROBUST, 25, 35, 3
WL2KREPORT PUBLIC, api.winlink.org, 80, PI8LAP-10, JO11VN, 00-23, 14102200, PKT300, 25, 35, 3
WL2KREPORT PUBLIC, api.winlink.org, 80, PI8LAP-10, JO11VN, 00-23, 144850000, PKT1200, 10, 20, 5, 0
WL2KREPORT PUBLIC, api.winlink.org, 80, PI8LAP-10, JO11VN, 00-23, 430950000, PKT9600, 10, 20, 5, 0
;#
  M UISC
  O 4                   ; MAXFRAME
  F 190                 ; FRACK
  T 8                   ; TX Delay
  FORCE ROBUST
  USEAPPLCALLS          ; Accept connects to all APPLCALLS
  BEACONAFTERSESSION    ; Beacon after session
  %L 1500               ; Centre Freq for Normal Packet (Default is 1500)
  @I 64                 ; Paclen = 60
  %T 1                  ; TX Autotracking 1 = on
  %N 10
  %B 300
ENDPORT

/var/log/syslog

Apr  4 16:34:41 pi1lap : Initialising Port 01     TCPKISS IP 127.0.0.1 Port 8001 Chan A
Apr  4 16:34:41 pi1lap : Initialising Port 02     TCPKISS IP 127.0.0.1 Port 8001 Chan B
Apr  4 16:34:41 pi1lap : Initialising Port 03     SCSTRK /dev/ttyUSB0
Apr  4 16:34:41 pi1lap : Initialising Port 04     UZ7HO Host 44.137.31.76 Port 8101 Chan A
Apr  4 16:34:41 pi1lap : Initialising Port 05     UZ7HO Host 44.137.31.76 Port 8101 Chan B
Apr  4 16:34:41 pi1lap : Initialising Port 06     ASYNC /dev/ttyUSB1 Chan A

 

Jnos with a KPC3(+) or Kam in kiss

I was reading in the Jnos mail list about a problem with getting a KPC3 + or Kam modem in kiss or out of kiss. There are some nice examples of how that works.

First get the modem out of Kiss.

echo -e "\xc0\xff\xc0" > /dev/ttyS0'

In the autoexec.nos

attach asy ttyS0 - ax25 p144 4096 256 9600
ifconfig p144 description "p144 - 144 Mhz - 1200 baud"
ifconfig p144 ax25 bbscall w3xsc-1
ax25 digipeat p144 off
ifconfig p144 tcp mss  216
ifconfig p144 tcp window  432
arp eaves p144 on
source p144.local
# Pause a sec to make sure the TNCs have time to reset
pause 1
trace p144 0111
ax25 bcport p144 on
trace p144 0111 ./logs/p144.trace 1000

In the p144.local file

# Serial interface
comm p144 "xxx"
comm p144 "INTFACE TERM"
comm p144 "ABAUD 9600"
comm p144 "XFLOW OFF"
comm p144 "START $00"
comm p144 "STOP $00"
comm p144 "XON $00"
comm p144 "XOFF $00"
comm p144 "TXFLOW OFF"
comm p144 "TRFLOW OFF"
comm p144 "MONITOR OFF"
# Radio interface
comm p144 "HBAUD 1200"
comm p144 "XMITOK ON"
comm p144 "CD SOFTWARE"
# Services
comm p144 "DIGIPEAT OFF"
comm p144 "NUMNODES 0"
comm p144 "USERS 0"
comm p144 "PBBS 0"
# 'PBBS 0' causes a soft reset if not already set to 0
pause 2
# Identification
comm p144 "MYCALL w3xsc-15"
comm p144 "MYPBBS w3xsc-14"
comm p144 "BTEXT SCCo ARES/RACES W3XSC BBS - Mountain View - Offline"
comm p144 "BEACON EVERY 15"
# AX.25 channel
comm p144 "PACLEN 0"
comm p144 "MAXFRAME 2"
comm p144 "RETRY 8"
comm p144 "FRACK 5"
comm p144 "SLOTTIME 10"
comm p144 "PERSIST 96"
comm p144 "DWAIT 0"
comm p144 "DIGIPEAT OFF"
comm p144 "TXDELAY 40"
comm p144 "CHECK 30"
# KISS mode
comm p144 "INTFACE KISS"
pause 1
comm p144 "RESET"
pause 2
# KISS Parameters
param p144 TxDelay 40
param p144 Persist 96
param p144 SlotTime 10
param p144 FullDup 0

This was the first option, now the second.

# KPC3P stuff
remark KPC3P USB (1200 baud) on port 'kpc3p'
attach asy ttyUSB1 - ax25 kpc3p 4096 256 1200
ifconfig kpc3p description "kpc3p - 1200 baud port"
# Put the KPC3P into KISS mode
#   the pauses are critical -- things may fail
#   sporadically if pauses are too short.
remark "Putting the KPC3P into KISS mode -- "
remark "  this takes about 10 seconds!"
pause 2
comm kpc3p ""
pause 2
comm kpc3p "intface kiss"
pause 2
comm kpc3p "reset"
pause 5

I have tested both options and they work perfectly. Nice.

Aprs Weather Beacon

Today I’ve been messing around with an APRS weather beacon. Now Direwolf and Linbpq and Jnos can send an aprs weather beacon. It turns out that this is quite precise, with the format of the beacon.

#!/bin/bash
# The weather beacon have to look like this....
# @220424z5057.81N/00729.37E_094/002g005t043r000p006P006h89b09783
# !5133.52N/00348.15E_073/013g...t048h85b10040wWXD
#
# Jun 01 2003 08:07
# 272/000g006t069r010p030P020h61b10150
# ***********************************************************
# 272 - wind direction - 272 degrees
# 010 - wind speed - 10 mph
# g015 - wind gust - 15 mph
# t069 - temperature - 69 degrees F
# r010 - rain in last hour in hundredths of an inch - 0.1 inches
# p030 - rain in last 24 hours in hundredths of an inch - 0.3 inches
# P020 - rain since midnight in hundredths of an inch - 0.2 inches
# h61 - humidity 61% (00 = 100%)
# b10153 - barometric pressure in tenths of a MILLIBAR - 1015.3 MILLIBARS

My weather station uploads its data to wunderground.com. Now wunderground has the option to read this again with an api key.

https://api.weather.com/v2/pws/observations/current?stationId=IKORTG9&format=json&units=m&apiKey=yourApiKey

You can read here how and what.

After a lot of messing around with a bash script, I am able to create the correct format.

TEMP=-4.9°C Temperature degrees Celsius
WPK=29.4km/h Wind speed in Kilometers per hour
WGK=39km/h Wind guts in Kilometers per hour
GRD=58° Wind direction in degrees
RAIN=0mm Rain in the last hour in mm
RAIN24=0.42065mm Rain in the last 24 hour in mm
RAIN12=0.214mm Rain in the last 12 hour in mm
HUM=74% Humidity in procent
Bar=1004mb Barometric pressure in millibars
FAH=023F Temperature degrees Fahrenheit
WPM=018mph Wind speed in miles per hour
WGM=024mph Wind guts in miles per hour
RNI=000inch Rain in the last hour in inches
RNI=001inch Rain in the last 24 hour in inches
RNI=000inch Rain in the last 12 hour in inches

The file I need to broadcast an APRS Weahter Beacon looks like this.

pd9q@pancake:~/linbpq/wx-project $ cat ~/linbpq/current.txt
Feb 09 2021 13:00
086/004g008t028r000p000P000h75b10007

The config file for Linbpq looks like this, this is in the aprs section of bpq32.cfg

WXCall=PD9Q-7
WXFileName=/home/pd9q/linbpq/current.txt
WXComment=/Weather Station JO11VN
WXPortList=1,5,IS        ; comma separated list 
WXInterval=10            ; mins

For Jnos in the autoexec.nos in the aprs section

aprs wx call PD9Q-7
aprs wx stat "Weather Station JO11VN"
aprs wx pos "5133.52N/00348.15E_METEO
aprs wx data "/home/pd9q/jnos/wx/current.wx"
aprs bc rftimer 10

For direwolf in the file direwolf.conf

PBEACON LAT=51^33.52N LONG=03^48.15E SYMBOL=”weather station” COMMENTCMD=”tail -1 /home/pd9q/linbpq/current.txt”

Direwolf Aprs packet look like this.

PD9Q-7>APDW15:!5133.52N/00348.15E_069/005g006t028r000p000P000h75b10007

BPQ32 Aprs packet look like this.

PD9Q-7>APBPQ1,WIDE1-1:@091338z5133.52N/00348.15E_069/005g006t028r000p000P00
0h75b10007/Weather Station JO11VN

Learned a lot.

PointoPoint link between two Ninotnc`s

Today I am playing with tncattach, I thought it would be fun to test this with the Ninotnc`s.

I have connect the first Ninotnc n9600A4 to my rpi 4 and install “tncattach” on it. The TNCs are connected with each other by means of a short cable.  Cross cable. The tnc are running 9600Baud

TNC1             TNC2
RX                   TX
TX                   RX

# If you don't already have a compiler installed
sudo apt install build-essential

# Clone repository from GitHub
git clone https://github.com/markqvist/tncattach.git

# Move into source directory
cd tncattach

# Make program
make

# Install to system
sudo make install

The next thing I did was setting up a pointopoint link. But first attach the modem.

sudo tncattach /dev/ttyACM0 57600 -d --noipv6 --noup --mtu 329
sudo ifconfig tnc0 10.0.0.1 pointopoint 10.0.0.2

The second Ninotnc n9600A3 I have connected to my rpi 3

sudo tncattach /dev/ttyACM0 57600 -d --noipv6 --noup --mtu 329 
sudo ifconfig tnc0 10.0.0.2 pointopoint 10.0.0.1

I made a short video of how it works.

That was Fun….