Näytetään tekstit, joissa on tunniste Raspberry Pi. Näytä kaikki tekstit
Näytetään tekstit, joissa on tunniste Raspberry Pi. Näytä kaikki tekstit

keskiviikko 1. tammikuuta 2020

Using Raspberry PI zero W as an USB wlan adapter

Background

My desktop computer is located so that it is difficult to route an ethernet cable cleanly to my modem. To have an internet connection I have tried several usb wlan adapters as well as phone tethering.

Earlier I used a Netgear one, it might have been a WNA3100 (N300), which somewhat worked with ndiswrapper. I think it had poor throughput and occasionally dropped the connection.

Some time ago I bought an Asus USB-N10 nano which claimed to have Linux support (Linux was written on the box). It didn't really work properly; there was a driver for an old kernel version and the new kernel had some kind of support built in. Depending on the driver I tried, either I did not even see my network, could not connect (authentication failed) or the connection dropped very often.

In the end I compiled the experimental version of rtl8xxxu which worked the best. The connection was rather stable, but the throughput was very poor, only 1 Mbps. My laptop can easily get over 40 Mbps...

Best results I got by using my mobile phone (connected to the wifi) and enabling usb tethering. However that has its own issues. First, I cannot use my phone anywhere else while it is sharing the connection and second, it is necessary to turn on the tethering always when connecting the cable (maybe some app could enable it automatically but...).

Solution

I had some spare Raspberry PI zero Ws lying around, and I've been playing with its usb gadget mode earlier. So I tought, why not make the PI look like an USB ethernet adapter, and bridge its wlan connection to the USB connection? I had all the pieces available, I just needed to put them together!

So, I made a script to
  1. make the PI to be an CDC/ECM USB ethernet gadget using configfs
  2. enable ipv4 port forwarding and NAT, forwarding usb0 to wlan0
  3. enable forwarding from wlan0 to the usb0
  4. enable DHCP server, serving address 192.168.20.10

I would have used CDC/NCM since I think it is the fastest protocol, but the stock Raspbian does not have built-in support for that. So I went with ECM, which works well on Linux. If the gadget is to be used with Windows, one should select RNDis (by replacing ecm with rndis in the script).

To enable gadget mode, dtoverlay=dwc2 should be added to /boot/config.txt.

Following script should be placed in /usr/local/bin/usb_wifi_gadget.sh and made executable (ug+x).

#!/bin/sh
#
# This script creates an Ethernet gadget using the
# CDC / ECM (Ethernet Control Model) interface and
# then shares the wlan0 to usb0 (with NAT)
# and starts a dhcp server on usb0

# Load libcomposite
modprobe libcomposite

# Create a gadget called usb-gadgets
cd /sys/kernel/config/usb_gadget/
mkdir -p usb-gadgets
cd usb-gadgets

# Configure the gadget
# ==========================

# Configure our gadget details
echo 0x1d6b > idVendor # Linux Foundation
echo 0x0104 > idProduct # Multifunction Composite Gadget
echo 0x0100 > bcdDevice # v1.0.0
echo 0x0200 > bcdUSB # USB2
mkdir -p strings/0x409

# Set serial number, manufacturer and product name here
echo "0123456789abcdef" > strings/0x409/serialnumber
echo "Pi Zero USB Gadget" > strings/0x409/manufacturer
echo "Pi Zero USB Gadget" > strings/0x409/product
mkdir -p configs/c.1/strings/0x409

# This describes the only configuration, free text
echo "Config 1: Test gadget" > configs/c.1/strings/0x409/configuration
echo 250 > configs/c.1/MaxPower

# =====================================
# Create gadget functions

# Ethernet gadget
# -------------------------
F_TYPE=ecm      # ECM gadget
F_NAME=usb0     # Freely selectable name

mkdir -p functions/$F_TYPE.$F_NAME

# Set configuration, see e.g.
# https://github.com/torvalds/linux/blob/master/Documentation/ABI/testing/configfs-usb-gadget-ecm

# MAC addresses, comment out for random addresses
# first byte of address must be even
HOST="32:70:05:18:ff:7a" # "HostPC"
SELF="32:70:05:18:ff:7b" # "Ethernet Gadget"
#echo $HOST > functions/$F_TYPE.$F_NAME/host_addr
#echo $SELF > functions/$F_TYPE.$F_NAME/dev_addr

# Interface name, by default will be usb0
#echo usb0 > functions/$F_TYPE.$F_NAME/ifname

# Link the function under the (only) configuration
ln -s functions/$F_TYPE.$F_NAME configs/c.1/

# End ethernet gadget
# ------------------------

# End functions
# ========================

# Enable gadgets
ls /sys/class/udc > UDC

 

# Internet connection shating
# Shares wlan0 over other connections

# Enable ipv4 forwarding
sysctl -w net.ipv4.ip_forward=1
sysctl -p

# Flush rules (flush all / flush only nat related)
#iptables -X
#iptables -F
iptables -t nat -X
iptables -t nat -F

# Enable NAT forwarding
iptables -I INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -I FORWARD  -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -t nat -I POSTROUTING -o wlan0 -j MASQUERADE


# Configure static IP address for the usb interface
ifconfig usb0 up
ifconfig usb0 192.168.20.1 netmask 255.255.255.0

# Enable incoming connections for DHCP
iptables -I INPUT -p udp --dport 67 -i usb0 -j ACCEPT

