Pages

12/03/2017

A DMR Hotspot using a Raspberry Pi, DVMega and MMDVMHost.

To celebrate passing my foundation radio license I treated myself to a Connect Systems CS-580 DMR Radio. DMR (Digital Mobile Radio) is a digital standard that digitises and compresses the audio, allowing two simultaneous conversations to occupy the same amount of bandwidth as a single narrow band call using a traditional FM radio. There's a lot more to it than than, but it's probably best covered in another post.

Unfortunately I discovered signal strength  from my local DMR repeater GB7WL was marginal, so I was unable to pick it up from the warmth and comfort of my flat. I initially considered fitting an external aerial, but that would leave me unable to roam around my flat as I'd be tethered via a cable to the aerial, so I started looking into hotspots - a low powered radio device that connects into the existing DMR networks over the internet and relays the voice traffic out of a small antenna. Plus, as I passed my intermediate license in the time it took for the CS-580 to arrive, I was due another treat...

I've heard good things about the SharkRF openSpot, a hotspot that works 'out of the box', but the inner hacker in me wanted something a little more customisable. I then stumbled across the DVMega, an add on 'shield' for the Raspberry Pi, and decided it would better suit my needs. The DVMega + Raspberry Pi also came out at approximately £150, which is £50 cheaper than the openSpot and includes a Pi that I can continue to use if I move on from DMR radio.

A DVMega on a Raspberry Pi 3

A DVMega on a Raspberry Pi 3



The Plan

The customisability of the Pi's Linux based operating system means I can use one of several methods to connect to the internet, Ethernet, Wifi, or even 3G. The plan is to combine the connectivity with several power options - on board battery, PoE, or USB, which will enable me to operate almost anywhere.

I would use the MMDVMHost software to operate the DVMega, and also MMDVMHost-Dashboard to provide a pretty management tool that can show whose talking, which network the hotspot is connected to, etc.

I also wanted to make the Pi's file system Read Only, so I can pull out the power without worrying about corrupting the file system. This isn't feasible for all applications, but as the hotspot is just relaying traffic from the network to RF, there's not much writing to disk other than logs which can be stored in the RAM.

Disclaimer

i) I operate the DMR hotspot for testing and development purposes. A dummy load is fitted to both the hotspot (Base Station) and DMR Radio (Mobile Station) to suppress RF emissions beyond the boundary of the premises to below the values laid out in the "Statutory Instrument 1989 No. 1842" which can be found here. More information from Ofcom can be found here

Therefore to the best of my belief I am operating within the confines of the law.

ii) The configuration laid out below is aimed at usability rather than security. The device should be protected from the 'public internet' using an appropriate firewall.

To Dos

The configuration currently involves an odd miss-mash of init scripts and systemd services. In future revisions I'd like to get everything switched over to systemd.

It also starts a couple of services within screen sessions, which works quite nicely but doesn't feel like the correct way of doing things.

I'd also like to release an 'image' for users who aren't so comfortable using the command line.

Instructions

The instructions below will over the basics of getting the hotspot working over Ethernet. I will cover the Wifi and 3G dongle in a future post to try and keep this one as brief as possible (ha!)

Initial Connections

To get started the only things I connected to the Pi was the DVMega, Power and Ethernet, as I was hoping to avoid having to plug in a display etc.

Operating System

I started off by downloading a Raspian Jessie Lite image from the official Raspberry Pi Website and copying it to the SD card. How you do this varies on your Operating System, but there's more information here.

Before removing the SD card and placing it in the Raspberry Pi, it's important to create a file called 'ssh' in the Boot Partition of the SD card which enables SSH.

Once done, eject the card, place it in the Raspberry Pi and power it up.

Logging In

Once the Pi had finished booting, I discovered it's IP address by checking my routers DHCP leases, but the Raspberry Pi also displays its IP on an attached display whilst booting.

I then connected via SSH using the credentials below-

Default Username: Pi
Default Password: Raspberry

and then escalated my privileges-
sudo su

Customising Packages

Before you can start installing the MMDVM components it's necessary to customise the available packages, to remove some unnecessary packages and to install lighttpd webserver to host the dashboard-
apt-get remove --purge wolfram-engine triggerhappy dbus dphys-swapfile xserver-common lightdm fake-hwclock rsyslog

apt-get install --yes  lighttpd php5-common php5-cgi php5 git busybox-syslogd

lighty-enable-mod fastcgi-php

/etc/init.d/lighttpd force-reload

apt-get autoremove --purge

Making the file system Read Only


First of all we need to disable the swap and boot into read only mode-
nano /boot/cmdline.txt

Add the following to the end of the line of options-
fastboot noswap ro

It's then necessary to delete some directories and move them to the /tmp directory which will be stored in RAM-
rm -rf /var/lib/dhcp/ /var/run /var/spool /var/lock /etc/resolv.conf /var/lib/systemd/random-seed

ln -s /tmp /var/lib/dhcp
ln -s /tmp /var/spool
ln -s /tmp /var/lock
ln -s /tmp/random-seed /var/lib/systemd/random-seed

touch /tmp/dhcpcd.resolv.conf; ln -s /tmp/dhcpcd.resolv.conf /etc/resolv.conf

We then need to tell some of the programs about the changes-
nano /etc/systemd/system/dhcpcd5

And update the PID file location-
PIDFile=/var/run/dhcpcd.pid

And then we need to ensure the random seed file is created in the RAM drive at boot-
nano /lib/systemd/system/systemd-random-seed.service

Add the following line-
ExecStartPre=/bin/echo "" >/tmp/random-seed

Reload systemd-
systemctl daemon-reload

We now need to tell the fstab to mount some drives as read only, and mount others in the RAM-
nano /etc/fstab

The / and /boot partions need ro added to the end of the options, and other partitions are created as tmpfs (In the RAM). My fstab looks like this-
proc            /proc           proc    defaults             0       0
/dev/mmcblk0p1  /boot           vfat    defaults,ro          0       2
/dev/mmcblk0p2  /               ext4    defaults,noatime,ro  0       1

tmpfs           /tmp            tmpfs   defaults             0       0
tmpfs           /var/log        tmpfs   defaults             0       0
tmpfs           /var/tmp        tmpfs   defaults             0       0
tmpfs           /var/lib/php5   tmpfs   defaults             0       0

Adding Aliases to make switching between RO and RW Mode

It's sometimes necessary to switch between RO and RW mode when updating settings etc. To make this easier add some aliases to bash.bashrc.

Open the file-
nano  /etc/bash.bashrc

And add the following at the end of the file.
# set variable identifying the filesystem you work in (used in the prompt below)
set_bash_prompt(){
    fs_mode=$(mount | sed -n -e "s/^\/dev\/.* on \/ .*(\(r[w|o]\).*/\1/p")
    PS1='\[\033[01;32m\]\u@\h${fs_mode:+($fs_mode)}\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
}
 
alias ro='sudo mount -o remount,ro / ; sudo mount -o remount,ro /boot'
alias rw='sudo mount -o remount,rw / ; sudo mount -o remount,rw /boot'
 
# setup fancy prompt"
PROMPT_COMMAND=set_bash_prompt

You can then enter ro or rw in the consle to switch between modes, and the current mode will display.

Creating folders on boot

Because we're mounting some partitions in the RAM, it's necessary to create some directories at boot time-
nano /etc/init.d/prepare-dirs

Enter the following script-
#!/bin/bash
#
### BEGIN INIT INFO
# Provides:          prepare-dirs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Required-Start:
# Required-Stop:
# Short-Description: Create directories on tmpfs at startup
# Description:       Create  directories on tmpfs at startup
### END INIT INFO

DIR=/var/log/lighttpd
MMDVMDIR=/var/log/MMDVM
#
# main()
#
case "${1:-''}" in
  start)
    # create the /var/log/lighttpd needed by webserver
    if [ ! -d ${DIR} ]; then
      mkdir ${DIR}
      chmod 755 ${DIR}
      chown www-data:www-data ${DIR}
    fi
    if [ ! -d ${MMDVMDIR} ]; then
      mkdir ${MMDVMDIR}
      chmod 755 ${MMDVMDIR}
      chown mmdvm:mmdvm ${MMDVMDIR}
    fi
    ;;
  stop)
    ;;
  restart)
   ;;
  reload|force-reload)
   ;;
  status)
   ;;
  *)
   echo "Usage: $SELF start"
   exit 1
   ;;
esac

Add the mmdvm user-
sudo adduser mmdvm

Then make the script executable, update the rc.d and daemon-
sudo chmod +x /etc/init.d/prepare-dirs
update-rc.d prepare-dirs defaults 01 99
systemctl daemon-reload