# Forward all TCP ports, except 22 (ssh), from wlan0 to usb0
iptables -t nat -A PREROUTING -p tcp -i wlan0 --dport 1:21 -j DNAT --to 192.168.20.10
iptables -t nat -A PREROUTING -p tcp -i wlan0 --dport 23:65535 -j DNAT --to 192.168.20.10


# Flush dhcp lease cache
if [ -f "/var/lib/dhcp/dhcpd.leases~" ]; then rm /var/lib/dhcp/dhcpd.leases~; fi
echo "" > /var/lib/dhcp/dhcpd.leases

# Launch (Restart) DCHP server
#systemctl restart isc-dhcp-server
if [ -f "/var/run/dhcpd.pid" ]; then kill `cat /var/run/dhcpd.pid`; fi
dhcpd -q -4 -cf /etc/dhcp/dhcpd.conf usb0
 

To launch this script at boot time, I added command usb_wifi_gadget.sh & to /etc/rc.local, before the exit 0 statement.


The dhcp server requires isc-dhcp-server package. The service should be disable by default, by running sudo systemctl disable isc-dhcp-server and sudo systemctl mask isc-dhcp-server.


The following minimalistic dhcp server configuration in /etc/dhcp/dhcpd.conf seems to work:
 

# dhcpd.conf
# Very basic dhcp daemon configuration for the USB interface

default-lease-time 600;
max-lease-time 7200;

# The ddns-updates-style parameter controls whether or not the server will
# attempt to do a DNS update when a lease is confirmed. We default to the
# behavior of the version 2 packages ('none', since DHCP v2 didn't
# have support for DDNS.)
ddns-update-style none;

# If this DHCP server is the official DHCP server for the local
# network, the authoritative directive should be uncommented.
authoritative;

# Use this to send dhcp log messages to a different log file (you also
# have to hack syslog.conf to complete the redirection).
log-facility local7;

# Subnet declaration
subnet 192.168.20.0 netmask 255.255.255.0 {
        option routers                  192.168.20.1;
        option subnet-mask              255.255.255.0;

        option domain-name-servers      192.168.0.20;
        range   192.168.20.10   192.168.20.10;
}


I run pi-hole on my local server at 192.168.0.20 so I pointed the name server to that. One could also use some other, like Comodo DNS server at 8.26.56.26. See for example this page for information.

Now this seems to work properly, when plugging the Raspberry PI (using the USB port, not the PWR port) the computer gets IP address, and can access the internet just fine. Note that on the desktop computer it may be necessary to add following to /etc/network/interfaces:

allow-hotplug usb0
iface usb0 inet dhcp

Notes

My home network is by default 192.168.0.0/24, and the PI creates 192.168.20.0/24. It seems that the routing works so that I can access the home network from the desktop computer just fine via the PI.

I added the routing through wlan0 to usb0 so that it is possible to run server(s) on the desktop computer and they are accessible by using the IP that the PI has over the wlan.

The PI should not be abruptly powered off, but rather one should ssh into it and shut it down with sudo shutdown -h now.

Speed test

When I got the gadget to work, I run some speed tests using iperf3. The server was my Raspberry PI 3B server that has wired connection to my router.
  • Asus USB-N10 nano: 4-6 Mbps (surprisingly good, right after boot & connection)
  • USB tethering with mobile phone: 15-28 Mbps
  • Raspberry PI gadget: 20 Mbps
So my conclusion is that the Raspberry PI gadget works very well as a WLAN adapter.

tiistai 2. huhtikuuta 2019

Modifying an FM radio

TL;DR I tried to modify an FM radio that only goes up to 108 MHz to receive weather satellites at 138 MHz. That failed, but I learned thing or two on the way.

Introduction

I read about receiving weather satellites with PC sound card and a modified radio many years ago, and since that time I've always wanted to do that. Today it is rather simple to do with very inexpensive software defined radios (SDRs), but using pre-built components is only half the fun.

The weather satellites I talk about transmit at 137 to 138 MHz using FM modulation. The easy way to receive that is to use a radio scanner and connect it to PC using the sound card line input and the software in previous link decodes to images. A powerful antenna may be needed, but that is just details ;)

Radio scanners tend to be quite expensive compared to normal FM radio receivers. Where I live, the FM radio band goes from about 88 MHz to 108 MHz, so quite close to what I needed. I decided to try and modify an existing radio to reach the required band.


Selecting a radio

I looked at the most inexpensive receivers and especially one that looked to have an analog tuning mechanism. I thought that one with analog tuning would have some LC tuning circuit, which I could modify to an upper frequency to extend the band upwards. I assumed that ones with digital tuning (e.g. buttons to tune up and down) might be hard to modify.

I ended up buying a Prego FM/AM radio which had analog potentiometer style tuning and volume. Below is a picture of what the radio looks like.


 

Opening it up

I opened the radio and looked at the PCB. There was no obvious tuning circuit (coils and capacitors) or even crystal oscillators visible on the board.

On the top side there was few IC circuits and on the bottom side just one. The bottom side one was a power amplifier driving the speaker, so what I wanted was one on the top side.

On the top side there was some regulators and interestingly a EEPROM of type L24C02B. This turned out to be important but I didn't know it yet.

The radio chip was under some plastic, protecting it from the mains transformer. The type of the radio receiver is KTmicro KT0922. Luckily I found datasheet for it.