Configuring NTP

As we have removed fake-hwclock we need to ensure the clock stays up to date. We can do this via NTP-
apt-get install ntp

Ensure the correct timezone is set-
raspi-config

And then edit the NTP conf file
nano /etc/ntp.conf

And update the drift file location to the RAM drive-
driftfile /var/tmp/ntp.drift

Installing MMDVMHost

Now the file system and tools are configured we can install and configure MMDVMHost.

Before we do so, we need to disable the serial and bluetooth interface, as MMDVMHost uses the serial connection to communicate with the DVMega-
sudo systemctl stop serial-getty@ttyAMA0.service
sudo systemctl disable serial-getty@ttyAMA0.service
sudo bash -c 'echo "dtoverlay=pi3-disable-bt" >> /boot/config.txt'

Then edit the boot options file-
nano /boot/cmdline.txt

And remove the following section-
console=ttyAMA0,115200

We can then download the files from git into the /usr/src directory, 'make' them, and then copy them into /opt/MMDVMHost-
cd /usr/src
git clone https://github.com/g4klx/MMDVMHost.git

cd MMDVMHost
make

mkdir /opt/MMDVMHost
rsync -a /usr/src/MMDVMHost/ /opt/MMDVMHost/

Configuring MMDVMHost

With MMDVMHost installed, its now necessary to create the MMDVM.ini config files. By default only one is required, but to allow MMDVMHost-Dashboard to switch between the DMR+ and Brandmeister networks its necessary to create three.

Create the file-
nano /etc/MMDVM.ini

And add the following. This is my 'native' configuration that connects to the Phoenix DMR network. You will need to update the sections in square brackets to your own details-
[General]
Callsign=[Your Call Sign or Gateway/Repeater Call Sign]
Timeout=180
Duplex=0
# ModeHang=10
RFModeHang=10
NetModeHang=3
Display=None
Daemon=0

[Info]
RXFrequency=[Your chosen RX frequency]
TXFrequency=[Your chosen TX frequency]
Power=1
Latitude=[Your Latitude]
Longitude=[Your Longitude]
Height=[Your Height Above Sea Level]
Location=[Your Location]
Description=[Your Description]
URL=[Your URL]

[Log]
# Logging levels, 0=No logging
DisplayLevel=1
FileLevel=2
FilePath=/var/log/MMDVM
FileRoot=MMDVM

[CW Id]
Enable=1
Time=1

[DMR Id Lookup]
File=/tmp/DMRIds.dat
Time=24

[Modem]
Port=/dev/ttyAMA0
TXInvert=1
RXInvert=0
PTTInvert=0
TXDelay=100
DMRDelay=0
RXLevel=50
TXLevel=50
# CWIdTXLevel=50
# D-StarTXLevel=50
# DMRTXLevel=50
# YSFTXLevel=50
# P25TXLevel=50
RSSIMappingFile=RSSI.dat
SamplesDir=.
Debug=2

[UMP]
Enable=0
# Port=\\.\COM4
Port=/dev/ttyACM1

[D-Star]
Enable=0
Module=C
SelfOnly=0
ErrorReply=1

[DMR]
Enable=1
Beacons=1
Id=[Your DMR ID]
ColorCode=1
SelfOnly=0
EmbeddedLCOnly=0
DumpTAData=1
# Prefixes=234,235
# Slot1TGWhiteList=
# Slot2TGWhiteList=
CallHang=3
TXHang=4

[System Fusion]
Enable=0
RemoteGateway=0

[P25]
Enable=0
NAC=293

[D-Star Network]
Enable=0
GatewayAddress=127.0.0.1
GatewayPort=20010
LocalPort=20011
Debug=0

[DMR Network]
Enable=1
#Phoenix Master DMR Server-
Address=109.69.105.88
Port=55555
Jitter=300
# Local=3350
Password=PASSWORD
# Options=
RSSI=1
Slot1=0
Slot2=1
Debug=2

[System Fusion Network]
Enable=0
LocalAddress=127.0.0.1
LocalPort=3200
GwyAddress=127.0.0.1
GwyPort=4200
Debug=0

[P25 Network]
Enable=0
GatewayAddress=127.0.0.1
GatewayPort=42020
LocalPort=32010
Debug=0

[TFT Serial]
# Port=modem
Port=/dev/ttyAMA0
Brightness=50

[HD44780]
Rows=2
Columns=16

# For basic HD44780 displays (4-bit connection)
# rs, strb, d0, d1, d2, d3
Pins=11,10,0,1,2,3

# Device address for I2C
I2CAddress=0x20

# PWM backlight
PWM=0
PWMPin=21
PWMBright=100
PWMDim=16

DisplayClock=1
UTC=0

[Nextion]
# Port=modem
Port=/dev/ttyAMA0
Brightness=50
DisplayClock=1
UTC=0
IdleBrightness=20

[OLED]
Type=3
Brightness=0
Invert=0

[LCDproc]
Address=localhost
Port=13666
#LocalPort=13667
DimOnIdle=0
DisplayClock=1
UTC=0

Copy the file to the DMRPLUS.ini file-
cp /etc/MMDVM.ini /etc/DMRPLUS.ini

And then copy it to the BRANDMEISTER file-
cp /etc/MMDVM.ini /etc/BRANDMEISTER.ini

For Brandmiester it's necessary update the server address and port-
nano /etc/BRANDMEISTER.ini

Update them to the following-
Address=212.129.24.44
Port=62031

MMDVMHost-Dashboard

The next step is to install and configure the MMDVMHost-Dashboard. The dashboard allows you to check the current status of the DMR network, switch between networks, restart the MMDVMHost process, and reboot the Pi. It also lets you see whose talking-





Installing the Dashboard

For sometime I struggled with getting the running dashboard as it was throwing errors when php-cgi was called. This turned out to be a knock on effect of linking /var/spool to the /tmp directory, as a start up script was altering the permissions on /var/spool which was also affecting /tmp.

Edit the offending file-

nano /usr/lib/tmpfiles.d/var.conf

And comment out the line that references /var/spool so it looks like this-
#d /var/spool 0755 - - -

With that done, we can now continue with installing the dashboard.

Change to the /usr/src directory and clone MMDVMHost-Dashboard from github-
cd /usr/src
git clone https://github.com/dg9vh/MMDVMHost-Dashboard.git

Copy the files to the web root directory-
rsync -a /usr/src/MMDVMHost-Dashboard /var/www/html/

We then need to set the correct permissions-
sudo chown -R www-data:www-data /var/www/html
sudo chmod -R 775 /var/www/html

So the dashboard can restart the MMDVMHost service, reboot the Pi and switch between networks it's necessary to allow the www-data user to run limited commands as sudo without a password, so firstly we need to enter visudo-
visudo

And add the following line-

www-data ALL=(ALL) NOPASSWD: /bin/systemctl restart mmdvmhost.service,/bin/cp,/opt/MMDVMHost,/usr/bin/killall,/sbin/halt,/sbin/reboot

Now to configure the dashboard, access it in your browser-
http://[Raspberry Pi IP]/setup.php

And configure as per below (click on the images to expand them)-

















Press save once done.

Then copy the config.php file to a persistent folder, so changes can be made on the fly and saved to a temporary folder, saved to disk on shutdown, and then restored on boot-
mkdir /var/www/html/persistent
mkdir /tmp/MMDVMHostDashboard

cp /var/www/html/config/config.php /var/www/html/persistent
rm -rf /var/www/html/config/

ln -s /tmp/MMDVMHostDashboard /var/www/html/config/

cp /var/www/html/persistent/config.php /tmp/MMDVMHostDashboard/config.php 

MMDVMHost and MMDVMHost-Dashboard scripts

To get things playing nicely with the read only file system, its necessary to create some more scripts to move things in and out of persistent storage during boot and shut down.

Create the prepare-MMDVM script-
nano /etc/init.d/prepare-MMDVM

And add the following-
#!/bin/bash
#
### BEGIN INIT INFO
# Provides:          prepare-MMDVM
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Required-Start:
# Required-Stop:
# Short-Description: Copy MMDVM files to RAM storage
# Description:       Copy MMDVM files to RAM storage
### END INIT INFO
#
# main()
#
case "${1:-''}" in
  start)
    cp /etc/MMDVM.ini /tmp
    chmod 755 /tmp/MMDVM.ini
    cp /etc/DMRPLUS.ini /tmp
    chmod 755 /tmp/DMRPLUS.ini
    cp /etc/BRANDMEISTER.ini /tmp
    chmod 755 /tmp/BRANDMEISTER.ini
    cp /opt/MMDVMHost/DMRIds.dat /tmp
    chmod 755 /tmp/DMRIds.dat
    mkdir /tmp/MMDVMHostDashboard
    rsync -a /var/www/html/persistent/ /tmp/MMDVMHostDashboard
    chmod -R 755 /tmp/MMDVMHostDashboard
    ;;
  stop)
    ;;
  restart)
   ;;
  reload|force-reload)
   ;;
  status)
   ;;
  *)
   echo "Usage: $SELF start"
   exit 1
   ;;
esac

Then make the script executable, update the rc.d and daemon-
sudo chmod +x /etc/init.d/prepare-MMDVM
update-rc.d prepare-MMDVM defaults 01 99
systemctl daemon-reload

Next, create the shutdown script which will move the files from the temporary to persistent storage-
/usr/bin/MMDVM-shutdown

And add the following-
#!/bin/bash
mount -o remount,rw /
history -a
rsync -a /tmp/MMDVMHostDashboard/ /var/www/html/persistent
rsync -a /tmp/DMRIds.dat /opt/MMDVMHost/DMRIds.dat
mount -o remount,ro /

Make it executable-
chmod +x /usr/bin/MMDVM-shutdown

Now create the systemd script that will call the MMDVM-shutdown script-
nano /lib/systemd/system/MMDVM-shutdown.service 

Add the following-
[Unit]
Description=Copy MMDVM files to persistent storage

[Service]
Type=oneshot
ExecStart=/bin/true
ExecStop=/usr/bin/MMDVM-shutdown
RemainAfterExit=yes
Before=shutdown.target reboot.target halt.target

[Install]
WantedBy=shutdown.target

Now we need to set the correct permissions on the systemd script, add the symbolic link and enable the service-
chmod 755 /lib/systemd/system/MMDVM-shutdown.service

ln -s /lib/systemd/system/MMDVM-shutdown.service /etc/systemd/system/MMDVM-shutdown.service 

systemctl daemon-reload
systemctl enable MMDVM-shutdown.service


MMDVMHost start up script

The last step is to create the startup script for MMDVMHost. This consists of two scripts that ensure MMDVMHost starts 60 seconds after boot, once everything's settled down.

Create the mmdvmhost.service script-
nano /lib/systemd/system/mmdvmhost.service

Add the following-
[Unit]
Description=MMDVM Host Service
After=syslog.target network.target

[Service]
User=root
WorkingDirectory=/opt/MMDVMHost
ExecStart=/usr/bin/screen -S MMDVMHost -D -m /opt/MMDVMHost/MMDVMHost /tmp/MMDVM.ini
ExecStop=/usr/bin/screen -S MMDVMHost -X quit

[Install]
WantedBy=multi-user.target

Create the mmdvmhost.timer script-
nano /lib/systemd/system/mmdvmhost.timer

Add the following-
[Timer]
OnStartupSec=60

[Install]
WantedBy=multi-user.target

Adjust the permissions and add symlinks-
chmod 755 /lib/systemd/system/mmdvmhost.service
chmod 755 /lib/systemd/system/mmdvmhost.timer

sudo ln -s /lib/systemd/system/mmdvmhost.service /etc/systemd/system/mmdvmhost.service
sudo ln -s /lib/systemd/system/mmdvmhost.timer /etc/systemd/system/mmdvmhost.timer

Reload and enable the services-
systemctl daemon-reload
systemctl enable mmdvmhost.timer
systemctl enable mmdvmhost.service

You should now be able to reboot and get started with the hotspot!

reboot

Acknowledgments

A big thanks to everyone below that made the above tutorial possible!

G4KLX - MMDVMHost software
DG9VH - MMDVMHost-Dashboard software
G0WFV - Various posts on running MMDVMHost
petr.io - Information on making a Pi filesystem read only
hallard.me - Information on making a Pi filesystem read only
DVmega.co.uk - UK supplier of the DVMega
Rondie - Referenced the /tmp/ permissions issue and fix.
Marianne Spiller - Shows details on troubleshooting php-cgi issues with strace



2 comments:

  1. Hi, you did a really really really good work with this documentation. I would bookmark this page for further use on MMDVMHost and so on :-) Keep on going on this way!

    ReplyDelete
    Replies
    1. Thanks Kim, it was done a while ago now, hopefully it's still up to date!

      Delete